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