OdbDesignLib
OdbDesign ODB++ Parsing Library
 
Loading...
Searching...
No Matches
EdaDataFile.cpp
1#include "EdaDataFile.h"
2#include <fstream>
3#include <sstream>
4#include "str_utils.h"
5#include "../../enums.h"
6#include "edadatafile.pb.h"
7#include "ArchiveExtractor.h"
8#include "Logger.h"
9#include "../parse_info.h"
10#include "../parse_error.h"
11#include "../invalid_odb_error.h"
12
13using namespace std::filesystem;
14using namespace Utils;
15
16namespace Odb::Lib::FileModel::Design
17{
18 EdaDataFile::EdaDataFile(bool logAllLineParsing)
19 : m_logAllLineParsing(logAllLineParsing)
20 {
21 }
22
23 EdaDataFile::~EdaDataFile()
24 {
25 m_layerNames.clear();
26 m_attributeNames.clear();
27 m_attributeTextValues.clear();
28 m_netRecords.clear();
29 m_netRecordsByName.clear();
30 m_packageRecords.clear();
31 m_packageRecordsByName.clear();
32 m_featureGroupRecords.clear();
33 m_propertyRecords.clear();
34 }
35
36 const std::filesystem::path& EdaDataFile::GetPath() const
37 {
38 return m_path;
39 }
40
41 const std::filesystem::path& EdaDataFile::GetDirectory() const
42 {
43 return m_directory;
44 }
45
46 const std::string& EdaDataFile::GetUnits() const
47 {
48 return m_units;
49 }
50
51 const std::string& EdaDataFile::GetSource() const
52 {
53 return m_source;
54 }
55
56 EdaDataFile::NetRecord::SubnetRecord::~SubnetRecord()
57 {
58 m_featureIdRecords.clear();
59 }
60
61 std::unique_ptr<Odb::Lib::Protobuf::EdaDataFile::NetRecord::SubnetRecord> EdaDataFile::NetRecord::SubnetRecord::to_protobuf() const
62 {
63 std::unique_ptr<Odb::Lib::Protobuf::EdaDataFile::NetRecord::SubnetRecord> pSubnetRecordMessage(new Odb::Lib::Protobuf::EdaDataFile::NetRecord::SubnetRecord);
64 pSubnetRecordMessage->set_type((Odb::Lib::Protobuf::EdaDataFile::NetRecord::SubnetRecord::Type) type);
65 if (type == Type::Toeprint)
66 {
67 pSubnetRecordMessage->set_componentnumber(componentNumber);
68 pSubnetRecordMessage->set_toeprintnumber(toeprintNumber);
69 pSubnetRecordMessage->set_side((Odb::Lib::Protobuf::BoardSide)side);
70 }
71 else if (type == Type::Plane)
72 {
73 pSubnetRecordMessage->set_filltype((Odb::Lib::Protobuf::EdaDataFile::NetRecord::SubnetRecord::FillType)fillType);
74 pSubnetRecordMessage->set_cutouttype((Odb::Lib::Protobuf::EdaDataFile::NetRecord::SubnetRecord::CutoutType) cutoutType);
75 pSubnetRecordMessage->set_fillsize(fillSize);
76 }
77
78 for (const auto& featureIdRecord : m_featureIdRecords)
79 {
80 auto pFeatureIdRecordMessage = pSubnetRecordMessage->add_featureidrecords();
81 pFeatureIdRecordMessage->CopyFrom(*featureIdRecord->to_protobuf());
82 }
83 return pSubnetRecordMessage;
84 }
85
86 void EdaDataFile::NetRecord::SubnetRecord::from_protobuf(const Odb::Lib::Protobuf::EdaDataFile::NetRecord::SubnetRecord& message)
87 {
88 type = static_cast<Type>(message.type());
89
90 if (type == Type::Toeprint)
91 {
92 componentNumber = message.componentnumber();
93 toeprintNumber = message.toeprintnumber();
94 side = static_cast<BoardSide>(message.side());
95 }
96 else if (type == Type::Plane)
97 {
98 fillType = static_cast<FillType>(message.filltype());
99 cutoutType = static_cast<CutoutType>(message.cutouttype());
100 fillSize = message.fillsize();
101 index = message.index();
102 }
103
104 for (const auto& featureIdRecordMessage : message.featureidrecords())
105 {
106 auto pFeatureIdRecord = std::make_shared<FeatureIdRecord>();
107 pFeatureIdRecord->from_protobuf(featureIdRecordMessage);
108 m_featureIdRecords.push_back(pFeatureIdRecord);
109 }
110 }
111
112 EdaDataFile::NetRecord::~NetRecord()
113 {
114 m_subnetRecords.clear();
115 m_propertyRecords.clear();
116 }
117
118 std::unique_ptr<Odb::Lib::Protobuf::EdaDataFile::NetRecord> EdaDataFile::NetRecord::to_protobuf() const
119 {
120 std::unique_ptr<Odb::Lib::Protobuf::EdaDataFile::NetRecord> pNetRecordMessage(new Odb::Lib::Protobuf::EdaDataFile::NetRecord);
121 pNetRecordMessage->set_name(name);
122 //pNetRecordMessage->set_attributesidstring(attributesIdString);
123 pNetRecordMessage->set_index(index);
124
125 for (const auto& propertyRecord : m_propertyRecords)
126 {
127 auto pPropertyRecordMessage = pNetRecordMessage->add_propertyrecords();
128 pPropertyRecordMessage->CopyFrom(*propertyRecord->to_protobuf());
129 }
130
131 for (const auto& subnetRecord : m_subnetRecords)
132 {
133 auto pSubnetRecordMessage = pNetRecordMessage->add_subnetrecords();
134 pSubnetRecordMessage->CopyFrom(*subnetRecord->to_protobuf());
135 }
136 for (const auto& kvAttributeAssignment : m_attributeLookupTable)
137 {
138 (*pNetRecordMessage->mutable_attributelookuptable())[kvAttributeAssignment.first] = kvAttributeAssignment.second;
139 }
140 return pNetRecordMessage;
141 }
142
143 void EdaDataFile::NetRecord::from_protobuf(const Odb::Lib::Protobuf::EdaDataFile::NetRecord& message)
144 {
145 name = message.name();
146 //attributesIdString = message.attributesidstring();
147 index = message.index();
148
149 for (const auto& propertyRecordMessage : message.propertyrecords())
150 {
151 auto pPropertyRecord = std::make_shared<PropertyRecord>();
152 pPropertyRecord->from_protobuf(propertyRecordMessage);
153 m_propertyRecords.push_back(pPropertyRecord);
154 }
155
156 for (const auto& subnetRecordMessage : message.subnetrecords())
157 {
158 auto pSubnetRecord = std::make_shared<SubnetRecord>();
159 pSubnetRecord->from_protobuf(subnetRecordMessage);
160 m_subnetRecords.push_back(pSubnetRecord);
161 }
162
163 for (const auto& kvAttributeAssignment : message.attributelookuptable())
164 {
165 m_attributeLookupTable[kvAttributeAssignment.first] = kvAttributeAssignment.second;
166 }
167 }
168
169 std::unique_ptr<Odb::Lib::Protobuf::EdaDataFile::FeatureIdRecord>
170 EdaDataFile::FeatureIdRecord::to_protobuf() const
171 {
172 std::unique_ptr<Odb::Lib::Protobuf::EdaDataFile::FeatureIdRecord> pFeatureIdRecordMessage(new Odb::Lib::Protobuf::EdaDataFile::FeatureIdRecord);
173 pFeatureIdRecordMessage->set_type((Odb::Lib::Protobuf::EdaDataFile::FeatureIdRecord::Type) type);
174 pFeatureIdRecordMessage->set_layernumber(layerNumber);
175 pFeatureIdRecordMessage->set_featurenumber(featureNumber);
176 return pFeatureIdRecordMessage;
177 }
178
179 void EdaDataFile::FeatureIdRecord::from_protobuf(const Odb::Lib::Protobuf::EdaDataFile::FeatureIdRecord& message)
180 {
181 type = static_cast<Type>(message.type());
182 layerNumber = message.layernumber();
183 featureNumber = message.featurenumber();
184 }
185
186 std::unique_ptr<Odb::Lib::Protobuf::EdaDataFile::FeatureGroupRecord>
187 EdaDataFile::FeatureGroupRecord::to_protobuf() const
188 {
189 std::unique_ptr<Odb::Lib::Protobuf::EdaDataFile::FeatureGroupRecord> pFeatureGroupRecordMessage(new Odb::Lib::Protobuf::EdaDataFile::FeatureGroupRecord);
190 pFeatureGroupRecordMessage->set_type(type);
191 for (const auto& featureIdRecord : m_featureIdRecords)
192 {
193 auto pFeatureIdRecordMessage = pFeatureGroupRecordMessage->add_featureidrecords();
194 pFeatureIdRecordMessage->CopyFrom(*featureIdRecord->to_protobuf());
195 }
196 for (const auto& propertyRecord : m_propertyRecords)
197 {
198 auto pPropertyRecordMessage = pFeatureGroupRecordMessage->add_featureidrecords();
199 pPropertyRecordMessage->CopyFrom(*propertyRecord->to_protobuf());
200 }
201 return pFeatureGroupRecordMessage;
202 }
203
204 void EdaDataFile::FeatureGroupRecord::from_protobuf(const Odb::Lib::Protobuf::EdaDataFile::FeatureGroupRecord& message)
205 {
206 type = message.type();
207 for (const auto& featureIdRecordMessage : message.featureidrecords())
208 {
209 auto pFeatureIdRecord = std::make_shared<FeatureIdRecord>();
210 pFeatureIdRecord->from_protobuf(featureIdRecordMessage);
211 m_featureIdRecords.push_back(pFeatureIdRecord);
212 }
213 for (const auto& propertyRecordMessage : message.propertyrecords())
214 {
215 auto pPropertyRecord = std::make_shared<PropertyRecord>();
216 pPropertyRecord->from_protobuf(propertyRecordMessage);
217 m_propertyRecords.push_back(pPropertyRecord);
218 }
219 }
220
221 const std::vector<std::string>& EdaDataFile::GetLayerNames() const
222 {
223 return m_layerNames;
224 }
225
226 const std::vector<std::string>& EdaDataFile::GetAttributeNames() const
227 {
228 return m_attributeNames;
229 }
230
231 const std::vector<std::string>& EdaDataFile::GetAttributeTextValues() const
232 {
233 return m_attributeTextValues;
234 }
235
236 const EdaDataFile::NetRecord::Vector& EdaDataFile::GetNetRecords() const
237 {
238 return m_netRecords;
239 }
240
241 const EdaDataFile::NetRecord::StringMap& EdaDataFile::GetNetRecordsByName() const
242 {
243 return m_netRecordsByName;
244 }
245
246 const EdaDataFile::PackageRecord::Vector& EdaDataFile::GetPackageRecords() const
247 {
248 return m_packageRecords;
249 }
250
251 const EdaDataFile::PackageRecord::StringMap& EdaDataFile::GetPackageRecordsByName() const
252 {
253 return m_packageRecordsByName;
254 }
255
256 const EdaDataFile::FeatureGroupRecord::Vector& EdaDataFile::GetFeatureGroupRecords() const
257 {
258 return m_featureGroupRecords;
259 }
260
261 const PropertyRecord::Vector& EdaDataFile::GetPropertyRecords() const
262 {
263 return m_propertyRecords;
264 }
265
266 std::unique_ptr<Odb::Lib::Protobuf::EdaDataFile> EdaDataFile::to_protobuf() const
267 {
268 std::unique_ptr<Odb::Lib::Protobuf::EdaDataFile> pEdaDataFileMessage(new Odb::Lib::Protobuf::EdaDataFile);
269 pEdaDataFileMessage->set_path(m_path.string());
270 pEdaDataFileMessage->set_units(m_units);
271 pEdaDataFileMessage->set_source(m_source);
272 for (const auto& layerName : m_layerNames)
273 {
274 pEdaDataFileMessage->add_layernames(layerName);
275 }
276 for (const auto& attributeName : m_attributeNames)
277 {
278 pEdaDataFileMessage->add_attributenames(attributeName);
279 }
280 for (const auto& attrTextValue : m_attributeTextValues)
281 {
282 pEdaDataFileMessage->add_attributetextvalues(attrTextValue);
283 }
284 for (const auto& pNetRecord : m_netRecords)
285 {
286 auto pNetRecordMessage = pEdaDataFileMessage->add_netrecords();
287 pNetRecordMessage->CopyFrom(*pNetRecord->to_protobuf());
288 }
289 for (const auto& kvNetRecord : m_netRecordsByName)
290 {
291 (*pEdaDataFileMessage->mutable_netrecordsbyname())[kvNetRecord.first] = *kvNetRecord.second->to_protobuf();
292 }
293 for (const auto& pPackageRecord : m_packageRecords)
294 {
295 auto pPackageRecordMessage = pEdaDataFileMessage->add_packagerecords();
296 pPackageRecordMessage->CopyFrom(*pPackageRecord->to_protobuf());
297 }
298 for (const auto& kvPackageRecord : m_packageRecordsByName)
299 {
300 (*pEdaDataFileMessage->mutable_packagerecordsbyname())[kvPackageRecord.first] = *kvPackageRecord.second->to_protobuf();
301 }
302 for (const auto& pPropertyRecord : m_propertyRecords)
303 {
304 auto pPropertyRecordMessage = pEdaDataFileMessage->add_propertyrecords();
305 pPropertyRecordMessage->CopyFrom(*pPropertyRecord->to_protobuf());
306 }
307 for (const auto& pFeatureGroupRecord : m_featureGroupRecords)
308 {
309 auto pFeatureGroupRecordMessage = pEdaDataFileMessage->add_featuregrouprecords();
310 pFeatureGroupRecordMessage->CopyFrom(*pFeatureGroupRecord->to_protobuf());
311 }
312
313 return pEdaDataFileMessage;
314 }
315
316 void EdaDataFile::from_protobuf(const Odb::Lib::Protobuf::EdaDataFile& message)
317 {
318 m_path = message.path();
319 m_units = message.units();
320 m_source = message.source();
321 for (const auto& layerName : message.layernames())
322 {
323 m_layerNames.push_back(layerName);
324 }
325 for (const auto& attributeName : message.attributenames())
326 {
327 m_attributeNames.push_back(attributeName);
328 }
329 for (const auto& attrTextValue : message.attributetextvalues())
330 {
331 m_attributeTextValues.push_back(attrTextValue);
332 }
333 for (const auto& netRecordMessage : message.netrecords())
334 {
335 auto pNetRecord = std::make_shared<NetRecord>();
336 pNetRecord->from_protobuf(netRecordMessage);
337 m_netRecords.push_back(pNetRecord);
338 }
339 for (const auto& kvNetRecordMessage : message.netrecordsbyname())
340 {
341 auto pNetRecord = std::make_shared<NetRecord>();
342 pNetRecord->from_protobuf(kvNetRecordMessage.second);
343 m_netRecordsByName[kvNetRecordMessage.first] = pNetRecord;
344 }
345 for (const auto& packageRecordMessage : message.packagerecords())
346 {
347 auto pPackageRecord = std::make_shared<PackageRecord>();
348 pPackageRecord->from_protobuf(packageRecordMessage);
349 m_packageRecords.push_back(pPackageRecord);
350 }
351 for (const auto& kvPackageRecordMessage : message.packagerecordsbyname())
352 {
353 auto pPackageRecord = std::make_shared<PackageRecord>();
354 pPackageRecord->from_protobuf(kvPackageRecordMessage.second);
355 m_packageRecordsByName[kvPackageRecordMessage.first] = pPackageRecord;
356 }
357 for (const auto& propertyRecordMessage : message.propertyrecords())
358 {
359 auto pPropertyRecord = std::make_shared<PropertyRecord>();
360 pPropertyRecord->from_protobuf(propertyRecordMessage);
361 m_propertyRecords.push_back(pPropertyRecord);
362 }
363 for (const auto& featureGroupRecordMessage : message.featuregrouprecords())
364 {
365 auto pFeatureGroupRecord = std::make_shared<FeatureGroupRecord>();
366 pFeatureGroupRecord->from_protobuf(featureGroupRecordMessage);
367 m_featureGroupRecords.push_back(pFeatureGroupRecord);
368 }
369 }
370
371 bool EdaDataFile::Save(std::ostream& os)
372 {
373 return true;
374 }
375
376 bool EdaDataFile::Parse(std::filesystem::path path)
377 {
378 std::ifstream edaDataFile;
379 int lineNumber = 0;
380 std::string line;
381
382 try
383 {
384 loginfo("checking for extraction...");
385
386 m_directory = path;
387 m_path = ArchiveExtractor::getUncompressedFilePath(m_directory.string(), EDADATA_FILENAME);
388
389 if (!std::filesystem::exists(m_path))
390 {
391 auto message = "eda/data file does not exist: [" + m_path.string() + "]";
392 throw invalid_odb_error(message.c_str());
393 }
394 else if (!std::filesystem::is_regular_file(m_path))
395 {
396 auto message = "eda/data is not a file: [" + m_path.string() + "]";
397 throw invalid_odb_error(message.c_str());
398 }
399
400 loginfo("any extraction complete, parsing data...");
401
402 edaDataFile.open(m_path.string(), std::ios::in);
403 if (!edaDataFile.is_open())
404 {
405 auto message = "unable to open eda/data file: [" + m_path.string() + "]";
406 throw invalid_odb_error(message.c_str());
407 }
408
409 std::shared_ptr<NetRecord> pCurrentNetRecord;
410 std::shared_ptr<NetRecord::SubnetRecord> pCurrentSubnetRecord;
411
412 std::shared_ptr<PackageRecord> pCurrentPackageRecord;
413 std::shared_ptr<PackageRecord::PinRecord> pCurrentPinRecord;
414
415 std::shared_ptr<PackageRecord::OutlineRecord> pCurrentContourOutlineRecord;
416 std::shared_ptr<ContourPolygon> pCurrentContourPolygon;
417
418 FeatureGroupRecord::shared_ptr pCurrentFeatureGroupRecord;
419
420 while (std::getline(edaDataFile, line))
421 {
422 // keep track of line number
423 lineNumber++;
424
425 // trim whitespace from beginning and end of line
426 Utils::str_trim(line);
427 if (!line.empty())
428 {
429 if (m_logAllLineParsing)
430 {
431 parse_info pi(m_path, line, lineNumber);
432 logdebug(pi.toString("Parsing line..."));
433 }
434
435 std::stringstream lineStream(line);
436
437 if (line.find(ATTRIBUTE_NAME_TOKEN) == 0 ||
438 line.find(std::string(COMMENT_TOKEN) + ATTRIBUTE_NAME_TOKEN) == 0) // backward compatibility dictates allowing comment character in front of attribute value token
439 {
440 // component attribute name line
441 std::string token;
442 // TODO: continue on failing line parse, to make a less strict/more robust parser (make a flag: enum ParseStrictness { strict, lax })
443 if (!std::getline(lineStream, token, ' '))
444 {
445 throw_parse_error(m_path, line, token, lineNumber);
446 }
447 else if (!std::getline(lineStream, token, ' '))
448 {
449 throw_parse_error(m_path, line, token, lineNumber);
450 }
451 m_attributeNames.push_back(token);
452 }
453 else if (line.find(ATTRIBUTE_VALUE_TOKEN) == 0 ||
454 line.find(std::string(COMMENT_TOKEN) + ATTRIBUTE_VALUE_TOKEN) == 0) // backward compatibility dictates allowing comment character in front of attribute value token
455 {
456 // component attribute text string values
457 std::string token;
458 if (!std::getline(lineStream, token, ' '))
459 {
460 throw_parse_error(m_path, line, token, lineNumber);
461 }
462 else if (!std::getline(lineStream, token, ' '))
463 {
464 throw_parse_error(m_path, line, token, lineNumber);
465 }
466 m_attributeTextValues.push_back(token);
467 }
468 else if (line.find(COMMENT_TOKEN) == 0)
469 {
470 // comment line
471 // TODO: attribute lines can begin with a comment for backward compatbility
472 }
473 else if (line.find(UNITS_TOKEN) == 0)
474 {
475 // units line
476 std::string token;
477 if (!std::getline(lineStream, token, '='))
478 {
479 throw_parse_error(m_path, line, token, lineNumber);
480 }
481 else if (!std::getline(lineStream, token, '='))
482 {
483 throw_parse_error(m_path, line, token, lineNumber);
484 }
485 m_units = token;
486 }
487 else if (line.find(HEADER_RECORD_TOKEN) == 0)
488 {
489 // component record line
490 std::string token;
491
492 lineStream >> token;
493 if (token != HEADER_RECORD_TOKEN)
494 {
495 throw_parse_error(m_path, line, token, lineNumber);
496 }
497
498 // read the rest of the line as the source
499 if (!std::getline(lineStream, m_source))
500 {
501 throw_parse_error(m_path, line, token, lineNumber);
502 }
503
504 Utils::str_trim(m_source);
505 }
506 else if (line.find(LAYER_NAMES_RECORD_TOKEN) == 0)
507 {
508 // component record line
509 std::string token;
510
511 lineStream >> token;
512 if (token != LAYER_NAMES_RECORD_TOKEN)
513 {
514 throw_parse_error(m_path, line, token, lineNumber);
515 }
516
517 while (lineStream >> token)
518 {
519 m_layerNames.push_back(token);
520 }
521 }
522 else if (line.find(PropertyRecord::RECORD_TOKEN) == 0)
523 {
524 // component property record line
525 std::string token;
526 if (!(lineStream >> token))
527 {
528 throw_parse_error(m_path, line, token, lineNumber);
529 }
530
531 if (token != PropertyRecord::RECORD_TOKEN)
532 {
533 throw_parse_error(m_path, line, token, lineNumber);
534 }
535
536 auto pPropertyRecord = std::make_shared<PropertyRecord>();
537
538 if (!(lineStream >> pPropertyRecord->name))
539 {
540 throw_parse_error(m_path, line, token, lineNumber);
541 }
542
543 if (!(lineStream >> token))
544 {
545 throw_parse_error(m_path, line, token, lineNumber);
546 }
547
548 if (!token.empty())
549 {
550 // handle case where the beginning of the value, after the opening single-quote, is whitespace...
551 if (token == "'")
552 {
553 // eat the single-quote and get the next token, i.e. the actual value (w/ space in front)
554 if (!(lineStream >> token))
555 {
556 throw_parse_error(m_path, line, token, lineNumber);
557 }
558 }
559
560 if (token.size() > 0 && token[0] == '\'')
561 {
562 // remove leading quote
563 token.erase(0, 1);
564 }
565
566 if (token.size() > 0 && token[token.size() - 1] == '\'')
567 {
568 // remove trailing quote
569 token.erase(token.size() - 1);
570 }
571
572 Utils::str_trim(token);
573 }
574
575 pPropertyRecord->value = token;
576
577 double f;
578 while (lineStream >> f)
579 {
580 pPropertyRecord->floatValues.push_back(f);
581 }
582
583 if (pCurrentNetRecord != nullptr)
584 {
585 pCurrentNetRecord->m_propertyRecords.push_back(pPropertyRecord);
586 }
587 else if (pCurrentPackageRecord != nullptr)
588 {
589 pCurrentPackageRecord->m_propertyRecords.push_back(pPropertyRecord);
590 }
591 else if (pCurrentFeatureGroupRecord != nullptr)
592 {
593 pCurrentFeatureGroupRecord->m_propertyRecords.push_back(pPropertyRecord);
594 }
595 else
596 {
597 // top-level PRP record
598 m_propertyRecords.push_back(pPropertyRecord);
599 }
600 }
601 else if (line.find(NET_RECORD_TOKEN) == 0)
602 {
603 // net record line
604 std::string token;
605
606 if (!(lineStream >> token))
607 {
608 throw_parse_error(m_path, line, token, lineNumber);
609 }
610
611 if (token != NET_RECORD_TOKEN)
612 {
613 throw_parse_error(m_path, line, token, lineNumber);
614 }
615
616 // finish current (previous) net record
617 if (pCurrentNetRecord != nullptr)
618 {
619 // finish up (any) current subnet record
620 if (pCurrentSubnetRecord != nullptr)
621 {
622 pCurrentNetRecord->m_subnetRecords.push_back(pCurrentSubnetRecord);
623 pCurrentSubnetRecord.reset();
624 }
625
626 m_netRecords.push_back(pCurrentNetRecord);
627 //m_netRecordsByName[pCurrentNetRecord->name] = pCurrentNetRecord;
628 pCurrentNetRecord.reset();
629 }
630
631 // net name
632 if (!std::getline(lineStream, token, ';'))
633 {
634 throw_parse_error(m_path, line, token, lineNumber);
635 }
636
637 // trim whitespace from beginning
638 str_trim(token);
639
640 // create new net record
641 pCurrentNetRecord = std::make_shared<NetRecord>();
642 pCurrentNetRecord->name = token;
643 pCurrentNetRecord->index = static_cast<unsigned>(m_netRecords.size());
644
645 std::string attrIdString;
646 lineStream >> attrIdString;
647 if (!pCurrentNetRecord->ParseAttributeLookupTable(attrIdString))
648 {
649 throw_parse_error(m_path, line, token, lineNumber);
650 }
651 }
652 else if (line.find(NetRecord::SubnetRecord::RECORD_TOKEN) == 0)
653 {
654 // component record line
655 std::string token;
656
657 lineStream >> token;
658 if (token != NetRecord::SubnetRecord::RECORD_TOKEN)
659 {
660 throw_parse_error(m_path, line, token, lineNumber);
661 }
662
663 if (pCurrentNetRecord != nullptr)
664 {
665 // finish current (previous) subnet record
666 if (pCurrentSubnetRecord != nullptr)
667 {
668 pCurrentNetRecord->m_subnetRecords.push_back(pCurrentSubnetRecord);
669 pCurrentSubnetRecord.reset();
670 }
671 }
672
673 pCurrentSubnetRecord = std::make_shared<NetRecord::SubnetRecord>();
674 pCurrentSubnetRecord->index = static_cast<unsigned>(pCurrentNetRecord->m_subnetRecords.size());
675
676 // subnet type
677 lineStream >> token;
678 if (token == NetRecord::SubnetRecord::RECORD_TYPE_VIA_TOKEN)
679 {
680 pCurrentSubnetRecord->type = NetRecord::SubnetRecord::Type::Via;
681 }
682 else if (token == NetRecord::SubnetRecord::RECORD_TYPE_TRACE_TOKEN)
683 {
684 pCurrentSubnetRecord->type = NetRecord::SubnetRecord::Type::Trace;
685 }
686 else if (token == NetRecord::SubnetRecord::RECORD_TYPE_PLANE_TOKEN)
687 {
688 pCurrentSubnetRecord->type = NetRecord::SubnetRecord::Type::Plane;
689
690 // fill type
691 lineStream >> token;
692 if (token == "S")
693 {
694 pCurrentSubnetRecord->fillType = NetRecord::SubnetRecord::FillType::Solid;
695 }
696 else if (token == "O")
697 {
698 pCurrentSubnetRecord->fillType = NetRecord::SubnetRecord::FillType::Outline;
699 }
700 else
701 {
702 throw_parse_error(m_path, line, token, lineNumber);
703 }
704
705 // cutout type
706 lineStream >> token;
707 if (token == "C")
708 {
709 pCurrentSubnetRecord->cutoutType = NetRecord::SubnetRecord::CutoutType::Circle;
710 }
711 else if (token == "R")
712 {
713 pCurrentSubnetRecord->cutoutType = NetRecord::SubnetRecord::CutoutType::Rectangle;
714 }
715 else if (token == "O")
716 {
717 pCurrentSubnetRecord->cutoutType = NetRecord::SubnetRecord::CutoutType::Octagon;
718 }
719 else if (token == "E")
720 {
721 pCurrentSubnetRecord->cutoutType = NetRecord::SubnetRecord::CutoutType::Exact;
722 }
723 else
724 {
725 throw_parse_error(m_path, line, token, lineNumber);
726 }
727
728 // fill size
729 lineStream >> pCurrentSubnetRecord->fillSize;
730 }
731 else if (token == NetRecord::SubnetRecord::RECORD_TYPE_TOEPRINT_TOKEN)
732 {
733 pCurrentSubnetRecord->type = NetRecord::SubnetRecord::Type::Toeprint;
734
735 // side
736 lineStream >> token;
737 if (token == "T")
738 {
739 pCurrentSubnetRecord->side = BoardSide::Top;
740 }
741 else if (token == "B")
742 {
743 pCurrentSubnetRecord->side = BoardSide::Bottom;
744 }
745 else
746 {
747 throw_parse_error(m_path, line, token, lineNumber);
748 }
749
750 // componentNumber
751 lineStream >> pCurrentSubnetRecord->componentNumber;
752
753 // toeprintNumber
754 lineStream >> pCurrentSubnetRecord->toeprintNumber;
755 }
756 else
757 {
758 throw_parse_error(m_path, line, token, lineNumber);
759 }
760 }
761 else if (line.find(FEATURE_ID_RECORD_TOKEN) == 0)
762 {
763 // component record line
764 std::string token;
765
766 if (!(lineStream >> token) || token != FEATURE_ID_RECORD_TOKEN)
767 {
768 throw_parse_error(m_path, line, token, lineNumber);
769 }
770
771 auto pFeatureIdRecord = std::make_shared<FeatureIdRecord>();
772
773 // type
774 if (!(lineStream >> token))
775 {
776 throw_parse_error(m_path, line, token, lineNumber);
777 }
778
779 if (token == "C")
780 {
781 pFeatureIdRecord->type = FeatureIdRecord::Type::Copper;
782 }
783 else if (token == "L")
784 {
785 pFeatureIdRecord->type = FeatureIdRecord::Type::Laminate;
786 }
787 else if (token == "H")
788 {
789 pFeatureIdRecord->type = FeatureIdRecord::Type::Hole;
790 }
791 else
792 {
793 throw_parse_error(m_path, line, token, lineNumber);
794 }
795
796 // layer number
797 if (!(lineStream >> pFeatureIdRecord->layerNumber))
798 {
799 throw_parse_error(m_path, line, token, lineNumber);
800 }
801
802 // feature number
803 if (!(lineStream >> pFeatureIdRecord->featureNumber))
804 {
805 throw_parse_error(m_path, line, token, lineNumber);
806 }
807
808 if (pCurrentNetRecord != nullptr &&
809 pCurrentSubnetRecord != nullptr)
810 {
811 pCurrentSubnetRecord->m_featureIdRecords.push_back(pFeatureIdRecord);
812 }
813 else if (pCurrentFeatureGroupRecord != nullptr)
814 {
815 pCurrentFeatureGroupRecord->m_featureIdRecords.push_back(pFeatureIdRecord);
816 }
817 else
818 {
819 throw_parse_error(m_path, line, token, lineNumber);
820 }
821 }
822 else if (line.find(PACKAGE_RECORD_TOKEN) == 0)
823 {
824 // package record line
825 std::string token;
826
827 if (!(lineStream >> token) || token != PACKAGE_RECORD_TOKEN)
828 {
829 throw_parse_error(m_path, line, token, lineNumber);
830 }
831
832 // finish current (previous) net record
833 if (pCurrentNetRecord != nullptr)
834 {
835 // finish up (any) current subnet record
836 if (pCurrentSubnetRecord != nullptr)
837 {
838 pCurrentNetRecord->m_subnetRecords.push_back(pCurrentSubnetRecord);
839 pCurrentSubnetRecord.reset();
840 }
841
842 m_netRecords.push_back(pCurrentNetRecord);
843 //m_netRecordsByName[pCurrentNetRecord->name] = pCurrentNetRecord;
844 pCurrentNetRecord.reset();
845 }
846 else if (pCurrentPackageRecord != nullptr)
847 {
848 // finish up any current (previous) pin records
849 if (pCurrentPinRecord != nullptr)
850 {
851 // check for overflow
852 if (pCurrentPackageRecord->m_pinRecords.size() > UINT_MAX)
853 {
854 throw_parse_error(m_path, line, token, lineNumber);
855 }
856 pCurrentPinRecord->index = static_cast<unsigned>(pCurrentPackageRecord->m_pinRecords.size());
857 pCurrentPackageRecord->m_pinRecords.push_back(pCurrentPinRecord);
858 pCurrentPinRecord.reset();
859 }
860
861 // finish up any current (previous) package records
862 m_packageRecords.push_back(pCurrentPackageRecord);
863 //m_packageRecordsByName[pCurrentPackageRecord->name] = pCurrentPackageRecord;
864 pCurrentPackageRecord.reset();
865 }
866
867 pCurrentPackageRecord = std::make_shared<PackageRecord>();
868 pCurrentPackageRecord->index = static_cast<unsigned int>(m_packageRecords.size());
869
870 // name
871 if (!(lineStream >> pCurrentPackageRecord->name))
872 {
873 throw_parse_error(m_path, line, token, lineNumber);
874 }
875
876 // pitch
877 if (!(lineStream >> pCurrentPackageRecord->pitch))
878 {
879 throw_parse_error(m_path, line, token, lineNumber);
880 }
881
882 // xmin, ymin
883 if (!(lineStream >> pCurrentPackageRecord->xMin >> pCurrentPackageRecord->yMin))
884 {
885 throw_parse_error(m_path, line, token, lineNumber);
886 }
887
888 // xmax
889 if (!(lineStream >> pCurrentPackageRecord->xMax))
890 {
891 throw_parse_error(m_path, line, token, lineNumber);
892 }
893
894 // ymax and attributes/ID string
895 if (!std::getline(lineStream, token, ';'))
896 {
897 throw_parse_error(m_path, line, token, lineNumber);
898 }
899
900 // ymax
901 pCurrentPackageRecord->yMax = std::stof(token);
902
903 std::string attrIdString;
904 lineStream >> attrIdString;
905 if (!pCurrentPackageRecord->ParseAttributeLookupTable(attrIdString))
906 {
907 throw_parse_error(m_path, line, token, lineNumber);
908 }
909 }
910 else if (line.find(PIN_RECORD_TOKEN) == 0)
911 {
912 // package pin record line
913 std::string token;
914
915 if (!(lineStream >> token) || token != PIN_RECORD_TOKEN)
916 {
917 throw_parse_error(m_path, line, token, lineNumber);
918 }
919
920 if (pCurrentPackageRecord != nullptr)
921 {
922 // finish up any current (previous) pin records
923 if (pCurrentPinRecord != nullptr)
924 {
925 // check for overflow
926 if (pCurrentPackageRecord->m_pinRecords.size() > UINT_MAX)
927 {
928 throw_parse_error(m_path, line, token, lineNumber);
929 }
930 pCurrentPinRecord->index = static_cast<unsigned>(pCurrentPackageRecord->m_pinRecords.size());
931 pCurrentPackageRecord->m_pinRecords.push_back(pCurrentPinRecord);
932 pCurrentPinRecord.reset();
933 }
934 }
935
936 pCurrentPinRecord = std::make_shared<PackageRecord::PinRecord>();
937 //pCurrentPinRecord->index = static_cast<unsigned>(pCurrentPackageRecord->m_pinRecords.size());
938
939 // name
940 lineStream >> pCurrentPinRecord->name;
941
942 // type
943 if (!(lineStream >> token))
944 {
945 throw_parse_error(m_path, line, token, lineNumber);
946 }
947
948 if (token == "T")
949 {
950 pCurrentPinRecord->type = PackageRecord::PinRecord::Type::ThroughHole;
951 }
952 else if (token == "B")
953 {
954 pCurrentPinRecord->type = PackageRecord::PinRecord::Type::Blind;
955 }
956 else if (token == "S")
957 {
958 pCurrentPinRecord->type = PackageRecord::PinRecord::Type::Surface;
959 }
960 else
961 {
962 logerror("unknown pin type: [" + token + "]");
963 throw_parse_error(m_path, line, token, lineNumber);
964 }
965
966 // xc, xy
967 if (!(lineStream >> pCurrentPinRecord->xCenter >> pCurrentPinRecord->yCenter))
968 {
969 throw_parse_error(m_path, line, token, lineNumber);
970 }
971
972 // finished hole size (fhs)
973 if (!(lineStream >> pCurrentPinRecord->finishedHoleSize))
974 {
975 throw_parse_error(m_path, line, token, lineNumber);
976 }
977
978 // electrical type
979 if (!(lineStream >> token))
980 {
981 throw_parse_error(m_path, line, token, lineNumber);
982 }
983
984 if (token == "E")
985 {
986 pCurrentPinRecord->electricalType = PackageRecord::PinRecord::ElectricalType::Electrical;
987 }
988 else if (token == "M")
989 {
990 pCurrentPinRecord->electricalType = PackageRecord::PinRecord::ElectricalType::NonElectrical;
991 }
992 else if (token == "U")
993 {
994 pCurrentPinRecord->electricalType = PackageRecord::PinRecord::ElectricalType::Undefined;
995 }
996 else
997 {
998 logerror("unknown pin electrical type: [" + token + "]");
999 throw_parse_error(m_path, line, token, lineNumber);
1000 }
1001
1002 // mount type
1003 if (!(lineStream >> token))
1004 {
1005 throw_parse_error(m_path, line, token, lineNumber);
1006 }
1007
1008 if (token == "S")
1009 {
1010 pCurrentPinRecord->mountType = PackageRecord::PinRecord::MountType::Smt;
1011 }
1012 else if (token == "D")
1013 {
1014 pCurrentPinRecord->mountType = PackageRecord::PinRecord::MountType::RecommendedSmtPad;
1015 }
1016 else if (token == "T")
1017 {
1018 pCurrentPinRecord->mountType = PackageRecord::PinRecord::MountType::MT_ThroughHole;
1019 }
1020 else if (token == "R")
1021 {
1022 pCurrentPinRecord->mountType = PackageRecord::PinRecord::MountType::RecommendedThroughHole;
1023 }
1024 else if (token == "P")
1025 {
1026 pCurrentPinRecord->mountType = PackageRecord::PinRecord::MountType::Pressfit;
1027 }
1028 else if (token == "N")
1029 {
1030 pCurrentPinRecord->mountType = PackageRecord::PinRecord::MountType::NonBoard;
1031 }
1032 else if (token == "H")
1033 {
1034 pCurrentPinRecord->mountType = PackageRecord::PinRecord::MountType::Hole;
1035 }
1036 else if (token == "U")
1037 {
1038 pCurrentPinRecord->mountType = PackageRecord::PinRecord::MountType::MT_Undefined;
1039 }
1040 else
1041 {
1042 logerror("unknown pin mount type: [" + token + "]");
1043 throw_parse_error(m_path, line, token, lineNumber);
1044 }
1045
1046 // ID=<id>
1047 // PIN record, ID field is optional: spec pg.31
1048 if (lineStream >> token)
1049 {
1050 std::stringstream idStream(token);
1051 if (!std::getline(idStream, token, '=') || token != "ID")
1052 {
1053 throw_parse_error(m_path, line, token, lineNumber);
1054 }
1055
1056 idStream >> pCurrentPinRecord->id;
1057 }
1058 else
1059 {
1060
1061#define SIMULATE_PARSE_ERROR 0
1062#if SIMULATE_PARSE_ERROR
1063 throw_parse_error(m_path, line, token, lineNumber);
1064#endif
1065
1066 pCurrentPinRecord->id = UINT_MAX;
1067 }
1068 }
1069 else if (line.find(FEATURE_GROUP_RECORD_TOKEN) == 0)
1070 {
1071 // feature group record line
1072 std::string token;
1073
1074 if (!(lineStream >> token))
1075 {
1076 throw_parse_error(m_path, line, token, lineNumber);
1077 }
1078
1079 if (token != FEATURE_GROUP_RECORD_TOKEN)
1080 {
1081 throw_parse_error(m_path, line, token, lineNumber);
1082 }
1083
1084 // finish current (previous) net record
1085 if (pCurrentNetRecord != nullptr)
1086 {
1087 // finish up (any) current subnet record
1088 if (pCurrentSubnetRecord != nullptr)
1089 {
1090 pCurrentNetRecord->m_subnetRecords.push_back(pCurrentSubnetRecord);
1091 pCurrentSubnetRecord.reset();
1092 }
1093
1094 m_netRecords.push_back(pCurrentNetRecord);
1095 //m_netRecordsByName[pCurrentNetRecord->name] = pCurrentNetRecord;
1096 pCurrentNetRecord.reset();
1097 }
1098 else if (pCurrentPackageRecord != nullptr)
1099 {
1100 // finish up any current (previous) pin records
1101 if (pCurrentPinRecord != nullptr)
1102 {
1103 // check for overflow
1104 if (pCurrentPackageRecord->m_pinRecords.size() > UINT_MAX)
1105 {
1106 throw_parse_error(m_path, line, token, lineNumber);
1107 }
1108 pCurrentPinRecord->index = static_cast<unsigned>(pCurrentPackageRecord->m_pinRecords.size());
1109 pCurrentPackageRecord->m_pinRecords.push_back(pCurrentPinRecord);
1110 pCurrentPinRecord.reset();
1111 }
1112
1113 // finish up any current (previous) package records
1114 m_packageRecords.push_back(pCurrentPackageRecord);
1115 //m_packageRecordsByName[pCurrentPackageRecord->name] = pCurrentPackageRecord;
1116 pCurrentPackageRecord.reset();
1117 }
1118 else if (pCurrentFeatureGroupRecord != nullptr)
1119 {
1120 m_featureGroupRecords.push_back(pCurrentFeatureGroupRecord);
1121 pCurrentFeatureGroupRecord.reset();
1122 }
1123
1124 pCurrentFeatureGroupRecord = std::make_shared<FeatureGroupRecord>();
1125
1126 if (!(lineStream >> pCurrentFeatureGroupRecord->type))
1127 {
1128 throw_parse_error(m_path, line, token, lineNumber);
1129 }
1130 }
1131 else if (line.find(PackageRecord::OutlineRecord::RECTANGLE_RECORD_TOKEN) == 0)
1132 {
1133 std::string token;
1134 if (!(lineStream >> token))
1135 {
1136 throw_parse_error(m_path, line, token, lineNumber);
1137 }
1138
1139 if (token != PackageRecord::OutlineRecord::RECTANGLE_RECORD_TOKEN)
1140 {
1141 throw_parse_error(m_path, line, token, lineNumber);
1142 }
1143
1144 auto pOutlineRecord = std::make_shared<PackageRecord::OutlineRecord>();
1145 pOutlineRecord->type = PackageRecord::OutlineRecord::Type::Rectangle;
1146
1147 if (!(lineStream >> pOutlineRecord->lowerLeftX))
1148 {
1149 throw_parse_error(m_path, line, token, lineNumber);
1150 }
1151
1152 if (!(lineStream >> pOutlineRecord->lowerLeftY))
1153 {
1154 throw_parse_error(m_path, line, token, lineNumber);
1155 }
1156
1157 if (!(lineStream >> pOutlineRecord->width))
1158 {
1159 throw_parse_error(m_path, line, token, lineNumber);
1160 }
1161
1162 if (!(lineStream >> pOutlineRecord->height))
1163 {
1164 throw_parse_error(m_path, line, token, lineNumber);
1165 }
1166
1167 if (pCurrentPackageRecord != nullptr)
1168 {
1169 if (pCurrentPinRecord != nullptr)
1170 {
1171 pCurrentPinRecord->m_outlineRecords.push_back(pOutlineRecord);
1172 }
1173 else
1174 {
1175 pCurrentPackageRecord->m_outlineRecords.push_back(pOutlineRecord);
1176 }
1177 }
1178 else
1179 {
1180 throw_parse_error(m_path, line, token, lineNumber);
1181 }
1182 }
1183 else if (line.find(PackageRecord::OutlineRecord::CIRCLE_RECORD_TOKEN) == 0)
1184 {
1185 std::string token;
1186 if (!(lineStream >> token))
1187 {
1188 throw_parse_error(m_path, line, token, lineNumber);
1189 }
1190
1191 if (token != PackageRecord::OutlineRecord::CIRCLE_RECORD_TOKEN)
1192 {
1193 throw_parse_error(m_path, line, token, lineNumber);
1194 }
1195
1196 auto pOutlineRecord = std::make_shared<PackageRecord::OutlineRecord>();
1197 pOutlineRecord->type = PackageRecord::OutlineRecord::Type::Circle;
1198
1199 if (!(lineStream >> pOutlineRecord->xCenter))
1200 {
1201 throw_parse_error(m_path, line, token, lineNumber);
1202 }
1203
1204 if (!(lineStream >> pOutlineRecord->yCenter))
1205 {
1206 throw_parse_error(m_path, line, token, lineNumber);
1207 }
1208
1209 if (!(lineStream >> pOutlineRecord->radius))
1210 {
1211 throw_parse_error(m_path, line, token, lineNumber);
1212 }
1213
1214 if (pCurrentPackageRecord != nullptr)
1215 {
1216 if (pCurrentPinRecord != nullptr)
1217 {
1218 pCurrentPinRecord->m_outlineRecords.push_back(pOutlineRecord);
1219 }
1220 else
1221 {
1222 pCurrentPackageRecord->m_outlineRecords.push_back(pOutlineRecord);
1223 }
1224 }
1225 else
1226 {
1227 throw_parse_error(m_path, line, token, lineNumber);
1228 }
1229 }
1230 else if (line.find(PackageRecord::OutlineRecord::SQUARE_RECORD_TOKEN) == 0)
1231 {
1232 std::string token;
1233 if (!(lineStream >> token))
1234 {
1235 throw_parse_error(m_path, line, token, lineNumber);
1236 }
1237
1238 if (token != PackageRecord::OutlineRecord::SQUARE_RECORD_TOKEN)
1239 {
1240 throw_parse_error(m_path, line, token, lineNumber);
1241 }
1242
1243 auto pOutlineRecord = std::make_shared<PackageRecord::OutlineRecord>();
1244 pOutlineRecord->type = PackageRecord::OutlineRecord::Type::Square;
1245
1246 if (!(lineStream >> pOutlineRecord->xCenter))
1247 {
1248 throw_parse_error(m_path, line, token, lineNumber);
1249 }
1250
1251 if (!(lineStream >> pOutlineRecord->yCenter))
1252 {
1253 throw_parse_error(m_path, line, token, lineNumber);
1254 }
1255
1256 if (!(lineStream >> pOutlineRecord->halfSide))
1257 {
1258 throw_parse_error(m_path, line, token, lineNumber);
1259 }
1260
1261 if (pCurrentPackageRecord != nullptr)
1262 {
1263 if (pCurrentPinRecord != nullptr)
1264 {
1265 pCurrentPinRecord->m_outlineRecords.push_back(pOutlineRecord);
1266 }
1267 else
1268 {
1269 pCurrentPackageRecord->m_outlineRecords.push_back(pOutlineRecord);
1270 }
1271 }
1272 else
1273 {
1274 throw_parse_error(m_path, line, token, lineNumber);
1275 }
1276 }
1277 else if (line.find(PackageRecord::OutlineRecord::CONTOUR_BEGIN_RECORD_TOKEN) == 0)
1278 {
1279 std::string token;
1280 if (!(lineStream >> token))
1281 {
1282 throw_parse_error(m_path, line, token, lineNumber);
1283 }
1284
1285 if (token != PackageRecord::OutlineRecord::CONTOUR_BEGIN_RECORD_TOKEN)
1286 {
1287 throw_parse_error(m_path, line, token, lineNumber);
1288 }
1289
1290 pCurrentContourOutlineRecord = std::make_shared<PackageRecord::OutlineRecord>();
1291 pCurrentContourOutlineRecord->type = PackageRecord::OutlineRecord::Type::Contour;
1292 }
1293 else if (line.find(PackageRecord::OutlineRecord::CONTOUR_END_RECORD_TOKEN) == 0)
1294 {
1295 std::string token;
1296 if (!(lineStream >> token))
1297 {
1298 throw_parse_error(m_path, line, token, lineNumber);
1299 }
1300
1301 if (token != PackageRecord::OutlineRecord::CONTOUR_END_RECORD_TOKEN)
1302 {
1303 throw_parse_error(m_path, line, token, lineNumber);
1304 }
1305
1306 if (pCurrentPackageRecord != nullptr)
1307 {
1308 if (pCurrentPinRecord != nullptr)
1309 {
1310 pCurrentPinRecord->m_outlineRecords.push_back(pCurrentContourOutlineRecord);
1311 }
1312 else
1313 {
1314 pCurrentPackageRecord->m_outlineRecords.push_back(pCurrentContourOutlineRecord);
1315 }
1316 }
1317 else
1318 {
1319 throw_parse_error(m_path, line, token, lineNumber);
1320 }
1321
1322 pCurrentContourOutlineRecord.reset();
1323 }
1324 else if (line.find(ContourPolygon::BEGIN_RECORD_TOKEN) == 0)
1325 {
1326 std::string token;
1327 if (!(lineStream >> token))
1328 {
1329 throw_parse_error(m_path, line, token, lineNumber);
1330 }
1331
1332 if (token != ContourPolygon::BEGIN_RECORD_TOKEN)
1333 {
1334 throw_parse_error(m_path, line, token, lineNumber);
1335 }
1336
1337 pCurrentContourPolygon = std::make_shared<ContourPolygon>();
1338
1339 if (!(lineStream >> pCurrentContourPolygon->xStart))
1340 {
1341 throw_parse_error(m_path, line, token, lineNumber);
1342 }
1343
1344 if (!(lineStream >> pCurrentContourPolygon->yStart))
1345 {
1346 throw_parse_error(m_path, line, token, lineNumber);
1347 }
1348
1349 if (!(lineStream >> token))
1350 {
1351 throw_parse_error(m_path, line, token, lineNumber);
1352 }
1353
1354 if (token == ContourPolygon::ISLAND_TYPE_TOKEN)
1355 {
1356 pCurrentContourPolygon->type = ContourPolygon::Type::Island;
1357 }
1358 else if (token == ContourPolygon::HOLE_TYPE_TOKEN)
1359 {
1360 pCurrentContourPolygon->type = ContourPolygon::Type::Hole;
1361 }
1362 else
1363 {
1364 throw_parse_error(m_path, line, token, lineNumber);
1365 }
1366 }
1367 else if (line.find(ContourPolygon::END_RECORD_TOKEN) == 0)
1368 {
1369 std::string token;
1370 if (!(lineStream >> token))
1371 {
1372 throw_parse_error(m_path, line, token, lineNumber);
1373 }
1374
1375 if (token != ContourPolygon::END_RECORD_TOKEN)
1376 {
1377 throw_parse_error(m_path, line, token, lineNumber);
1378 }
1379
1380 if (pCurrentContourOutlineRecord != nullptr)
1381 {
1382 pCurrentContourOutlineRecord->m_contourPolygons.push_back(pCurrentContourPolygon);
1383 pCurrentContourPolygon.reset();
1384 }
1385 else
1386 {
1387 throw_parse_error(m_path, line, token, lineNumber);
1388 }
1389 }
1390 else if (line.find(ContourPolygon::PolygonPart::ARC_RECORD_TOKEN) == 0)
1391 {
1392 std::string token;
1393 if (!(lineStream >> token))
1394 {
1395 throw_parse_error(m_path, line, token, lineNumber);
1396 }
1397
1398 if (token != ContourPolygon::PolygonPart::ARC_RECORD_TOKEN)
1399 {
1400 throw_parse_error(m_path, line, token, lineNumber);
1401 }
1402
1403 auto pPolygonPart = std::make_shared<ContourPolygon::PolygonPart>();
1404 pPolygonPart->type = ContourPolygon::PolygonPart::Type::Arc;
1405
1406 if (!(lineStream >> pPolygonPart->endX))
1407 {
1408 throw_parse_error(m_path, line, token, lineNumber);
1409 }
1410
1411 if (!(lineStream >> pPolygonPart->endY))
1412 {
1413 throw_parse_error(m_path, line, token, lineNumber);
1414 }
1415
1416 if (!(lineStream >> pPolygonPart->xCenter))
1417 {
1418 throw_parse_error(m_path, line, token, lineNumber);
1419 }
1420
1421 if (!(lineStream >> pPolygonPart->yCenter))
1422 {
1423 throw_parse_error(m_path, line, token, lineNumber);
1424 }
1425
1426 if (!(lineStream >> token))
1427 {
1428 throw_parse_error(m_path, line, token, lineNumber);
1429 }
1430
1431 if (token == "y" || token == "Y")
1432 {
1433 pPolygonPart->isClockwise = true;
1434 }
1435 else if (token == "n" || token == "N")
1436 {
1437 pPolygonPart->isClockwise = false;
1438 }
1439 else
1440 {
1441 throw_parse_error(m_path, line, token, lineNumber);
1442 }
1443
1444 if (pCurrentContourPolygon != nullptr)
1445 {
1446 pCurrentContourPolygon->m_polygonParts.push_back(pPolygonPart);
1447 }
1448 else
1449 {
1450 throw_parse_error(m_path, line, token, lineNumber);
1451 }
1452 }
1453 else if (line.find(ContourPolygon::PolygonPart::SEGMENT_RECORD_TOKEN) == 0)
1454 {
1455 std::string token;
1456 if (!(lineStream >> token))
1457 {
1458 throw_parse_error(m_path, line, token, lineNumber);
1459 }
1460
1461 if (token != ContourPolygon::PolygonPart::SEGMENT_RECORD_TOKEN)
1462 {
1463 throw_parse_error(m_path, line, token, lineNumber);
1464 }
1465
1466 auto pPolygonPart = std::make_shared<ContourPolygon::PolygonPart>();
1467 pPolygonPart->type = ContourPolygon::PolygonPart::Type::Segment;
1468
1469 if (!(lineStream >> pPolygonPart->endX))
1470 {
1471 throw_parse_error(m_path, line, token, lineNumber);
1472 }
1473
1474 if (!(lineStream >> pPolygonPart->endY))
1475 {
1476 throw_parse_error(m_path, line, token, lineNumber);
1477 }
1478
1479 if (pCurrentContourPolygon != nullptr)
1480 {
1481 pCurrentContourPolygon->m_polygonParts.push_back(pPolygonPart);
1482 }
1483 else
1484 {
1485 throw_parse_error(m_path, line, token, lineNumber);
1486 }
1487 }
1488 else
1489 {
1490 // unrecognized record line
1491 parse_info pi(m_path, line, lineNumber);
1492 logwarn(pi.toString("unrecognized record line in EDADATA file:"));
1493 }
1494 }
1495 else
1496 {
1497 // empty line
1498 continue;
1499 }
1500 }
1501
1502 // finish current (previous) net record
1503 // this is the case where the last line of the file is not a net record (and there are no PKG records)
1504 if (pCurrentNetRecord != nullptr)
1505 {
1506 // finish current (previous) subnet record
1507 // case where we reach the end of the file before a new net record is encountered (and there are no PKG records)
1508 if (pCurrentSubnetRecord != nullptr)
1509 {
1510 pCurrentNetRecord->m_subnetRecords.push_back(pCurrentSubnetRecord);
1511 pCurrentSubnetRecord.reset();
1512 }
1513
1514 m_netRecords.push_back(pCurrentNetRecord);
1515 //m_netRecordsByName[pCurrentNetRecord->name] = pCurrentNetRecord;
1516 pCurrentNetRecord.reset();
1517 }
1518 else if (pCurrentPackageRecord != nullptr)
1519 {
1520 // finish up any current (previous) pin records
1521 if (pCurrentPinRecord != nullptr)
1522 {
1523 // check for overflow
1524 if (pCurrentPackageRecord->m_pinRecords.size() > UINT_MAX)
1525 {
1526 throw_parse_error(m_path, line, "", lineNumber);
1527 }
1528 pCurrentPinRecord->index = static_cast<unsigned>(pCurrentPackageRecord->m_pinRecords.size());
1529 pCurrentPackageRecord->m_pinRecords.push_back(pCurrentPinRecord);
1530 pCurrentPinRecord.reset();
1531 }
1532
1533 // finish up any current (previous) package records
1534 m_packageRecords.push_back(pCurrentPackageRecord);
1535 //m_packageRecordsByName[pCurrentPackageRecord->name] = pCurrentPackageRecord;
1536 pCurrentPackageRecord.reset();
1537 }
1538 else if (pCurrentFeatureGroupRecord != nullptr)
1539 {
1540 m_featureGroupRecords.push_back(pCurrentFeatureGroupRecord);
1541 pCurrentFeatureGroupRecord.reset();
1542 }
1543
1544 edaDataFile.close();
1545 }
1546 catch (parse_error& pe)
1547 {
1548 auto m = pe.toString("Parse Error:");
1549 logerror(m);
1550 // cleanup file
1551 edaDataFile.close();
1552 throw pe;
1553 }
1554 catch (std::exception& e)
1555 {
1556 parse_info pi(m_path, line, lineNumber);
1557 const auto m = pi.toString();
1558 logexception_msg(e, m);
1559 // cleanup file
1560 edaDataFile.close();
1561 throw e;
1562 }
1563
1564 return true;
1565 }
1566
1567 // Inherited via IProtoBuffable
1568 std::unique_ptr<Odb::Lib::Protobuf::EdaDataFile::PackageRecord>
1569 EdaDataFile::PackageRecord::to_protobuf() const
1570 {
1571 std::unique_ptr<Odb::Lib::Protobuf::EdaDataFile::PackageRecord> pPackageRecordMessage(new Odb::Lib::Protobuf::EdaDataFile::PackageRecord);
1572 pPackageRecordMessage->set_name(name);
1573 pPackageRecordMessage->set_pitch(pitch);
1574 pPackageRecordMessage->set_xmin(xMin);
1575 pPackageRecordMessage->set_ymin(yMin);
1576 pPackageRecordMessage->set_xmax(xMax);
1577 pPackageRecordMessage->set_ymax(yMax);
1578 //pPackageRecordMessage->set_attributesidstring(attributesIdString);
1579 for (const auto& pinRecord : m_pinRecords)
1580 {
1581 auto pPinRecordMessage = pPackageRecordMessage->add_pinrecords();
1582 pPinRecordMessage->CopyFrom(*pinRecord->to_protobuf());
1583 }
1584 for (const auto& kvPinRecord : m_pinRecordsByName)
1585 {
1586 (*pPackageRecordMessage->mutable_pinrecordsbyname())[kvPinRecord.first] = *kvPinRecord.second->to_protobuf();
1587 }
1588 for (const auto& propertyRecord : m_propertyRecords)
1589 {
1590 auto pPropertyRecordMessage = pPackageRecordMessage->add_propertyrecords();
1591 pPropertyRecordMessage->CopyFrom(*propertyRecord->to_protobuf());
1592 }
1593 for (const auto& outlineRecord : m_outlineRecords)
1594 {
1595 auto pOutlineRecordMessage = pPackageRecordMessage->add_outlinerecords();
1596 pOutlineRecordMessage->CopyFrom(*outlineRecord->to_protobuf());
1597 }
1598 for (const auto& kvAttributeAssignment : m_attributeLookupTable)
1599 {
1600 (*pPackageRecordMessage->mutable_attributelookuptable())[kvAttributeAssignment.first] = kvAttributeAssignment.second;
1601 }
1602 return pPackageRecordMessage;
1603 }
1604
1605 void EdaDataFile::PackageRecord::from_protobuf(const Odb::Lib::Protobuf::EdaDataFile::PackageRecord& message)
1606 {
1607 name = message.name();
1608 pitch = message.pitch();
1609 xMin = message.xmin();
1610 yMin = message.ymin();
1611 xMax = message.xmax();
1612 yMax = message.ymax();
1613 //attributesIdString = message.attributesidstring();
1614
1615 for (const auto& pinRecordMessage : message.pinrecords())
1616 {
1617 auto pPinRecord = std::make_shared<PinRecord>();
1618 pPinRecord->from_protobuf(pinRecordMessage);
1619 m_pinRecords.push_back(pPinRecord);
1620 }
1621
1622 for (const auto& kvPinRecordMessage : message.pinrecordsbyname())
1623 {
1624 auto pPinRecord = std::make_shared<PinRecord>();
1625 pPinRecord->from_protobuf(kvPinRecordMessage.second);
1626 m_pinRecordsByName[kvPinRecordMessage.first] = pPinRecord;
1627 }
1628
1629 for (const auto& propertyRecordMessage : message.propertyrecords())
1630 {
1631 auto pPropertyRecord = std::make_shared<PropertyRecord>();
1632 pPropertyRecord->from_protobuf(propertyRecordMessage);
1633 m_propertyRecords.push_back(pPropertyRecord);
1634 }
1635
1636 for (const auto& outlineRecordMessage : message.outlinerecords())
1637 {
1638 auto pOutlineRecord = std::make_shared<OutlineRecord>();
1639 pOutlineRecord->from_protobuf(outlineRecordMessage);
1640 m_outlineRecords.push_back(pOutlineRecord);
1641 }
1642
1643 for (const auto& kvAttributeAssignment : message.attributelookuptable())
1644 {
1645 m_attributeLookupTable[kvAttributeAssignment.first] = kvAttributeAssignment.second;
1646 }
1647 }
1648
1649 // Inherited via IProtoBuffable
1650 std::unique_ptr<Odb::Lib::Protobuf::EdaDataFile::PackageRecord::OutlineRecord> EdaDataFile::PackageRecord::OutlineRecord::to_protobuf() const
1651 {
1652 std::unique_ptr<Odb::Lib::Protobuf::EdaDataFile::PackageRecord::OutlineRecord> pOutlineRecordMessage(new Odb::Lib::Protobuf::EdaDataFile::PackageRecord::OutlineRecord);
1653 pOutlineRecordMessage->set_type((Odb::Lib::Protobuf::EdaDataFile::PackageRecord::OutlineRecord::Type)type);
1654 pOutlineRecordMessage->set_lowerleftx(lowerLeftX);
1655 pOutlineRecordMessage->set_lowerlefty(lowerLeftY);
1656 pOutlineRecordMessage->set_width(width);
1657 pOutlineRecordMessage->set_height(height);
1658 pOutlineRecordMessage->set_xcenter(xCenter);
1659 pOutlineRecordMessage->set_ycenter(yCenter);
1660 pOutlineRecordMessage->set_radius(radius);
1661 pOutlineRecordMessage->set_halfside(halfSide);
1662 for (const auto& contourPolygon : m_contourPolygons)
1663 {
1664 auto pContourPolygonMessage = pOutlineRecordMessage->add_contourpolygons();
1665 pContourPolygonMessage->CopyFrom(*contourPolygon->to_protobuf());
1666 }
1667 return pOutlineRecordMessage;
1668 }
1669
1670 void EdaDataFile::PackageRecord::OutlineRecord::from_protobuf(const Odb::Lib::Protobuf::EdaDataFile::PackageRecord::OutlineRecord& message)
1671 {
1672 type = (Type)message.type();
1673 lowerLeftX = message.lowerleftx();
1674 lowerLeftY = message.lowerlefty();
1675 width = message.width();
1676 height = message.height();
1677 xCenter = message.xcenter();
1678 yCenter = message.ycenter();
1679 radius = message.radius();
1680 halfSide = message.halfside();
1681 for (const auto& contourPolygonMessage : message.contourpolygons())
1682 {
1683 auto pContourPolygon = std::make_shared<ContourPolygon>();
1684 pContourPolygon->from_protobuf(contourPolygonMessage);
1685 m_contourPolygons.push_back(pContourPolygon);
1686 }
1687 }
1688
1689 // Inherited via IProtoBuffable
1690 std::unique_ptr<Odb::Lib::Protobuf::EdaDataFile::PackageRecord::PinRecord>
1691 EdaDataFile::PackageRecord::PinRecord::to_protobuf() const
1692 {
1693 std::unique_ptr<Odb::Lib::Protobuf::EdaDataFile::PackageRecord::PinRecord> pPinRecordMessage(new Odb::Lib::Protobuf::EdaDataFile::PackageRecord::PinRecord);
1694 pPinRecordMessage->set_name(name);
1695 pPinRecordMessage->set_type((Odb::Lib::Protobuf::EdaDataFile::PackageRecord::PinRecord::Type)type);
1696 pPinRecordMessage->set_xcenter(xCenter);
1697 pPinRecordMessage->set_ycenter(yCenter);
1698 pPinRecordMessage->set_finishedholesize(finishedHoleSize);
1699 pPinRecordMessage->set_electricaltype((Odb::Lib::Protobuf::EdaDataFile::PackageRecord::PinRecord::ElectricalType)electricalType);
1700 pPinRecordMessage->set_mounttype((Odb::Lib::Protobuf::EdaDataFile::PackageRecord::PinRecord::MountType)mountType);
1701 pPinRecordMessage->set_id(id);
1702 pPinRecordMessage->set_index(index);
1703 return pPinRecordMessage;
1704 }
1705
1706 void EdaDataFile::PackageRecord::PinRecord::from_protobuf(const Odb::Lib::Protobuf::EdaDataFile::PackageRecord::PinRecord& message)
1707 {
1708 name = message.name();
1709 type = (Type)message.type();
1710 xCenter = message.xcenter();
1711 yCenter = message.ycenter();
1712 finishedHoleSize = message.finishedholesize();
1713 electricalType = (ElectricalType)message.electricaltype();
1714 mountType = (MountType)message.mounttype();
1715 id = message.id();
1716 index = message.index();
1717 }
1718}