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