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