OdbDesignLib
OdbDesign ODB++ Parsing Library
FeaturesFile.cpp
1 #include "FeaturesFile.h"
2 #include "FeaturesFile.h"
3 #include "ArchiveExtractor.h"
4 #include <fstream>
5 #include "Logger.h"
6 #include "../invalid_odb_error.h"
7 #include "str_utils.h"
8 #include "../parse_error.h"
9 #include "SymbolName.h"
10 #include "equals_within.h"
11 #include "macros.h"
12 
13 
14 namespace Odb::Lib::FileModel::Design
15 {
16  FeaturesFile::FeaturesFile()
17  : m_units("")
18  , m_path("")
19  , m_directory("")
20  , m_numFeatures(0)
21  , m_id((unsigned) -1)
22  {
23  }
24 
25  FeaturesFile::~FeaturesFile()
26  {
27  m_featureRecords.clear();
28  m_attributeNames.clear();
29  m_attributeTextValues.clear();
30  m_symbolNamesByName.clear();
31  }
32 
33  bool FeaturesFile::Parse(std::filesystem::path directory, const std::string& alternateFilename /*= ""*/)
34  {
35  std::ifstream featuresFile;
36  int lineNumber = 0;
37  std::string line;
38 
39  try
40  {
41  m_directory = directory;
42 
43  loginfo("checking for extraction...");
44 
45  std::vector<std::string> filenames;
46  if (alternateFilename.empty())
47  {
48  std::copy(std::begin(FEATURES_FILENAMES), std::end(FEATURES_FILENAMES), std::back_inserter(filenames));
49  }
50  else
51  {
52  filenames.push_back(alternateFilename);
53  }
54 
55  std::filesystem::path featuresFilePath;
56  for (const auto& featuresFilename : filenames)
57  {
58  loginfo("trying features file: [" + featuresFilename + "]...");
59 
60  featuresFilePath = Utils::ArchiveExtractor::getUncompressedFilePath(m_directory, featuresFilename);
61  if (exists(featuresFilePath) && is_regular_file(featuresFilePath))
62  {
63  loginfo("found features file: [" + featuresFilePath.string() + "]");
64  break;
65  }
66  }
67 
68  m_path = featuresFilePath;
69 
70  loginfo("any extraction complete, parsing data...");
71 
72  if (!std::filesystem::exists(m_path))
73  {
74  auto message = "features file does not exist: [" + m_path.string() + "]";
75  throw invalid_odb_error(message.c_str());
76  }
77  else if (!std::filesystem::is_regular_file(m_path))
78  {
79  auto message = "features is not a file: [" + m_path.string() + "]";
80  throw invalid_odb_error(message.c_str());
81  }
82 
83  featuresFile.open(m_path.string(), std::ios::in);
84  if (!featuresFile.is_open())
85  {
86  auto message = "unable to open features file: [" + m_path.string() + "]";
87  throw invalid_odb_error(message.c_str());
88  }
89 
90  std::shared_ptr<FeatureRecord> pCurrentFeatureRecord;
91  std::shared_ptr<ContourPolygon> pCurrentContourPolygon;
92 
93  while (std::getline(featuresFile, line))
94  {
95  lineNumber++;
96 
97  // trim whitespace from beginning and end of line
98  Utils::str_trim(line);
99  if (!line.empty())
100  {
101  std::stringstream lineStream(line);
102  //char firstChar = line[0];
103 
104  if (line.find(COMMENT_TOKEN) == 0)
105  {
106  // comment line
107  }
108  else if (line.find(UNITS_TOKEN) == 0)
109  {
110  // units line
111  std::string token;
112  if (!std::getline(lineStream, token, '='))
113  {
114  throw_parse_error(m_path, line, token, lineNumber);
115  }
116  else if (!std::getline(lineStream, token, '='))
117  {
118  throw_parse_error(m_path, line, token, lineNumber);
119  }
120 
121  m_units = token;
122  }
123  else if (line.find("U") == 0)
124  {
125  std::string token;
126  if (!std::getline(lineStream, token, ' '))
127  {
128  throw_parse_error(m_path, line, token, lineNumber);
129  }
130  else if (!std::getline(lineStream, token, ' '))
131  {
132  throw_parse_error(m_path, line, token, lineNumber);
133  }
134 
135  m_units = token;
136  }
137  else if (line.find(ID_TOKEN) == 0)
138  {
139  std::string token;
140  if (!std::getline(lineStream, token, '='))
141  {
142  throw_parse_error(m_path, line, token, lineNumber);
143  }
144  else if (!std::getline(lineStream, token, '='))
145  {
146  throw_parse_error(m_path, line, token, lineNumber);
147  }
148  m_id = std::stoul(token);
149  }
150  else if (line.find(NUM_FEATURES_TOKEN) == 0)
151  {
152  // component record line
153  std::string token;
154 
155  if (!(lineStream >> token))
156  {
157  throw_parse_error(m_path, line, token, lineNumber);
158  }
159 
160  if (token != NUM_FEATURES_TOKEN)
161  {
162  throw_parse_error(m_path, line, token, lineNumber);
163  }
164 
165  if (!(lineStream >> m_numFeatures))
166  {
167  throw_parse_error(m_path, line, token, lineNumber);
168  }
169  }
170  else if (line.find(ATTRIBUTE_NAME_TOKEN) == 0)
171  {
172  // component attribute name line
173  std::string token;
174  // TODO: continue on failing line parse, to make a less strict/more robust parser (make a flag: enum ParseStrictness { strict, lax })
175  if (!std::getline(lineStream, token, ' '))
176  {
177  throw_parse_error(m_path, line, token, lineNumber);
178  }
179  else if (!std::getline(lineStream, token, ' '))
180  {
181  throw_parse_error(m_path, line, token, lineNumber);
182  }
183  m_attributeNames.push_back(token);
184  }
185  else if (line.find(ATTRIBUTE_VALUE_TOKEN) == 0)
186  {
187  // component attribute text string values
188  std::string token;
189  if (!std::getline(lineStream, token, ' '))
190  {
191  throw_parse_error(m_path, line, token, lineNumber);
192  }
193  else if (!std::getline(lineStream, token, ' '))
194  {
195  throw_parse_error(m_path, line, token, lineNumber);
196  }
197  m_attributeTextValues.push_back(token);
198  }
199  else if (line.find(SYMBOL_NAME_TOKEN) == 0)
200  {
201  // component attribute text string values
202  auto pSymbolName = std::make_shared<SymbolName>();
203  if (!pSymbolName->SymbolName::Parse(m_path, line, lineNumber))
204  {
205  throw_parse_error(m_path, line, "", lineNumber);
206  }
207  m_symbolNamesByName[pSymbolName->GetName()] = pSymbolName;
208  }
209  else if (line.find(FeatureRecord::LINE_TOKEN) == 0)
210  {
211  std::string token;
212  if (!(lineStream >> token) || token != FeatureRecord::LINE_TOKEN)
213  {
214  throw_parse_error(m_path, line, token, lineNumber);
215  }
216 
217  auto pFeatureRecord = std::make_shared<FeatureRecord>();
218  pFeatureRecord->type = FeatureRecord::Type::Line;
219 
220  if (!(lineStream >> pFeatureRecord->xs))
221  {
222  throw_parse_error(m_path, line, token, lineNumber);
223  }
224 
225  if (!(lineStream >> pFeatureRecord->ys))
226  {
227  throw_parse_error(m_path, line, token, lineNumber);
228  }
229 
230  if (!(lineStream >> pFeatureRecord->xe))
231  {
232  throw_parse_error(m_path, line, token, lineNumber);
233  }
234 
235  if (!(lineStream >> pFeatureRecord->ye))
236  {
237  throw_parse_error(m_path, line, token, lineNumber);
238  }
239 
240  if (!(lineStream >> pFeatureRecord->sym_num))
241  {
242  throw_parse_error(m_path, line, token, lineNumber);
243  }
244 
245  char polarity;
246  if (!(lineStream >> polarity))
247  {
248  throw_parse_error(m_path, line, token, lineNumber);
249  }
250  switch (polarity)
251  {
252  case 'P': pFeatureRecord->polarity = Polarity::Positive; break;
253  case 'N': pFeatureRecord->polarity = Polarity::Negative; break;
254  default: throw_parse_error(m_path, line, token, lineNumber);
255  }
256 
257  if (!(lineStream >> pFeatureRecord->dcode))
258  {
259  throw_parse_error(m_path, line, token, lineNumber);
260  }
261 
262  std::string attrIdString;
263  lineStream >> attrIdString;
264 
265  if (!pFeatureRecord->ParseAttributeLookupTable(attrIdString))
266  {
267  throw_parse_error(m_path, line, token, lineNumber);
268  }
269 
270  m_featureRecords.push_back(pFeatureRecord);
271  }
272  else if (line.find(FeatureRecord::PAD_TOKEN) == 0)
273  {
274  std::string token;
275  if (!(lineStream >> token) || token != FeatureRecord::PAD_TOKEN)
276  {
277  throw_parse_error(m_path, line, token, lineNumber);
278  }
279 
280  auto pFeatureRecord = std::make_shared<FeatureRecord>();
281  pFeatureRecord->type = FeatureRecord::Type::Pad;
282 
283  if (!(lineStream >> pFeatureRecord->x))
284  {
285  throw_parse_error(m_path, line, token, lineNumber);
286  }
287 
288  if (!(lineStream >> pFeatureRecord->y))
289  {
290  throw_parse_error(m_path, line, token, lineNumber);
291  }
292 
293  if (!(lineStream >> pFeatureRecord->apt_def_symbol_num))
294  {
295  throw_parse_error(m_path, line, token, lineNumber);
296  }
297  if (pFeatureRecord->apt_def_symbol_num == -1)
298  {
299  if (!(lineStream >> pFeatureRecord->apt_def_resize_factor))
300  {
301  throw_parse_error(m_path, line, token, lineNumber);
302  }
303  }
304 
305  char polarity;
306  if (!(lineStream >> polarity))
307  {
308  throw_parse_error(m_path, line, token, lineNumber);
309  }
310  switch (polarity)
311  {
312  case 'P': pFeatureRecord->polarity = Polarity::Positive; break;
313  case 'N': pFeatureRecord->polarity = Polarity::Negative; break;
314  default: throw_parse_error(m_path, line, token, lineNumber);
315  }
316 
317  if (!(lineStream >> pFeatureRecord->dcode))
318  {
319  throw_parse_error(m_path, line, token, lineNumber);
320  }
321 
322  if (!(lineStream >> pFeatureRecord->orient_def))
323  {
324  throw_parse_error(m_path, line, token, lineNumber);
325  }
326 
327  std::string attrIdString;
328  lineStream >> attrIdString;
329 
330  if (!pFeatureRecord->ParseAttributeLookupTable(attrIdString))
331  {
332  throw_parse_error(m_path, line, token, lineNumber);
333  }
334 
335  m_featureRecords.push_back(pFeatureRecord);
336  }
337  else if (line.find(FeatureRecord::TEXT_TOKEN) == 0)
338  {
339  std::string token;
340  if (!(lineStream >> token) || token != FeatureRecord::TEXT_TOKEN)
341  {
342  throw_parse_error(m_path, line, token, lineNumber);
343  }
344 
345  auto pFeatureRecord = std::make_shared<FeatureRecord>();
346  pFeatureRecord->type = FeatureRecord::Type::Text;
347 
348  if (!(lineStream >> pFeatureRecord->x))
349  {
350  throw_parse_error(m_path, line, token, lineNumber);
351  }
352 
353  if (!(lineStream >> pFeatureRecord->y))
354  {
355  throw_parse_error(m_path, line, token, lineNumber);
356  }
357 
358  if (!(lineStream >> pFeatureRecord->font))
359  {
360  throw_parse_error(m_path, line, token, lineNumber);
361  }
362 
363  char polarity;
364  if (!(lineStream >> polarity))
365  {
366  throw_parse_error(m_path, line, token, lineNumber);
367  }
368  switch (polarity)
369  {
370  case 'P': pFeatureRecord->polarity = Polarity::Positive; break;
371  case 'N': pFeatureRecord->polarity = Polarity::Negative; break;
372  default: throw_parse_error(m_path, line, token, lineNumber);
373  }
374 
375  if (!(lineStream >> pFeatureRecord->orient_def))
376  {
377  throw_parse_error(m_path, line, token, lineNumber);
378  }
379 
380  if (pFeatureRecord->orient_def == 8 ||
381  pFeatureRecord->orient_def == 9)
382  {
383  if (!(lineStream >> pFeatureRecord->orient_def_rotation))
384  {
385  throw_parse_error(m_path, line, token, lineNumber);
386  }
387  }
388 
389  if (!(lineStream >> pFeatureRecord->xsize))
390  {
391  throw_parse_error(m_path, line, token, lineNumber);
392  }
393 
394  if (!(lineStream >> pFeatureRecord->ysize))
395  {
396  throw_parse_error(m_path, line, token, lineNumber);
397  }
398 
399  if (!(lineStream >> pFeatureRecord->width_factor))
400  {
401  throw_parse_error(m_path, line, token, lineNumber);
402  }
403 
404  if (!(lineStream >> std::quoted(pFeatureRecord->text, '\'')))
405  {
406  throw_parse_error(m_path, line, token, lineNumber);
407  }
408 
409  if (!(lineStream >> pFeatureRecord->version))
410  {
411  throw_parse_error(m_path, line, token, lineNumber);
412  }
413 
414  std::string attrIdString;
415  lineStream >> attrIdString;
416 
417  if (!pFeatureRecord->ParseAttributeLookupTable(attrIdString))
418  {
419  throw_parse_error(m_path, line, token, lineNumber);
420  }
421 
422  m_featureRecords.push_back(pFeatureRecord);
423  }
424  else if (line.find(FeatureRecord::ARC_TOKEN) == 0)
425  {
426  std::string token;
427  if (!(lineStream >> token) || token != FeatureRecord::ARC_TOKEN)
428  {
429  throw_parse_error(m_path, line, token, lineNumber);
430  }
431 
432  auto pFeatureRecord = std::make_shared<FeatureRecord>();
433  pFeatureRecord->type = FeatureRecord::Type::Arc;
434 
435  if (!(lineStream >> pFeatureRecord->xs))
436  {
437  throw_parse_error(m_path, line, token, lineNumber);
438  }
439 
440  if (!(lineStream >> pFeatureRecord->ys))
441  {
442  throw_parse_error(m_path, line, token, lineNumber);
443  }
444 
445  if (!(lineStream >> pFeatureRecord->xe))
446  {
447  throw_parse_error(m_path, line, token, lineNumber);
448  }
449 
450  if (!(lineStream >> pFeatureRecord->ye))
451  {
452  throw_parse_error(m_path, line, token, lineNumber);
453  }
454 
455  if (!(lineStream >> pFeatureRecord->xc))
456  {
457  throw_parse_error(m_path, line, token, lineNumber);
458  }
459 
460  if (!(lineStream >> pFeatureRecord->yc))
461  {
462  throw_parse_error(m_path, line, token, lineNumber);
463  }
464 
465 
466  if (!(lineStream >> pFeatureRecord->sym_num))
467  {
468  throw_parse_error(m_path, line, token, lineNumber);
469  }
470 
471  char polarity;
472  if (!(lineStream >> polarity))
473  {
474  throw_parse_error(m_path, line, token, lineNumber);
475  }
476  switch (polarity)
477  {
478  case 'P': pFeatureRecord->polarity = Polarity::Positive; break;
479  case 'N': pFeatureRecord->polarity = Polarity::Negative; break;
480  default: throw_parse_error(m_path, line, token, lineNumber);
481  }
482 
483  if (!(lineStream >> pFeatureRecord->dcode))
484  {
485  throw_parse_error(m_path, line, token, lineNumber);
486  }
487 
488  char cw;
489  if (!(lineStream >> cw))
490  {
491  throw_parse_error(m_path, line, token, lineNumber);
492  }
493  switch (cw)
494  {
495  case 'Y': pFeatureRecord->cw = true; break;
496  case 'N': pFeatureRecord->cw = false; break;
497  default: throw_parse_error(m_path, line, token, lineNumber);
498  }
499 
500  std::string attrIdString;
501  lineStream >> attrIdString;
502 
503  if (!pFeatureRecord->ParseAttributeLookupTable(attrIdString))
504  {
505  throw_parse_error(m_path, line, token, lineNumber);
506  }
507 
508  m_featureRecords.push_back(pFeatureRecord);
509  }
510  else if (line.find(FeatureRecord::BARCODE_TOKEN) == 0)
511  {
512  std::string token;
513  if (!(lineStream >> token) || token != FeatureRecord::BARCODE_TOKEN)
514  {
515  throw_parse_error(m_path, line, token, lineNumber);
516  }
517 
518  auto pFeatureRecord = std::make_shared<FeatureRecord>();
519  pFeatureRecord->type = FeatureRecord::Type::Barcode;
520 
521  // TODO: barcode feature record type
522 
523  //std::string attrIdString;
524  //lineStream >> attrIdString;
525 
526  //if (!pFeatureRecord->ParseAttributeLookupTable(attrIdString))
527  //{
528  // throw_parse_error(m_path, line, token, lineNumber);
529  //}
530 
531  m_featureRecords.push_back(pFeatureRecord);
532  }
533  else if (line.find(FeatureRecord::SURFACE_START_TOKEN) == 0 &&
534  line.size() > 1 && line[1] == ' ')
535  {
536  std::string token;
537  if (!(lineStream >> token) || token != FeatureRecord::SURFACE_START_TOKEN)
538  {
539  throw_parse_error(m_path, line, token, lineNumber);
540  }
541 
542  pCurrentFeatureRecord = std::make_shared<FeatureRecord>();
543  pCurrentFeatureRecord->type = FeatureRecord::Type::Surface;
544 
545  char polarity;
546  if (!(lineStream >> polarity))
547  {
548  throw_parse_error(m_path, line, token, lineNumber);
549  }
550  switch (polarity)
551  {
552  case 'P': pCurrentFeatureRecord->polarity = Polarity::Positive; break;
553  case 'N': pCurrentFeatureRecord->polarity = Polarity::Negative; break;
554  default: throw_parse_error(m_path, line, token, lineNumber);
555  }
556 
557  if (!(lineStream >> pCurrentFeatureRecord->dcode))
558  {
559  throw_parse_error(m_path, line, token, lineNumber);
560  }
561 
562  std::string attrIdString;
563  lineStream >> attrIdString;
564 
565  if (!pCurrentFeatureRecord->ParseAttributeLookupTable(attrIdString))
566  {
567  throw_parse_error(m_path, line, token, lineNumber);
568  }
569  }
570  else if (line.find(FeatureRecord::SURFACE_END_TOKEN) == 0)
571  {
572  std::string token;
573  if (!(lineStream >> token) || token != FeatureRecord::SURFACE_END_TOKEN)
574  {
575  throw_parse_error(m_path, line, token, lineNumber);
576  }
577 
578  if (pCurrentFeatureRecord != nullptr)
579  {
580  m_featureRecords.push_back(pCurrentFeatureRecord);
581  pCurrentFeatureRecord.reset();
582  }
583  else
584  {
585  throw_parse_error(m_path, line, token, lineNumber);
586  }
587  }
588  else if (line.find(ContourPolygon::BEGIN_RECORD_TOKEN) == 0)
589  {
590  std::string token;
591  if (!(lineStream >> token))
592  {
593  throw_parse_error(m_path, line, token, lineNumber);
594  }
595 
596  if (token != ContourPolygon::BEGIN_RECORD_TOKEN)
597  {
598  throw_parse_error(m_path, line, token, lineNumber);
599  }
600 
601  pCurrentContourPolygon = std::make_shared<ContourPolygon>();
602 
603  if (!(lineStream >> pCurrentContourPolygon->xStart))
604  {
605  throw_parse_error(m_path, line, token, lineNumber);
606  }
607 
608  if (!(lineStream >> pCurrentContourPolygon->yStart))
609  {
610  throw_parse_error(m_path, line, token, lineNumber);
611  }
612 
613  if (!(lineStream >> token))
614  {
615  throw_parse_error(m_path, line, token, lineNumber);
616  }
617 
618  if (token == ContourPolygon::ISLAND_TYPE_TOKEN)
619  {
620  pCurrentContourPolygon->type = ContourPolygon::Type::Island;
621  }
622  else if (token == ContourPolygon::HOLE_TYPE_TOKEN)
623  {
624  pCurrentContourPolygon->type = ContourPolygon::Type::Hole;
625  }
626  else
627  {
628  throw_parse_error(m_path, line, token, lineNumber);
629  }
630  }
631  else if (line.find(ContourPolygon::END_RECORD_TOKEN) == 0)
632  {
633  std::string token;
634  if (!(lineStream >> token))
635  {
636  throw_parse_error(m_path, line, token, lineNumber);
637  }
638 
639  if (token != ContourPolygon::END_RECORD_TOKEN)
640  {
641  throw_parse_error(m_path, line, token, lineNumber);
642  }
643 
644  if (pCurrentFeatureRecord != nullptr)
645  {
646  pCurrentFeatureRecord->m_contourPolygons.push_back(pCurrentContourPolygon);
647  pCurrentContourPolygon.reset();
648  }
649  else
650  {
651  throw_parse_error(m_path, line, token, lineNumber);
652  }
653  }
654  else if (line.find(ContourPolygon::PolygonPart::ARC_RECORD_TOKEN) == 0)
655  {
656  std::string token;
657  if (!(lineStream >> token))
658  {
659  throw_parse_error(m_path, line, token, lineNumber);
660  }
661 
662  if (token != ContourPolygon::PolygonPart::ARC_RECORD_TOKEN)
663  {
664  throw_parse_error(m_path, line, token, lineNumber);
665  }
666 
667  auto pPolygonPart = std::make_shared<ContourPolygon::PolygonPart>();
668  pPolygonPart->type = ContourPolygon::PolygonPart::Type::Arc;
669 
670  if (!(lineStream >> pPolygonPart->endX))
671  {
672  throw_parse_error(m_path, line, token, lineNumber);
673  }
674 
675  if (!(lineStream >> pPolygonPart->endY))
676  {
677  throw_parse_error(m_path, line, token, lineNumber);
678  }
679 
680  if (!(lineStream >> pPolygonPart->xCenter))
681  {
682  throw_parse_error(m_path, line, token, lineNumber);
683  }
684 
685  if (!(lineStream >> pPolygonPart->yCenter))
686  {
687  throw_parse_error(m_path, line, token, lineNumber);
688  }
689 
690  if (!(lineStream >> token))
691  {
692  throw_parse_error(m_path, line, token, lineNumber);
693  }
694 
695  if (token == "y" || token == "Y")
696  {
697  pPolygonPart->isClockwise = true;
698  }
699  else if (token == "n" || token == "N")
700  {
701  pPolygonPart->isClockwise = false;
702  }
703  else
704  {
705  throw_parse_error(m_path, line, token, lineNumber);
706  }
707 
708  if (pCurrentContourPolygon != nullptr)
709  {
710  pCurrentContourPolygon->m_polygonParts.push_back(pPolygonPart);
711  }
712  else
713  {
714  throw_parse_error(m_path, line, token, lineNumber);
715  }
716  }
717  else if (line.find(ContourPolygon::PolygonPart::SEGMENT_RECORD_TOKEN) == 0)
718  {
719  std::string token;
720  if (!(lineStream >> token))
721  {
722  throw_parse_error(m_path, line, token, lineNumber);
723  }
724 
725  if (token != ContourPolygon::PolygonPart::SEGMENT_RECORD_TOKEN)
726  {
727  throw_parse_error(m_path, line, token, lineNumber);
728  }
729 
730  auto pPolygonPart = std::make_shared<ContourPolygon::PolygonPart>();
731  pPolygonPart->type = ContourPolygon::PolygonPart::Type::Segment;
732 
733  if (!(lineStream >> pPolygonPart->endX))
734  {
735  throw_parse_error(m_path, line, token, lineNumber);
736  }
737 
738  if (!(lineStream >> pPolygonPart->endY))
739  {
740  throw_parse_error(m_path, line, token, lineNumber);
741  }
742 
743  if (pCurrentContourPolygon != nullptr)
744  {
745  pCurrentContourPolygon->m_polygonParts.push_back(pPolygonPart);
746  }
747  else
748  {
749  throw_parse_error(m_path, line, token, lineNumber);
750  }
751  }
752  else
753  {
754  // unrecognized record line
755  parse_info pi(m_path, line, lineNumber);
756  logwarn(pi.toString("unrecognized record line in features file:"));
757  }
758  }
759  }
760 
761  // do we have a current feature record? (finish up the last record in the file- i.e. ran out of file)
762  if (pCurrentFeatureRecord != nullptr)
763  {
764  // finish it up and add it to the list
765  m_featureRecords.push_back(pCurrentFeatureRecord);
766  pCurrentFeatureRecord.reset();
767  }
768 
769  featuresFile.close();
770  }
771  catch (parse_error& pe)
772  {
773  auto m = pe.toString("Parse Error:");
774  logerror(m);
775  featuresFile.close();
776  throw pe;
777  }
778  catch (std::exception& e)
779  {
780  parse_info pi(m_path, line, lineNumber);
781  const auto m = pi.toString();
782  logexception_msg(e, m);
783  featuresFile.close();
784  throw e;
785  }
786 
787  return true;
788  }
789 
790  std::string FeaturesFile::GetUnits() const
791  {
792  return m_units;
793  }
794 
795  std::filesystem::path FeaturesFile::GetPath()
796  {
797  return m_path;
798  }
799 
800  std::filesystem::path FeaturesFile::GetDirectory()
801  {
802  return m_directory;
803  }
804 
805  int FeaturesFile::GetNumFeatures() const
806  {
807  return m_numFeatures;
808  }
809 
810  unsigned int FeaturesFile::GetId() const
811  {
812  return m_id;
813  }
814 
815  const SymbolName::StringMap& FeaturesFile::GetSymbolNamesByName() const
816  {
817  return m_symbolNamesByName;
818  }
819 
820  const FeaturesFile::FeatureRecord::Vector& FeaturesFile::GetFeatureRecords() const
821  {
822  return m_featureRecords;
823  }
824 
825  std::unique_ptr<Odb::Lib::Protobuf::FeaturesFile> FeaturesFile::to_protobuf() const
826  {
827  std::unique_ptr<Odb::Lib::Protobuf::FeaturesFile> pFeaturesFileMessage(new Odb::Lib::Protobuf::FeaturesFile);
828  pFeaturesFileMessage->set_id(m_id);
829  pFeaturesFileMessage->set_numfeatures(m_numFeatures);
830  pFeaturesFileMessage->set_units(m_units);
831  for (const auto& pFeatureRecord : m_featureRecords)
832  {
833  pFeaturesFileMessage->add_featurerecords()->CopyFrom(*pFeatureRecord->to_protobuf());
834  }
835  for (const auto& kvSymbolName : m_symbolNamesByName)
836  {
837  (*pFeaturesFileMessage->mutable_symbolnamesbyname())[kvSymbolName.first] = *kvSymbolName.second->to_protobuf();
838  }
839  return pFeaturesFileMessage;
840  }
841 
842  void FeaturesFile::from_protobuf(const Odb::Lib::Protobuf::FeaturesFile& message)
843  {
844  m_id = message.id();
845  m_numFeatures = message.numfeatures();
846  m_units = message.units();
847  for (const auto& featureRecordMessage : message.featurerecords())
848  {
849  std::shared_ptr<FeatureRecord> pFeatureRecord(new FeatureRecord);
850  pFeatureRecord->from_protobuf(featureRecordMessage);
851  m_featureRecords.push_back(pFeatureRecord);
852  }
853  for (const auto& kvSymbolNameMessage : message.symbolnamesbyname())
854  {
855  auto pSymbolName = std::make_shared<SymbolName>();
856  pSymbolName->from_protobuf(kvSymbolNameMessage.second);
857  m_symbolNamesByName[kvSymbolNameMessage.first] = pSymbolName;
858  }
859  }
860 
861  FeaturesFile::FeatureRecord::~FeatureRecord()
862  {
863  m_contourPolygons.clear();
864  }
865 
866  const ContourPolygon::Vector& FeaturesFile::FeatureRecord::GetContourPolygons() const
867  {
868  return m_contourPolygons;
869  }
870 
871  std::unique_ptr<Odb::Lib::Protobuf::FeaturesFile::FeatureRecord> Odb::Lib::FileModel::Design::FeaturesFile::FeatureRecord::to_protobuf() const
872  {
873  std::unique_ptr<Odb::Lib::Protobuf::FeaturesFile::FeatureRecord> pFeatureRecordMessage(new Odb::Lib::Protobuf::FeaturesFile::FeatureRecord);
874  pFeatureRecordMessage->set_apt_def_resize_factor(apt_def_resize_factor);
875  pFeatureRecordMessage->set_xc(xc);
876  pFeatureRecordMessage->set_yc(yc);
877  pFeatureRecordMessage->set_cw(cw);
878  pFeatureRecordMessage->set_font(font);
879  pFeatureRecordMessage->set_xsize(xsize);
880  pFeatureRecordMessage->set_ysize(ysize);
881  pFeatureRecordMessage->set_width_factor(width_factor);
882  pFeatureRecordMessage->set_text(text);
883  pFeatureRecordMessage->set_version(version);
884  pFeatureRecordMessage->set_sym_num(sym_num);
885  pFeatureRecordMessage->set_polarity(static_cast<Odb::Lib::Protobuf::Polarity>(polarity));
886  pFeatureRecordMessage->set_dcode(dcode);
887  pFeatureRecordMessage->set_id(id);
888  pFeatureRecordMessage->set_orient_def(orient_def);
889  pFeatureRecordMessage->set_orient_def_rotation(orient_def_rotation);
890  pFeatureRecordMessage->set_type(static_cast<Odb::Lib::Protobuf::FeaturesFile::FeatureRecord::Type>(type));
891  pFeatureRecordMessage->set_xs(xs);
892  pFeatureRecordMessage->set_ys(ys);
893  pFeatureRecordMessage->set_xe(xe);
894  pFeatureRecordMessage->set_ye(ye);
895  pFeatureRecordMessage->set_x(x);
896  pFeatureRecordMessage->set_y(y);
897  pFeatureRecordMessage->set_apt_def_symbol_num(apt_def_symbol_num);
898  for (const auto& pContourPolygon : m_contourPolygons)
899  {
900  pFeatureRecordMessage->add_contourpolygons()->CopyFrom(*pContourPolygon->to_protobuf());
901  }
902  for (const auto& kvAttributeAssignment : m_attributeLookupTable)
903  {
904  (*pFeatureRecordMessage->mutable_attributelookuptable())[kvAttributeAssignment.first] = kvAttributeAssignment.second;
905  }
906  return pFeatureRecordMessage;
907  }
908 
909  void Odb::Lib::FileModel::Design::FeaturesFile::FeatureRecord::from_protobuf(const Odb::Lib::Protobuf::FeaturesFile::FeatureRecord& message)
910  {
911  apt_def_resize_factor = message.apt_def_resize_factor();
912  xc = message.xc();
913  yc = message.yc();
914  cw = message.cw();
915  font = message.font();
916  xsize = message.xsize();
917  ysize = message.ysize();
918  width_factor = message.width_factor();
919  text = message.text();
920  version = message.version();
921  sym_num = message.sym_num();
922  polarity = static_cast<Polarity>(message.polarity());
923  dcode = message.dcode();
924  id = message.id();
925  orient_def = message.orient_def();
926  orient_def_rotation = message.orient_def_rotation();
927  type = static_cast<Type>(message.type());
928  xs = message.xs();
929  ys = message.ys();
930  xe = message.xe();
931  ye = message.ye();
932  x = message.x();
933  y = message.y();
934  apt_def_symbol_num = message.apt_def_symbol_num();
935  for (const auto& contourPolygonMessage : message.contourpolygons())
936  {
937  std::shared_ptr<ContourPolygon> pContourPolygon(new ContourPolygon);
938  pContourPolygon->from_protobuf(contourPolygonMessage);
939  m_contourPolygons.push_back(pContourPolygon);
940  }
941  for (const auto& kvAttributeAssignment : message.attributelookuptable())
942  {
943  m_attributeLookupTable[kvAttributeAssignment.first] = kvAttributeAssignment.second;
944  }
945  }
946 }