OdbDesignLib
OdbDesign ODB++ Parsing Library
 
Loading...
Searching...
No Matches
ComponentsFile.cpp
1#include "ComponentsFile.h"
2#include <fstream>
3#include <sstream>
4#include <filesystem>
5#include "ArchiveExtractor.h"
6#include "../parse_error.h"
7#include <Logger.h>
8#include <exception>
9#include "str_utils.h"
10#include "../invalid_odb_error.h"
11#include <climits>
12#include "ComponentHeightTracer.h"
13
14using namespace std::filesystem;
15
16
17namespace Odb::Lib::FileModel::Design
18{
19 ComponentsFile::ComponentsFile()
20 : m_id((unsigned int)-1)
21 , m_side(BoardSide::BsNone)
22 {
23 }
24
25 ComponentsFile::~ComponentsFile()
26 {
27 m_attributeNames.clear();
28 m_attributeTextValues.clear();
29 m_componentRecords.clear();
30 m_componentRecordsByName.clear();
31 m_bomDescriptionRecordsByCpn.clear();
32 }
33
34 std::string ComponentsFile::GetUnits() const
35 {
36 return m_units;
37 }
38
39 BoardSide ComponentsFile::GetSide() const
40 {
41 return m_side;
42 }
43
44 std::filesystem::path ComponentsFile::GetPath()
45 {
46 return m_path;
47 }
48
49 std::filesystem::path ComponentsFile::GetDirectory()
50 {
51 return m_directory;
52 }
53
54 std::string ComponentsFile::GetLayerName() const
55 {
56 return m_layerName;
57 }
58
59 const ComponentsFile::ComponentRecord::Vector& ComponentsFile::GetComponentRecords() const
60 {
61 return m_componentRecords;
62 }
63
64 const ComponentsFile::ComponentRecord::StringMap& ComponentsFile::GetComponentRecordsByName() const
65 {
66 return m_componentRecordsByName;
67 }
68
69 const std::vector<std::string>& ComponentsFile::GetAttributeNames() const
70 {
71 return m_attributeNames;
72 }
73
74 const std::vector<std::string>& ComponentsFile::GetAttributeTextValues() const
75 {
76 return m_attributeTextValues;
77 }
78
79 const ComponentsFile::BomDescriptionRecord::StringMap& ComponentsFile::GetBomDescriptionRecordsByCpn() const
80 {
81 return m_bomDescriptionRecordsByCpn;
82 }
83
84 std::unique_ptr<Odb::Lib::Protobuf::ComponentsFile> ComponentsFile::to_protobuf() const
85 {
86 std::unique_ptr<Odb::Lib::Protobuf::ComponentsFile> pComponentsFileMessage(new Odb::Lib::Protobuf::ComponentsFile);
87 pComponentsFileMessage->set_units(m_units);
88 pComponentsFileMessage->set_id(m_id);
89 pComponentsFileMessage->set_side(static_cast<Odb::Lib::Protobuf::BoardSide>(m_side));
90 pComponentsFileMessage->set_layername(m_layerName);
91 pComponentsFileMessage->set_path(m_path.string());
92 pComponentsFileMessage->set_directory(m_directory.string());
93
94 for (const auto& attributeName : m_attributeNames)
95 {
96 pComponentsFileMessage->add_attributenames(attributeName);
97 }
98
99 for (const auto& attributeTextValue : m_attributeTextValues)
100 {
101 pComponentsFileMessage->add_attributetextvalues(attributeTextValue);
102 }
103
104 for (const auto& pComponentRecord : m_componentRecords)
105 {
106 // Log component height serialization
107 ComponentHeightTracer::instance().logSerialization(
108 pComponentRecord->compName,
109 pComponentRecord->pkgRef,
110 pComponentRecord->GetAttributeLookupTable(),
111 m_attributeNames);
112
113 auto pComponentRecordMessage = pComponentRecord->to_protobuf();
114 pComponentsFileMessage->add_componentrecords()->CopyFrom(*pComponentRecordMessage);
115 }
116
117 for (const auto& kvBomDescriptionRecord : m_bomDescriptionRecordsByCpn)
118 {
119 auto pBomDescriptionRecordMessage = kvBomDescriptionRecord.second->to_protobuf();
120 (*pComponentsFileMessage->mutable_bomdescriptionrecordsbycpn())[kvBomDescriptionRecord.first] = *pBomDescriptionRecordMessage;
121 }
122
123 return pComponentsFileMessage;
124 }
125
126 void ComponentsFile::from_protobuf(const Odb::Lib::Protobuf::ComponentsFile& message)
127 {
128 m_units = message.units();
129 m_id = message.id();
130 m_side = static_cast<BoardSide>(message.side());
131 m_layerName = message.layername();
132 m_path = message.path();
133 m_directory = message.directory();
134
135 for (const auto& attributeName : message.attributenames())
136 {
137 m_attributeNames.push_back(attributeName);
138 }
139
140 for (const auto& attributeTextValue : message.attributetextvalues())
141 {
142 m_attributeTextValues.push_back(attributeTextValue);
143 }
144
145 for (const auto& componentRecordMessage : message.componentrecords())
146 {
147 auto pComponentRecord = std::make_shared<ComponentRecord>();
148 pComponentRecord->from_protobuf(componentRecordMessage);
149 m_componentRecords.push_back(pComponentRecord);
150 }
151
152 for (const auto& kvBomDescriptionRecord : message.bomdescriptionrecordsbycpn())
153 {
154 auto pBomDescriptionRecord = std::make_shared<BomDescriptionRecord>();
155 pBomDescriptionRecord->from_protobuf(kvBomDescriptionRecord.second);
156 m_bomDescriptionRecordsByCpn[kvBomDescriptionRecord.first] = pBomDescriptionRecord;
157 }
158 }
159
160 bool ComponentsFile::Save(std::ostream& os)
161 {
162 return true;
163 }
164
165 std::unique_ptr<Odb::Lib::Protobuf::ComponentsFile::BomDescriptionRecord> ComponentsFile::BomDescriptionRecord::to_protobuf() const
166 {
167 std::unique_ptr<Odb::Lib::Protobuf::ComponentsFile::BomDescriptionRecord> pBomDescriptionRecordMessage(new Odb::Lib::Protobuf::ComponentsFile::BomDescriptionRecord);
168 pBomDescriptionRecordMessage->set_cpn(cpn);
169 pBomDescriptionRecordMessage->set_pkg(pkg);
170 pBomDescriptionRecordMessage->set_ipn(ipn);
171 for (const auto& description : descriptions)
172 {
173 pBomDescriptionRecordMessage->add_descriptions()->assign(description);
174 }
175 pBomDescriptionRecordMessage->set_vpl_vnd(vpl_vnd);
176 pBomDescriptionRecordMessage->set_vpl_mpn(vpl_mpn);
177 pBomDescriptionRecordMessage->set_vnd(vnd);
178 pBomDescriptionRecordMessage->set_mpn(mpn);
179 return pBomDescriptionRecordMessage;
180 }
181
182 void ComponentsFile::BomDescriptionRecord::from_protobuf(const Odb::Lib::Protobuf::ComponentsFile::BomDescriptionRecord& message)
183 {
184 cpn = message.cpn();
185 pkg = message.pkg();
186 ipn = message.ipn();
187 for (const auto& description : message.descriptions())
188 {
189 descriptions.push_back(description);
190 }
191 vpl_vnd = message.vpl_vnd();
192 vpl_mpn = message.vpl_mpn();
193 vnd = message.vnd();
194 mpn = message.mpn();
195 }
196
197 ComponentsFile::ComponentRecord::~ComponentRecord()
198 {
199 m_toeprintRecords.clear();
200 m_propertyRecords.clear();
201 }
202
203 std::unique_ptr<Odb::Lib::Protobuf::ComponentsFile::ComponentRecord> ComponentsFile::ComponentRecord::to_protobuf() const
204 {
205 std::unique_ptr<Odb::Lib::Protobuf::ComponentsFile::ComponentRecord> pComponentRecordMessage(new Odb::Lib::Protobuf::ComponentsFile::ComponentRecord);
206 pComponentRecordMessage->set_pkgref(pkgRef);
207 pComponentRecordMessage->set_locationx(locationX);
208 pComponentRecordMessage->set_locationy(locationY);
209 pComponentRecordMessage->set_rotation(rotation);
210 pComponentRecordMessage->set_mirror(mirror);
211 pComponentRecordMessage->set_compname(compName);
212 pComponentRecordMessage->set_partname(partName);
213 //pComponentRecordMessage->set_attributes(attributes);
214 pComponentRecordMessage->set_index(index);
215
216 for (const auto& pPropertyRecord : m_propertyRecords)
217 {
218 auto pPropertyRecordMessage = pPropertyRecord->to_protobuf();
219 pComponentRecordMessage->add_propertyrecords()->CopyFrom(*pPropertyRecordMessage);
220 }
221
222 for (const auto& pToeprintRecord : m_toeprintRecords)
223 {
224 auto pToeprintRecordMessage = pToeprintRecord->to_protobuf();
225 pComponentRecordMessage->add_toeprintrecords()->CopyFrom(*pToeprintRecordMessage);
226 }
227
228 for (const auto& kvAttributeAssignment : m_attributeLookupTable)
229 {
230 (*pComponentRecordMessage->mutable_attributelookuptable())[kvAttributeAssignment.first] = kvAttributeAssignment.second;
231 }
232
233 return pComponentRecordMessage;
234 }
235
236 void ComponentsFile::ComponentRecord::from_protobuf(const Odb::Lib::Protobuf::ComponentsFile::ComponentRecord& message)
237 {
238 pkgRef = message.pkgref();
239 locationX = message.locationx();
240 locationY = message.locationy();
241 rotation = message.rotation();
242 mirror = message.mirror();
243 compName = message.compname();
244 partName = message.partname();
245 //attributes = message.attributes();
246 index = message.index();
247
248 for (const auto& propertyRecordMessage : message.propertyrecords())
249 {
250 auto pPropertyRecord = std::make_shared<PropertyRecord>();
251 pPropertyRecord->from_protobuf(propertyRecordMessage);
252 m_propertyRecords.push_back(pPropertyRecord);
253 }
254
255 for (const auto& toeprintRecordMessage : message.toeprintrecords())
256 {
257 auto pToeprintRecord = std::make_shared<ToeprintRecord>();
258 pToeprintRecord->from_protobuf(toeprintRecordMessage);
259 m_toeprintRecords.push_back(pToeprintRecord);
260 }
261
262 for (const auto& kvAttributeAssignment : message.attributelookuptable())
263 {
264 m_attributeLookupTable[kvAttributeAssignment.first] = kvAttributeAssignment.second;
265 }
266 }
267
268 std::unique_ptr<Odb::Lib::Protobuf::ComponentsFile::ComponentRecord::ToeprintRecord> ComponentsFile::ComponentRecord::ToeprintRecord::to_protobuf() const
269 {
270 std::unique_ptr<Odb::Lib::Protobuf::ComponentsFile::ComponentRecord::ToeprintRecord> pToeprintRecordMessage(new Odb::Lib::Protobuf::ComponentsFile::ComponentRecord::ToeprintRecord);
271 pToeprintRecordMessage->set_pinnumber(pinNumber);
272 pToeprintRecordMessage->set_locationx(locationX);
273 pToeprintRecordMessage->set_locationy(locationY);
274 pToeprintRecordMessage->set_rotation(rotation);
275 pToeprintRecordMessage->set_mirror(mirror);
276 pToeprintRecordMessage->set_netnumber(netNumber);
277 pToeprintRecordMessage->set_subnetnumber(subnetNumber);
278 pToeprintRecordMessage->set_name(name);
279 return pToeprintRecordMessage;
280 }
281
282 void ComponentsFile::ComponentRecord::ToeprintRecord::from_protobuf(const Odb::Lib::Protobuf::ComponentsFile::ComponentRecord::ToeprintRecord& message)
283 {
284 pinNumber = message.pinnumber();
285 locationX = message.locationx();
286 locationY = message.locationy();
287 rotation = message.rotation();
288 mirror = message.mirror();
289 netNumber = message.netnumber();
290 subnetNumber = message.subnetnumber();
291 name = message.name();
292 }
293
294 bool ComponentsFile::Parse(std::filesystem::path directory)
295 {
296 std::ifstream componentsFile;
297 int lineNumber = 0;
298 std::string line;
299
300 try
301 {
302 m_directory = directory;
303
304 m_layerName = m_directory.filename().string();
305 if (m_layerName == TOP_COMPONENTS_LAYER_NAME ||
306 m_layerName == BOTTOM_COMPONENTS_LAYER_NAME)
307 {
308 m_side = m_layerName == TOP_COMPONENTS_LAYER_NAME ?
309 BoardSide::Top :
310 BoardSide::Bottom;
311 }
312 else
313 {
314 // not a components layer
315 return true;
316 }
317
318 loginfo("checking for extraction...");
319
320 std::filesystem::path componentsFilePath;
321 for (const std::string componentsFilename : COMPONENTS_FILENAMES)
322 {
323 loginfo("trying components file: [" + componentsFilename + "]...");
324
325 componentsFilePath = Utils::ArchiveExtractor::getUncompressedFilePath(m_directory, componentsFilename);
326 if (exists(componentsFilePath) && is_regular_file(componentsFilePath))
327 {
328 loginfo("found components file: [" + componentsFilePath.string() + "]");
329 break;
330 }
331 }
332
333 m_path = componentsFilePath;
334
335 loginfo("any extraction complete, parsing data...");
336
337 if (!std::filesystem::exists(m_path))
338 {
339 auto message = "components file does not exist: [" + m_path.string() + "]";
340 throw invalid_odb_error(message.c_str());
341 }
342 else if (!std::filesystem::is_regular_file(m_path))
343 {
344 auto message = "components is not a file: [" + m_path.string() + "]";
345 throw invalid_odb_error(message.c_str());
346 }
347
348 componentsFile.open(m_path.string(), std::ios::in);
349 if (!componentsFile.is_open())
350 {
351 auto message = "unable to open components file: [" + m_path.string() + "]";
352 throw invalid_odb_error(message.c_str());
353 }
354
355 std::shared_ptr<ComponentRecord> pCurrentComponentRecord;
356 std::shared_ptr<BomDescriptionRecord> pCurrentBomDescriptionRecord;
357
358 while (std::getline(componentsFile, line))
359 {
360 lineNumber++;
361
362 // trim whitespace from beginning and end of line
363 Utils::str_trim(line);
364 if (!line.empty())
365 {
366 std::stringstream lineStream(line);
367 //char firstChar = line[0];
368
369 if (line.find(COMMENT_TOKEN) == 0)
370 {
371 // comment line
372 }
373 else if (line.find(UNITS_TOKEN) == 0)
374 {
375 // units line
376 std::string token;
377 if (!std::getline(lineStream, token, '='))
378 {
379 throw_parse_error(m_path, line, token, lineNumber);
380 }
381 else if (!std::getline(lineStream, token, '='))
382 {
383 throw_parse_error(m_path, line, token, lineNumber);
384 }
385
386 m_units = token;
387 }
388 else if (line.find(ID_TOKEN) == 0)
389 {
390 std::string token;
391 if (!std::getline(lineStream, token, '='))
392 {
393 throw_parse_error(m_path, line, token, lineNumber);
394 }
395 else if (!std::getline(lineStream, token, '='))
396 {
397 throw_parse_error(m_path, line, token, lineNumber);
398 }
399 m_id = std::stoul(token);
400 }
401 else if (line.find(ATTRIBUTE_NAME_TOKEN) == 0)
402 {
403 // component attribute name line
404 std::string token;
405 // TODO: continue on failing line parse, to make a less strict/more robust parser (make a flag: enum ParseStrictness { strict, lax })
406 if (!std::getline(lineStream, token, ' '))
407 {
408 throw_parse_error(m_path, line, token, lineNumber);
409 }
410 else if (!std::getline(lineStream, token, ' '))
411 {
412 throw_parse_error(m_path, line, token, lineNumber);
413 }
414 m_attributeNames.push_back(token);
415 }
416 else if (line.find(ATTRIBUTE_VALUE_TOKEN) == 0)
417 {
418 // component attribute text string values
419 std::string token;
420 if (!std::getline(lineStream, token, ' '))
421 {
422 throw_parse_error(m_path, line, token, lineNumber);
423 }
424 else if (!std::getline(lineStream, token, ' '))
425 {
426 throw_parse_error(m_path, line, token, lineNumber);
427 }
428 m_attributeTextValues.push_back(token);
429 }
430 else if (line.find(ComponentRecord::RECORD_TOKEN) == 0)
431 {
432 // component record line
433 std::string token;
434
435 lineStream >> token;
436 if (token != ComponentRecord::RECORD_TOKEN)
437 {
438 throw_parse_error(m_path, line, token, lineNumber);
439 }
440
441 if (pCurrentBomDescriptionRecord != nullptr)
442 {
443 // BomDescriptionRecord end (i.e. MPN) line
444 m_bomDescriptionRecordsByCpn[pCurrentBomDescriptionRecord->cpn] = pCurrentBomDescriptionRecord;
445 pCurrentBomDescriptionRecord.reset();
446 }
447
448 // do we have a current component record?
449 if (pCurrentComponentRecord != nullptr)
450 {
451 // finish it up and add it to the list
452 m_componentRecords.push_back(pCurrentComponentRecord);
453 pCurrentComponentRecord.reset();
454 }
455
456 // create a new current component record
457 pCurrentComponentRecord = std::make_shared<ComponentRecord>();
458
459 lineStream >> pCurrentComponentRecord->pkgRef;
460 lineStream >> pCurrentComponentRecord->locationX;
461 lineStream >> pCurrentComponentRecord->locationY;
462 lineStream >> pCurrentComponentRecord->rotation;
463
464 char mirror;
465 lineStream >> mirror;
466 pCurrentComponentRecord->mirror = (mirror == 'M');
467
468 lineStream >> pCurrentComponentRecord->compName;
469 lineStream >> pCurrentComponentRecord->partName;
470 //lineStream >> pCurrentComponentRecord->attributes;
471
472 if (m_componentRecords.size() > UINT_MAX)
473 {
474 throw_parse_error(m_path, line, token, lineNumber);
475 }
476
477 pCurrentComponentRecord->index = static_cast<unsigned int>(m_componentRecords.size());
478
479 std::string attrIdString;
480 lineStream >> attrIdString;
481
482 // Log component height parsing start
483 ComponentHeightTracer::instance().logParseStart(
484 pCurrentComponentRecord->compName,
485 pCurrentComponentRecord->pkgRef,
486 attrIdString);
487
488 if (!pCurrentComponentRecord->ParseAttributeLookupTable(attrIdString))
489 {
490 throw_parse_error(m_path, line, token, lineNumber);
491 }
492
493 // Log component height parsing result
494 ComponentHeightTracer::instance().logParseResult(
495 pCurrentComponentRecord->compName,
496 pCurrentComponentRecord->pkgRef,
497 pCurrentComponentRecord->GetAttributeLookupTable(),
498 m_attributeNames);
499 }
500 else if (line.find(PropertyRecord::RECORD_TOKEN) == 0)
501 {
502 // component property record line
503 std::string token;
504 if (!(lineStream >> token))
505 {
506 throw_parse_error(m_path, line, token, lineNumber);
507 }
508
509 if (token != PropertyRecord::RECORD_TOKEN)
510 {
511 throw_parse_error(m_path, line, token, lineNumber);
512 }
513
514 auto pPropertyRecord = std::make_shared<PropertyRecord>();
515
516 if (!(lineStream >> pPropertyRecord->name))
517 {
518 throw_parse_error(m_path, line, token, lineNumber);
519 }
520
521 if (!(lineStream >> token))
522 {
523 throw_parse_error(m_path, line, token, lineNumber);
524 }
525
526 if (!token.empty())
527 {
528 // handle case where the beginning of the value, after the opening single-quote, is whitespace...
529 if (token == "'")
530 {
531 // eat the single-quote and get the next token, i.e. the actual value (w/ space in front)
532 if (!(lineStream >> token))
533 {
534 throw_parse_error(m_path, line, token, lineNumber);
535 }
536 }
537
538 if (token.size() > 0 && token[0] == '\'')
539 {
540 // remove leading quote
541 token.erase(0, 1);
542 }
543
544 if (token.size() > 0 && token[token.size() - 1] == '\'')
545 {
546 // remove trailing quote
547 token.erase(token.size() - 1);
548 }
549
550 Utils::str_trim(token);
551 }
552
553 pPropertyRecord->value = token;
554
555 double f;
556 while (lineStream >> f)
557 {
558 pPropertyRecord->floatValues.push_back(f);
559 }
560
561 pCurrentComponentRecord->m_propertyRecords.push_back(pPropertyRecord);
562 }
563 else if (line.find(ComponentRecord::ToeprintRecord::RECORD_TOKEN) == 0)
564 {
565 // component toeprint record line
566 std::string token;
567 lineStream >> token;
568 if (token != ComponentRecord::ToeprintRecord::RECORD_TOKEN)
569 {
570 throw_parse_error(m_path, line, token, lineNumber);
571 }
572
573 auto pToeprintRecord = std::make_shared<ComponentRecord::ToeprintRecord>();
574 lineStream >> pToeprintRecord->pinNumber;
575 lineStream >> pToeprintRecord->locationX;
576 lineStream >> pToeprintRecord->locationY;
577 lineStream >> pToeprintRecord->rotation;
578
579 char mirror;
580 lineStream >> mirror;
581 pToeprintRecord->mirror = (mirror == 'M' || mirror == 'm');
582
583 lineStream >> pToeprintRecord->netNumber;
584 if (pToeprintRecord->netNumber == (unsigned int)-1)
585 {
586 // netNumber == -1
587 parse_info pi(m_path, line, lineNumber);
588 logdebug(pi.toString("Component Toeprint record with netNumber = -1"));
589
590 if (!m_allowToepintNetNumbersOfNegative1)
591 {
592 throw_parse_error(m_path, line, token, lineNumber);
593 }
594 }
595
596 lineStream >> pToeprintRecord->subnetNumber;
597 if (pToeprintRecord->subnetNumber == (unsigned int)-1)
598 {
599 // subnetNumber == -1
600 parse_info pi(m_path, line, lineNumber);
601 logdebug(pi.toString("Component Toeprint record with subnetNumber = -1"));
602
603 if (!m_allowToepintNetNumbersOfNegative1)
604 {
605 throw_parse_error(m_path, line, token, lineNumber);
606 }
607 }
608
609 lineStream >> pToeprintRecord->name;
610
611 pCurrentComponentRecord->m_toeprintRecords.push_back(pToeprintRecord);
612 }
613 else if (line.find(ComponentsFile::BomDescriptionRecord::CPN_RECORD_TOKEN) == 0)
614 {
615 // BomDescriptionRecord start (i.e. CPN) line
616
617 std::string token;
618 lineStream >> token;
619 if (token != ComponentsFile::BomDescriptionRecord::CPN_RECORD_TOKEN)
620 {
621 throw_parse_error(m_path, line, token, lineNumber);
622 }
623
624 if (pCurrentBomDescriptionRecord != nullptr)
625 {
626 m_bomDescriptionRecordsByCpn[pCurrentBomDescriptionRecord->cpn] = pCurrentBomDescriptionRecord;
627 pCurrentBomDescriptionRecord.reset();
628 }
629
630 pCurrentBomDescriptionRecord = std::make_shared<ComponentsFile::BomDescriptionRecord>();
631 }
632 else if (line.find(ComponentsFile::BomDescriptionRecord::IPN_RECORD_TOKEN) == 0)
633 {
634 std::string token;
635 lineStream >> token;
636 if (token != ComponentsFile::BomDescriptionRecord::IPN_RECORD_TOKEN)
637 {
638 throw_parse_error(m_path, line, token, lineNumber);
639 }
640
641 if (pCurrentBomDescriptionRecord == nullptr)
642 {
643 throw_parse_error(m_path, line, token, lineNumber);
644 }
645
646 if (!(lineStream >> pCurrentBomDescriptionRecord->ipn))
647 {
648 // blank/ no IPN value allowed
649 //throw_parse_error(m_path, line, token, lineNumber);
650 }
651 }
652 else if (line.find(ComponentsFile::BomDescriptionRecord::DSC_RECORD_TOKEN) == 0)
653 {
654 std::string token;
655 lineStream >> token;
656 if (token != ComponentsFile::BomDescriptionRecord::DSC_RECORD_TOKEN)
657 {
658 throw_parse_error(m_path, line, token, lineNumber);
659 }
660
661 if (pCurrentBomDescriptionRecord == nullptr)
662 {
663 throw_parse_error(m_path, line, token, lineNumber);
664 }
665
666 std::string description;
667
668 if (!(lineStream >> description))
669 {
670 // allow blank/no description value
671 //throw_parse_error(m_path, line, token, lineNumber);
672 }
673
674 pCurrentBomDescriptionRecord->descriptions.push_back(description);
675 }
676 else if (line.find(ComponentsFile::BomDescriptionRecord::VPL_VND_RECORD_TOKEN) == 0)
677 {
678 std::string token;
679 lineStream >> token;
680 if (token != ComponentsFile::BomDescriptionRecord::VPL_VND_RECORD_TOKEN)
681 {
682 throw_parse_error(m_path, line, token, lineNumber);
683 }
684
685 if (pCurrentBomDescriptionRecord == nullptr)
686 {
687 throw_parse_error(m_path, line, token, lineNumber);
688 }
689
690 if (!(lineStream >> pCurrentBomDescriptionRecord->vpl_vnd))
691 {
692 throw_parse_error(m_path, line, token, lineNumber);
693 }
694 }
695 else if (line.find(ComponentsFile::BomDescriptionRecord::VPL_MPN_RECORD_TOKEN) == 0)
696 {
697 std::string token;
698 lineStream >> token;
699 if (token != ComponentsFile::BomDescriptionRecord::VPL_MPN_RECORD_TOKEN)
700 {
701 throw_parse_error(m_path, line, token, lineNumber);
702 }
703
704 if (pCurrentBomDescriptionRecord == nullptr)
705 {
706 throw_parse_error(m_path, line, token, lineNumber);
707 }
708
709 if (!(lineStream >> pCurrentBomDescriptionRecord->vpl_mpn))
710 {
711 throw_parse_error(m_path, line, token, lineNumber);
712 }
713 }
714 else if (line.find(ComponentsFile::BomDescriptionRecord::VND_RECORD_TOKEN) == 0)
715 {
716 std::string token;
717 lineStream >> token;
718 if (token != ComponentsFile::BomDescriptionRecord::VND_RECORD_TOKEN)
719 {
720 throw_parse_error(m_path, line, token, lineNumber);
721 }
722
723 if (pCurrentBomDescriptionRecord == nullptr)
724 {
725 throw_parse_error(m_path, line, token, lineNumber);
726 }
727
728 if (!(lineStream >> pCurrentBomDescriptionRecord->vnd))
729 {
730 throw_parse_error(m_path, line, token, lineNumber);
731 }
732 }
733 else if (line.find(ComponentsFile::BomDescriptionRecord::MPN_RECORD_TOKEN) == 0)
734 {
735 std::string token;
736 lineStream >> token;
737 if (token != ComponentsFile::BomDescriptionRecord::MPN_RECORD_TOKEN)
738 {
739 throw_parse_error(m_path, line, token, lineNumber);
740 }
741
742 if (pCurrentBomDescriptionRecord == nullptr)
743 {
744 throw_parse_error(m_path, line, token, lineNumber);
745 }
746
747 if (!(lineStream >> pCurrentBomDescriptionRecord->mpn))
748 {
749 throw_parse_error(m_path, line, token, lineNumber);
750 }
751
752 // BomDescriptionRecord end (i.e. MPN) line
753 //m_bomDescriptionRecordsByCpn[pCurrentBomDescriptionRecord->cpn] = pCurrentBomDescriptionRecord;
754 //pCurrentBomDescriptionRecord.reset();
755 }
756 }
757 }
758
759 if (pCurrentBomDescriptionRecord != nullptr)
760 {
761 // BomDescriptionRecord end (i.e. MPN) line
762 m_bomDescriptionRecordsByCpn[pCurrentBomDescriptionRecord->cpn] = pCurrentBomDescriptionRecord;
763 pCurrentBomDescriptionRecord.reset();
764 }
765
766 // do we have a current component record? (finish up the last record in the file- i.e. ran out of file)
767 if (pCurrentComponentRecord != nullptr)
768 {
769 // finish it up and add it to the list
770 m_componentRecords.push_back(pCurrentComponentRecord);
771 pCurrentComponentRecord.reset();
772 }
773
774 componentsFile.close();
775 }
776 catch (parse_error& pe)
777 {
778 auto m = pe.toString("Parse Error:");
779 logerror(m);
780 componentsFile.close();
781 throw pe;
782 }
783 catch (std::exception& e)
784 {
785 parse_info pi(m_path, line, lineNumber);
786 const auto m = pi.toString();
787 logexception_msg(e, m);
788 componentsFile.close();
789 throw e;
790 }
791
792 return true;
793 }
794}