1#include "ComponentsFile.h"
5#include "ArchiveExtractor.h"
6#include "../parse_error.h"
10#include "../invalid_odb_error.h"
12#include "ComponentHeightTracer.h"
14using namespace std::filesystem;
17namespace Odb::Lib::FileModel::Design
19 ComponentsFile::ComponentsFile()
20 : m_id((unsigned int)-1)
21 , m_side(BoardSide::BsNone)
25 ComponentsFile::~ComponentsFile()
27 m_attributeNames.clear();
28 m_attributeTextValues.clear();
29 m_componentRecords.clear();
30 m_componentRecordsByName.clear();
31 m_bomDescriptionRecordsByCpn.clear();
34 std::string ComponentsFile::GetUnits()
const
39 BoardSide ComponentsFile::GetSide()
const
44 std::filesystem::path ComponentsFile::GetPath()
49 std::filesystem::path ComponentsFile::GetDirectory()
54 std::string ComponentsFile::GetLayerName()
const
59 const ComponentsFile::ComponentRecord::Vector& ComponentsFile::GetComponentRecords()
const
61 return m_componentRecords;
64 const ComponentsFile::ComponentRecord::StringMap& ComponentsFile::GetComponentRecordsByName()
const
66 return m_componentRecordsByName;
69 const std::vector<std::string>& ComponentsFile::GetAttributeNames()
const
71 return m_attributeNames;
74 const std::vector<std::string>& ComponentsFile::GetAttributeTextValues()
const
76 return m_attributeTextValues;
79 const ComponentsFile::BomDescriptionRecord::StringMap& ComponentsFile::GetBomDescriptionRecordsByCpn()
const
81 return m_bomDescriptionRecordsByCpn;
84 std::unique_ptr<Odb::Lib::Protobuf::ComponentsFile> ComponentsFile::to_protobuf()
const
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());
94 for (
const auto& attributeName : m_attributeNames)
96 pComponentsFileMessage->add_attributenames(attributeName);
99 for (
const auto& attributeTextValue : m_attributeTextValues)
101 pComponentsFileMessage->add_attributetextvalues(attributeTextValue);
104 for (
const auto& pComponentRecord : m_componentRecords)
107 ComponentHeightTracer::instance().logSerialization(
108 pComponentRecord->compName,
109 pComponentRecord->pkgRef,
110 pComponentRecord->GetAttributeLookupTable(),
113 auto pComponentRecordMessage = pComponentRecord->to_protobuf();
114 pComponentsFileMessage->add_componentrecords()->CopyFrom(*pComponentRecordMessage);
117 for (
const auto& kvBomDescriptionRecord : m_bomDescriptionRecordsByCpn)
119 auto pBomDescriptionRecordMessage = kvBomDescriptionRecord.second->to_protobuf();
120 (*pComponentsFileMessage->mutable_bomdescriptionrecordsbycpn())[kvBomDescriptionRecord.first] = *pBomDescriptionRecordMessage;
123 return pComponentsFileMessage;
126 void ComponentsFile::from_protobuf(
const Odb::Lib::Protobuf::ComponentsFile& message)
128 m_units = message.units();
130 m_side =
static_cast<BoardSide
>(message.side());
131 m_layerName = message.layername();
132 m_path = message.path();
133 m_directory = message.directory();
135 for (
const auto& attributeName : message.attributenames())
137 m_attributeNames.push_back(attributeName);
140 for (
const auto& attributeTextValue : message.attributetextvalues())
142 m_attributeTextValues.push_back(attributeTextValue);
145 for (
const auto& componentRecordMessage : message.componentrecords())
147 auto pComponentRecord = std::make_shared<ComponentRecord>();
148 pComponentRecord->from_protobuf(componentRecordMessage);
149 m_componentRecords.push_back(pComponentRecord);
152 for (
const auto& kvBomDescriptionRecord : message.bomdescriptionrecordsbycpn())
154 auto pBomDescriptionRecord = std::make_shared<BomDescriptionRecord>();
155 pBomDescriptionRecord->from_protobuf(kvBomDescriptionRecord.second);
156 m_bomDescriptionRecordsByCpn[kvBomDescriptionRecord.first] = pBomDescriptionRecord;
160 bool ComponentsFile::Save(std::ostream& os)
165 std::unique_ptr<Odb::Lib::Protobuf::ComponentsFile::BomDescriptionRecord> ComponentsFile::BomDescriptionRecord::to_protobuf()
const
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)
173 pBomDescriptionRecordMessage->add_descriptions()->assign(description);
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;
182 void ComponentsFile::BomDescriptionRecord::from_protobuf(
const Odb::Lib::Protobuf::ComponentsFile::BomDescriptionRecord& message)
187 for (
const auto& description : message.descriptions())
189 descriptions.push_back(description);
191 vpl_vnd = message.vpl_vnd();
192 vpl_mpn = message.vpl_mpn();
197 ComponentsFile::ComponentRecord::~ComponentRecord()
199 m_toeprintRecords.clear();
200 m_propertyRecords.clear();
203 std::unique_ptr<Odb::Lib::Protobuf::ComponentsFile::ComponentRecord> ComponentsFile::ComponentRecord::to_protobuf()
const
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);
214 pComponentRecordMessage->set_index(index);
216 for (
const auto& pPropertyRecord : m_propertyRecords)
218 auto pPropertyRecordMessage = pPropertyRecord->to_protobuf();
219 pComponentRecordMessage->add_propertyrecords()->CopyFrom(*pPropertyRecordMessage);
222 for (
const auto& pToeprintRecord : m_toeprintRecords)
224 auto pToeprintRecordMessage = pToeprintRecord->to_protobuf();
225 pComponentRecordMessage->add_toeprintrecords()->CopyFrom(*pToeprintRecordMessage);
228 for (
const auto& kvAttributeAssignment : m_attributeLookupTable)
230 (*pComponentRecordMessage->mutable_attributelookuptable())[kvAttributeAssignment.first] = kvAttributeAssignment.second;
233 return pComponentRecordMessage;
236 void ComponentsFile::ComponentRecord::from_protobuf(
const Odb::Lib::Protobuf::ComponentsFile::ComponentRecord& message)
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();
246 index = message.index();
248 for (
const auto& propertyRecordMessage : message.propertyrecords())
250 auto pPropertyRecord = std::make_shared<PropertyRecord>();
251 pPropertyRecord->from_protobuf(propertyRecordMessage);
252 m_propertyRecords.push_back(pPropertyRecord);
255 for (
const auto& toeprintRecordMessage : message.toeprintrecords())
257 auto pToeprintRecord = std::make_shared<ToeprintRecord>();
258 pToeprintRecord->from_protobuf(toeprintRecordMessage);
259 m_toeprintRecords.push_back(pToeprintRecord);
262 for (
const auto& kvAttributeAssignment : message.attributelookuptable())
264 m_attributeLookupTable[kvAttributeAssignment.first] = kvAttributeAssignment.second;
268 std::unique_ptr<Odb::Lib::Protobuf::ComponentsFile::ComponentRecord::ToeprintRecord> ComponentsFile::ComponentRecord::ToeprintRecord::to_protobuf()
const
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;
282 void ComponentsFile::ComponentRecord::ToeprintRecord::from_protobuf(
const Odb::Lib::Protobuf::ComponentsFile::ComponentRecord::ToeprintRecord& message)
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();
294 bool ComponentsFile::Parse(std::filesystem::path directory)
296 std::ifstream componentsFile;
302 m_directory = directory;
304 m_layerName = m_directory.filename().string();
305 if (m_layerName == TOP_COMPONENTS_LAYER_NAME ||
306 m_layerName == BOTTOM_COMPONENTS_LAYER_NAME)
308 m_side = m_layerName == TOP_COMPONENTS_LAYER_NAME ?
318 loginfo(
"checking for extraction...");
320 std::filesystem::path componentsFilePath;
321 for (
const std::string componentsFilename : COMPONENTS_FILENAMES)
323 loginfo(
"trying components file: [" + componentsFilename +
"]...");
325 componentsFilePath = Utils::ArchiveExtractor::getUncompressedFilePath(m_directory, componentsFilename);
326 if (exists(componentsFilePath) && is_regular_file(componentsFilePath))
328 loginfo(
"found components file: [" + componentsFilePath.string() +
"]");
333 m_path = componentsFilePath;
335 loginfo(
"any extraction complete, parsing data...");
337 if (!std::filesystem::exists(m_path))
339 auto message =
"components file does not exist: [" + m_path.string() +
"]";
340 throw invalid_odb_error(message.c_str());
342 else if (!std::filesystem::is_regular_file(m_path))
344 auto message =
"components is not a file: [" + m_path.string() +
"]";
345 throw invalid_odb_error(message.c_str());
348 componentsFile.open(m_path.string(), std::ios::in);
349 if (!componentsFile.is_open())
351 auto message =
"unable to open components file: [" + m_path.string() +
"]";
352 throw invalid_odb_error(message.c_str());
355 std::shared_ptr<ComponentRecord> pCurrentComponentRecord;
356 std::shared_ptr<BomDescriptionRecord> pCurrentBomDescriptionRecord;
358 while (std::getline(componentsFile, line))
363 Utils::str_trim(line);
366 std::stringstream lineStream(line);
369 if (line.find(COMMENT_TOKEN) == 0)
373 else if (line.find(UNITS_TOKEN) == 0)
377 if (!std::getline(lineStream, token,
'='))
379 throw_parse_error(m_path, line, token, lineNumber);
381 else if (!std::getline(lineStream, token,
'='))
383 throw_parse_error(m_path, line, token, lineNumber);
388 else if (line.find(ID_TOKEN) == 0)
391 if (!std::getline(lineStream, token,
'='))
393 throw_parse_error(m_path, line, token, lineNumber);
395 else if (!std::getline(lineStream, token,
'='))
397 throw_parse_error(m_path, line, token, lineNumber);
399 m_id = std::stoul(token);
401 else if (line.find(ATTRIBUTE_NAME_TOKEN) == 0)
406 if (!std::getline(lineStream, token,
' '))
408 throw_parse_error(m_path, line, token, lineNumber);
410 else if (!std::getline(lineStream, token,
' '))
412 throw_parse_error(m_path, line, token, lineNumber);
414 m_attributeNames.push_back(token);
416 else if (line.find(ATTRIBUTE_VALUE_TOKEN) == 0)
420 if (!std::getline(lineStream, token,
' '))
422 throw_parse_error(m_path, line, token, lineNumber);
424 else if (!std::getline(lineStream, token,
' '))
426 throw_parse_error(m_path, line, token, lineNumber);
428 m_attributeTextValues.push_back(token);
430 else if (line.find(ComponentRecord::RECORD_TOKEN) == 0)
436 if (token != ComponentRecord::RECORD_TOKEN)
438 throw_parse_error(m_path, line, token, lineNumber);
441 if (pCurrentBomDescriptionRecord !=
nullptr)
444 m_bomDescriptionRecordsByCpn[pCurrentBomDescriptionRecord->cpn] = pCurrentBomDescriptionRecord;
445 pCurrentBomDescriptionRecord.reset();
449 if (pCurrentComponentRecord !=
nullptr)
452 m_componentRecords.push_back(pCurrentComponentRecord);
453 pCurrentComponentRecord.reset();
457 pCurrentComponentRecord = std::make_shared<ComponentRecord>();
459 lineStream >> pCurrentComponentRecord->pkgRef;
460 lineStream >> pCurrentComponentRecord->locationX;
461 lineStream >> pCurrentComponentRecord->locationY;
462 lineStream >> pCurrentComponentRecord->rotation;
465 lineStream >> mirror;
466 pCurrentComponentRecord->mirror = (mirror ==
'M');
468 lineStream >> pCurrentComponentRecord->compName;
469 lineStream >> pCurrentComponentRecord->partName;
472 if (m_componentRecords.size() > UINT_MAX)
474 throw_parse_error(m_path, line, token, lineNumber);
477 pCurrentComponentRecord->index =
static_cast<unsigned int>(m_componentRecords.size());
479 std::string attrIdString;
480 lineStream >> attrIdString;
483 ComponentHeightTracer::instance().logParseStart(
484 pCurrentComponentRecord->compName,
485 pCurrentComponentRecord->pkgRef,
488 if (!pCurrentComponentRecord->ParseAttributeLookupTable(attrIdString))
490 throw_parse_error(m_path, line, token, lineNumber);
494 ComponentHeightTracer::instance().logParseResult(
495 pCurrentComponentRecord->compName,
496 pCurrentComponentRecord->pkgRef,
497 pCurrentComponentRecord->GetAttributeLookupTable(),
500 else if (line.find(PropertyRecord::RECORD_TOKEN) == 0)
504 if (!(lineStream >> token))
506 throw_parse_error(m_path, line, token, lineNumber);
509 if (token != PropertyRecord::RECORD_TOKEN)
511 throw_parse_error(m_path, line, token, lineNumber);
514 auto pPropertyRecord = std::make_shared<PropertyRecord>();
516 if (!(lineStream >> pPropertyRecord->name))
518 throw_parse_error(m_path, line, token, lineNumber);
521 if (!(lineStream >> token))
523 throw_parse_error(m_path, line, token, lineNumber);
532 if (!(lineStream >> token))
534 throw_parse_error(m_path, line, token, lineNumber);
538 if (token.size() > 0 && token[0] ==
'\'')
544 if (token.size() > 0 && token[token.size() - 1] ==
'\'')
547 token.erase(token.size() - 1);
550 Utils::str_trim(token);
553 pPropertyRecord->value = token;
556 while (lineStream >> f)
558 pPropertyRecord->floatValues.push_back(f);
561 pCurrentComponentRecord->m_propertyRecords.push_back(pPropertyRecord);
563 else if (line.find(ComponentRecord::ToeprintRecord::RECORD_TOKEN) == 0)
568 if (token != ComponentRecord::ToeprintRecord::RECORD_TOKEN)
570 throw_parse_error(m_path, line, token, lineNumber);
573 auto pToeprintRecord = std::make_shared<ComponentRecord::ToeprintRecord>();
574 lineStream >> pToeprintRecord->pinNumber;
575 lineStream >> pToeprintRecord->locationX;
576 lineStream >> pToeprintRecord->locationY;
577 lineStream >> pToeprintRecord->rotation;
580 lineStream >> mirror;
581 pToeprintRecord->mirror = (mirror ==
'M' || mirror ==
'm');
583 lineStream >> pToeprintRecord->netNumber;
584 if (pToeprintRecord->netNumber == (
unsigned int)-1)
587 parse_info pi(m_path, line, lineNumber);
588 logdebug(pi.toString(
"Component Toeprint record with netNumber = -1"));
590 if (!m_allowToepintNetNumbersOfNegative1)
592 throw_parse_error(m_path, line, token, lineNumber);
596 lineStream >> pToeprintRecord->subnetNumber;
597 if (pToeprintRecord->subnetNumber == (
unsigned int)-1)
600 parse_info pi(m_path, line, lineNumber);
601 logdebug(pi.toString(
"Component Toeprint record with subnetNumber = -1"));
603 if (!m_allowToepintNetNumbersOfNegative1)
605 throw_parse_error(m_path, line, token, lineNumber);
609 lineStream >> pToeprintRecord->name;
611 pCurrentComponentRecord->m_toeprintRecords.push_back(pToeprintRecord);
613 else if (line.find(ComponentsFile::BomDescriptionRecord::CPN_RECORD_TOKEN) == 0)
619 if (token != ComponentsFile::BomDescriptionRecord::CPN_RECORD_TOKEN)
621 throw_parse_error(m_path, line, token, lineNumber);
624 if (pCurrentBomDescriptionRecord !=
nullptr)
626 m_bomDescriptionRecordsByCpn[pCurrentBomDescriptionRecord->cpn] = pCurrentBomDescriptionRecord;
627 pCurrentBomDescriptionRecord.reset();
630 pCurrentBomDescriptionRecord = std::make_shared<ComponentsFile::BomDescriptionRecord>();
632 else if (line.find(ComponentsFile::BomDescriptionRecord::IPN_RECORD_TOKEN) == 0)
636 if (token != ComponentsFile::BomDescriptionRecord::IPN_RECORD_TOKEN)
638 throw_parse_error(m_path, line, token, lineNumber);
641 if (pCurrentBomDescriptionRecord ==
nullptr)
643 throw_parse_error(m_path, line, token, lineNumber);
646 if (!(lineStream >> pCurrentBomDescriptionRecord->ipn))
652 else if (line.find(ComponentsFile::BomDescriptionRecord::DSC_RECORD_TOKEN) == 0)
656 if (token != ComponentsFile::BomDescriptionRecord::DSC_RECORD_TOKEN)
658 throw_parse_error(m_path, line, token, lineNumber);
661 if (pCurrentBomDescriptionRecord ==
nullptr)
663 throw_parse_error(m_path, line, token, lineNumber);
666 std::string description;
668 if (!(lineStream >> description))
674 pCurrentBomDescriptionRecord->descriptions.push_back(description);
676 else if (line.find(ComponentsFile::BomDescriptionRecord::VPL_VND_RECORD_TOKEN) == 0)
680 if (token != ComponentsFile::BomDescriptionRecord::VPL_VND_RECORD_TOKEN)
682 throw_parse_error(m_path, line, token, lineNumber);
685 if (pCurrentBomDescriptionRecord ==
nullptr)
687 throw_parse_error(m_path, line, token, lineNumber);
690 if (!(lineStream >> pCurrentBomDescriptionRecord->vpl_vnd))
692 throw_parse_error(m_path, line, token, lineNumber);
695 else if (line.find(ComponentsFile::BomDescriptionRecord::VPL_MPN_RECORD_TOKEN) == 0)
699 if (token != ComponentsFile::BomDescriptionRecord::VPL_MPN_RECORD_TOKEN)
701 throw_parse_error(m_path, line, token, lineNumber);
704 if (pCurrentBomDescriptionRecord ==
nullptr)
706 throw_parse_error(m_path, line, token, lineNumber);
709 if (!(lineStream >> pCurrentBomDescriptionRecord->vpl_mpn))
711 throw_parse_error(m_path, line, token, lineNumber);
714 else if (line.find(ComponentsFile::BomDescriptionRecord::VND_RECORD_TOKEN) == 0)
718 if (token != ComponentsFile::BomDescriptionRecord::VND_RECORD_TOKEN)
720 throw_parse_error(m_path, line, token, lineNumber);
723 if (pCurrentBomDescriptionRecord ==
nullptr)
725 throw_parse_error(m_path, line, token, lineNumber);
728 if (!(lineStream >> pCurrentBomDescriptionRecord->vnd))
730 throw_parse_error(m_path, line, token, lineNumber);
733 else if (line.find(ComponentsFile::BomDescriptionRecord::MPN_RECORD_TOKEN) == 0)
737 if (token != ComponentsFile::BomDescriptionRecord::MPN_RECORD_TOKEN)
739 throw_parse_error(m_path, line, token, lineNumber);
742 if (pCurrentBomDescriptionRecord ==
nullptr)
744 throw_parse_error(m_path, line, token, lineNumber);
747 if (!(lineStream >> pCurrentBomDescriptionRecord->mpn))
749 throw_parse_error(m_path, line, token, lineNumber);
759 if (pCurrentBomDescriptionRecord !=
nullptr)
762 m_bomDescriptionRecordsByCpn[pCurrentBomDescriptionRecord->cpn] = pCurrentBomDescriptionRecord;
763 pCurrentBomDescriptionRecord.reset();
767 if (pCurrentComponentRecord !=
nullptr)
770 m_componentRecords.push_back(pCurrentComponentRecord);
771 pCurrentComponentRecord.reset();
774 componentsFile.close();
776 catch (parse_error& pe)
778 auto m = pe.toString(
"Parse Error:");
780 componentsFile.close();
783 catch (std::exception& e)
785 parse_info pi(m_path, line, lineNumber);
786 const auto m = pi.toString();
787 logexception_msg(e, m);
788 componentsFile.close();