1#include "ComponentsFile.h"
5#include "ArchiveExtractor.h"
6#include "../parse_error.h"
10#include "../invalid_odb_error.h"
12#include "ComponentHeightTracer.h"
13#include "../../Text/Utf8Sanitizer.h"
15using namespace std::filesystem;
18namespace Odb::Lib::FileModel::Design
20 ComponentsFile::ComponentsFile()
21 : m_id((unsigned int)-1)
22 , m_side(BoardSide::BsNone)
26 ComponentsFile::~ComponentsFile()
28 m_attributeNames.clear();
29 m_attributeTextValues.clear();
30 m_componentRecords.clear();
31 m_componentRecordsByName.clear();
32 m_bomDescriptionRecordsByCpn.clear();
35 std::string ComponentsFile::GetUnits()
const
40 BoardSide ComponentsFile::GetSide()
const
45 std::filesystem::path ComponentsFile::GetPath()
50 std::filesystem::path ComponentsFile::GetDirectory()
55 std::string ComponentsFile::GetLayerName()
const
60 const ComponentsFile::ComponentRecord::Vector& ComponentsFile::GetComponentRecords()
const
62 return m_componentRecords;
65 const ComponentsFile::ComponentRecord::StringMap& ComponentsFile::GetComponentRecordsByName()
const
67 return m_componentRecordsByName;
70 const std::vector<std::string>& ComponentsFile::GetAttributeNames()
const
72 return m_attributeNames;
75 const std::vector<std::string>& ComponentsFile::GetAttributeTextValues()
const
77 return m_attributeTextValues;
80 const ComponentsFile::BomDescriptionRecord::StringMap& ComponentsFile::GetBomDescriptionRecordsByCpn()
const
82 return m_bomDescriptionRecordsByCpn;
85 std::unique_ptr<Odb::Lib::Protobuf::ComponentsFile> ComponentsFile::to_protobuf()
const
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()));
95 for (
const auto& attributeName : m_attributeNames)
97 pComponentsFileMessage->add_attributenames(Odb::Lib::Text::ToUtf8(attributeName));
100 for (
const auto& attributeTextValue : m_attributeTextValues)
102 pComponentsFileMessage->add_attributetextvalues(Odb::Lib::Text::ToUtf8(attributeTextValue));
105 for (
const auto& pComponentRecord : m_componentRecords)
108 ComponentHeightTracer::instance().logSerialization(
109 pComponentRecord->compName,
110 pComponentRecord->pkgRef,
111 pComponentRecord->GetAttributeLookupTable(),
114 auto pComponentRecordMessage = pComponentRecord->to_protobuf();
115 pComponentsFileMessage->add_componentrecords()->CopyFrom(*pComponentRecordMessage);
118 for (
const auto& kvBomDescriptionRecord : m_bomDescriptionRecordsByCpn)
120 auto pBomDescriptionRecordMessage = kvBomDescriptionRecord.second->to_protobuf();
121 (*pComponentsFileMessage->mutable_bomdescriptionrecordsbycpn())[Odb::Lib::Text::ToUtf8(kvBomDescriptionRecord.first)] = *pBomDescriptionRecordMessage;
124 return pComponentsFileMessage;
127 void ComponentsFile::from_protobuf(
const Odb::Lib::Protobuf::ComponentsFile& message)
129 m_units = message.units();
131 m_side =
static_cast<BoardSide
>(message.side());
132 m_layerName = message.layername();
133 m_path = message.path();
134 m_directory = message.directory();
136 for (
const auto& attributeName : message.attributenames())
138 m_attributeNames.push_back(attributeName);
141 for (
const auto& attributeTextValue : message.attributetextvalues())
143 m_attributeTextValues.push_back(attributeTextValue);
146 for (
const auto& componentRecordMessage : message.componentrecords())
148 auto pComponentRecord = std::make_shared<ComponentRecord>();
149 pComponentRecord->from_protobuf(componentRecordMessage);
150 m_componentRecords.push_back(pComponentRecord);
153 for (
const auto& kvBomDescriptionRecord : message.bomdescriptionrecordsbycpn())
155 auto pBomDescriptionRecord = std::make_shared<BomDescriptionRecord>();
156 pBomDescriptionRecord->from_protobuf(kvBomDescriptionRecord.second);
157 m_bomDescriptionRecordsByCpn[kvBomDescriptionRecord.first] = pBomDescriptionRecord;
161 bool ComponentsFile::Save(std::ostream& os)
166 std::unique_ptr<Odb::Lib::Protobuf::ComponentsFile::BomDescriptionRecord> ComponentsFile::BomDescriptionRecord::to_protobuf()
const
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)
174 pBomDescriptionRecordMessage->add_descriptions()->assign(Odb::Lib::Text::ToUtf8(description));
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;
183 void ComponentsFile::BomDescriptionRecord::from_protobuf(
const Odb::Lib::Protobuf::ComponentsFile::BomDescriptionRecord& message)
188 for (
const auto& description : message.descriptions())
190 descriptions.push_back(description);
192 vpl_vnd = message.vpl_vnd();
193 vpl_mpn = message.vpl_mpn();
198 ComponentsFile::ComponentRecord::~ComponentRecord()
200 m_toeprintRecords.clear();
201 m_propertyRecords.clear();
204 std::unique_ptr<Odb::Lib::Protobuf::ComponentsFile::ComponentRecord> ComponentsFile::ComponentRecord::to_protobuf()
const
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));
215 pComponentRecordMessage->set_index(index);
217 for (
const auto& pPropertyRecord : m_propertyRecords)
219 auto pPropertyRecordMessage = pPropertyRecord->to_protobuf();
220 pComponentRecordMessage->add_propertyrecords()->CopyFrom(*pPropertyRecordMessage);
223 for (
const auto& pToeprintRecord : m_toeprintRecords)
225 auto pToeprintRecordMessage = pToeprintRecord->to_protobuf();
226 pComponentRecordMessage->add_toeprintrecords()->CopyFrom(*pToeprintRecordMessage);
229 for (
const auto& kvAttributeAssignment : m_attributeLookupTable)
231 (*pComponentRecordMessage->mutable_attributelookuptable())[Odb::Lib::Text::ToUtf8(kvAttributeAssignment.first)] =
Odb::Lib::Text::ToUtf8(kvAttributeAssignment.second);
234 return pComponentRecordMessage;
237 void ComponentsFile::ComponentRecord::from_protobuf(
const Odb::Lib::Protobuf::ComponentsFile::ComponentRecord& message)
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();
247 index = message.index();
249 for (
const auto& propertyRecordMessage : message.propertyrecords())
251 auto pPropertyRecord = std::make_shared<PropertyRecord>();
252 pPropertyRecord->from_protobuf(propertyRecordMessage);
253 m_propertyRecords.push_back(pPropertyRecord);
256 for (
const auto& toeprintRecordMessage : message.toeprintrecords())
258 auto pToeprintRecord = std::make_shared<ToeprintRecord>();
259 pToeprintRecord->from_protobuf(toeprintRecordMessage);
260 m_toeprintRecords.push_back(pToeprintRecord);
263 for (
const auto& kvAttributeAssignment : message.attributelookuptable())
265 m_attributeLookupTable[kvAttributeAssignment.first] = kvAttributeAssignment.second;
269 std::unique_ptr<Odb::Lib::Protobuf::ComponentsFile::ComponentRecord::ToeprintRecord> ComponentsFile::ComponentRecord::ToeprintRecord::to_protobuf()
const
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;
283 void ComponentsFile::ComponentRecord::ToeprintRecord::from_protobuf(
const Odb::Lib::Protobuf::ComponentsFile::ComponentRecord::ToeprintRecord& message)
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();
295 bool ComponentsFile::Parse(std::filesystem::path directory)
297 std::ifstream componentsFile;
303 m_directory = directory;
305 m_layerName = m_directory.filename().string();
306 if (m_layerName == TOP_COMPONENTS_LAYER_NAME ||
307 m_layerName == BOTTOM_COMPONENTS_LAYER_NAME)
309 m_side = m_layerName == TOP_COMPONENTS_LAYER_NAME ?
319 loginfo(
"checking for extraction...");
321 std::filesystem::path componentsFilePath;
322 for (
const std::string componentsFilename : COMPONENTS_FILENAMES)
324 loginfo(
"trying components file: [" + componentsFilename +
"]...");
326 componentsFilePath = Utils::ArchiveExtractor::getUncompressedFilePath(m_directory, componentsFilename);
327 if (exists(componentsFilePath) && is_regular_file(componentsFilePath))
329 loginfo(
"found components file: [" + componentsFilePath.string() +
"]");
334 m_path = componentsFilePath;
336 loginfo(
"any extraction complete, parsing data...");
338 if (!std::filesystem::exists(m_path))
340 auto message =
"components file does not exist: [" + m_path.string() +
"]";
341 throw invalid_odb_error(message.c_str());
343 else if (!std::filesystem::is_regular_file(m_path))
345 auto message =
"components is not a file: [" + m_path.string() +
"]";
346 throw invalid_odb_error(message.c_str());
349 componentsFile.open(m_path.string(), std::ios::in);
350 if (!componentsFile.is_open())
352 auto message =
"unable to open components file: [" + m_path.string() +
"]";
353 throw invalid_odb_error(message.c_str());
356 std::shared_ptr<ComponentRecord> pCurrentComponentRecord;
357 std::shared_ptr<BomDescriptionRecord> pCurrentBomDescriptionRecord;
359 while (std::getline(componentsFile, line))
364 Utils::str_trim(line);
367 std::stringstream lineStream(line);
370 if (line.find(COMMENT_TOKEN) == 0)
374 else if (line.find(UNITS_TOKEN) == 0)
378 if (!std::getline(lineStream, token,
'='))
380 throw_parse_error(m_path, line, token, lineNumber);
382 else if (!std::getline(lineStream, token,
'='))
384 throw_parse_error(m_path, line, token, lineNumber);
389 else if (line.find(ID_TOKEN) == 0)
392 if (!std::getline(lineStream, token,
'='))
394 throw_parse_error(m_path, line, token, lineNumber);
396 else if (!std::getline(lineStream, token,
'='))
398 throw_parse_error(m_path, line, token, lineNumber);
400 m_id = std::stoul(token);
402 else if (line.find(ATTRIBUTE_NAME_TOKEN) == 0)
407 if (!std::getline(lineStream, token,
' '))
409 throw_parse_error(m_path, line, token, lineNumber);
411 else if (!std::getline(lineStream, token,
' '))
413 throw_parse_error(m_path, line, token, lineNumber);
415 m_attributeNames.push_back(token);
417 else if (line.find(ATTRIBUTE_VALUE_TOKEN) == 0)
421 if (!std::getline(lineStream, token,
' '))
423 throw_parse_error(m_path, line, token, lineNumber);
425 else if (!std::getline(lineStream, token,
' '))
427 throw_parse_error(m_path, line, token, lineNumber);
429 m_attributeTextValues.push_back(token);
431 else if (line.find(ComponentRecord::RECORD_TOKEN) == 0)
437 if (token != ComponentRecord::RECORD_TOKEN)
439 throw_parse_error(m_path, line, token, lineNumber);
442 if (pCurrentBomDescriptionRecord !=
nullptr)
445 m_bomDescriptionRecordsByCpn[pCurrentBomDescriptionRecord->cpn] = pCurrentBomDescriptionRecord;
446 pCurrentBomDescriptionRecord.reset();
450 if (pCurrentComponentRecord !=
nullptr)
453 m_componentRecords.push_back(pCurrentComponentRecord);
454 pCurrentComponentRecord.reset();
458 pCurrentComponentRecord = std::make_shared<ComponentRecord>();
460 lineStream >> pCurrentComponentRecord->pkgRef;
461 lineStream >> pCurrentComponentRecord->locationX;
462 lineStream >> pCurrentComponentRecord->locationY;
463 lineStream >> pCurrentComponentRecord->rotation;
466 lineStream >> mirror;
467 pCurrentComponentRecord->mirror = (mirror ==
'M');
469 lineStream >> pCurrentComponentRecord->compName;
470 lineStream >> pCurrentComponentRecord->partName;
473 if (m_componentRecords.size() > UINT_MAX)
475 throw_parse_error(m_path, line, token, lineNumber);
478 pCurrentComponentRecord->index =
static_cast<unsigned int>(m_componentRecords.size());
480 std::string attrIdString;
481 lineStream >> attrIdString;
484 ComponentHeightTracer::instance().logParseStart(
485 pCurrentComponentRecord->compName,
486 pCurrentComponentRecord->pkgRef,
489 if (!pCurrentComponentRecord->ParseAttributeLookupTable(attrIdString))
491 throw_parse_error(m_path, line, token, lineNumber);
495 ComponentHeightTracer::instance().logParseResult(
496 pCurrentComponentRecord->compName,
497 pCurrentComponentRecord->pkgRef,
498 pCurrentComponentRecord->GetAttributeLookupTable(),
501 else if (line.find(PropertyRecord::RECORD_TOKEN) == 0)
505 if (!(lineStream >> token))
507 throw_parse_error(m_path, line, token, lineNumber);
510 if (token != PropertyRecord::RECORD_TOKEN)
512 throw_parse_error(m_path, line, token, lineNumber);
515 auto pPropertyRecord = std::make_shared<PropertyRecord>();
517 if (!(lineStream >> pPropertyRecord->name))
519 throw_parse_error(m_path, line, token, lineNumber);
522 if (!(lineStream >> token))
524 throw_parse_error(m_path, line, token, lineNumber);
533 if (!(lineStream >> token))
535 throw_parse_error(m_path, line, token, lineNumber);
539 if (token.size() > 0 && token[0] ==
'\'')
545 if (token.size() > 0 && token[token.size() - 1] ==
'\'')
548 token.erase(token.size() - 1);
551 Utils::str_trim(token);
554 pPropertyRecord->value = token;
557 while (lineStream >> f)
559 pPropertyRecord->floatValues.push_back(f);
562 pCurrentComponentRecord->m_propertyRecords.push_back(pPropertyRecord);
564 else if (line.find(ComponentRecord::ToeprintRecord::RECORD_TOKEN) == 0)
569 if (token != ComponentRecord::ToeprintRecord::RECORD_TOKEN)
571 throw_parse_error(m_path, line, token, lineNumber);
574 auto pToeprintRecord = std::make_shared<ComponentRecord::ToeprintRecord>();
575 lineStream >> pToeprintRecord->pinNumber;
576 lineStream >> pToeprintRecord->locationX;
577 lineStream >> pToeprintRecord->locationY;
578 lineStream >> pToeprintRecord->rotation;
581 lineStream >> mirror;
582 pToeprintRecord->mirror = (mirror ==
'M' || mirror ==
'm');
584 lineStream >> pToeprintRecord->netNumber;
585 if (pToeprintRecord->netNumber == (
unsigned int)-1)
588 parse_info pi(m_path, line, lineNumber);
589 logdebug(pi.toString(
"Component Toeprint record with netNumber = -1"));
591 if (!m_allowToepintNetNumbersOfNegative1)
593 throw_parse_error(m_path, line, token, lineNumber);
597 lineStream >> pToeprintRecord->subnetNumber;
598 if (pToeprintRecord->subnetNumber == (
unsigned int)-1)
601 parse_info pi(m_path, line, lineNumber);
602 logdebug(pi.toString(
"Component Toeprint record with subnetNumber = -1"));
604 if (!m_allowToepintNetNumbersOfNegative1)
606 throw_parse_error(m_path, line, token, lineNumber);
610 lineStream >> pToeprintRecord->name;
612 pCurrentComponentRecord->m_toeprintRecords.push_back(pToeprintRecord);
614 else if (line.find(ComponentsFile::BomDescriptionRecord::CPN_RECORD_TOKEN) == 0)
620 if (token != ComponentsFile::BomDescriptionRecord::CPN_RECORD_TOKEN)
622 throw_parse_error(m_path, line, token, lineNumber);
625 if (pCurrentBomDescriptionRecord !=
nullptr)
627 m_bomDescriptionRecordsByCpn[pCurrentBomDescriptionRecord->cpn] = pCurrentBomDescriptionRecord;
628 pCurrentBomDescriptionRecord.reset();
631 pCurrentBomDescriptionRecord = std::make_shared<ComponentsFile::BomDescriptionRecord>();
633 else if (line.find(ComponentsFile::BomDescriptionRecord::IPN_RECORD_TOKEN) == 0)
637 if (token != ComponentsFile::BomDescriptionRecord::IPN_RECORD_TOKEN)
639 throw_parse_error(m_path, line, token, lineNumber);
642 if (pCurrentBomDescriptionRecord ==
nullptr)
644 throw_parse_error(m_path, line, token, lineNumber);
647 if (!(lineStream >> pCurrentBomDescriptionRecord->ipn))
653 else if (line.find(ComponentsFile::BomDescriptionRecord::DSC_RECORD_TOKEN) == 0)
657 if (token != ComponentsFile::BomDescriptionRecord::DSC_RECORD_TOKEN)
659 throw_parse_error(m_path, line, token, lineNumber);
662 if (pCurrentBomDescriptionRecord ==
nullptr)
664 throw_parse_error(m_path, line, token, lineNumber);
667 std::string description;
669 if (!(lineStream >> description))
675 pCurrentBomDescriptionRecord->descriptions.push_back(description);
677 else if (line.find(ComponentsFile::BomDescriptionRecord::VPL_VND_RECORD_TOKEN) == 0)
681 if (token != ComponentsFile::BomDescriptionRecord::VPL_VND_RECORD_TOKEN)
683 throw_parse_error(m_path, line, token, lineNumber);
686 if (pCurrentBomDescriptionRecord ==
nullptr)
688 throw_parse_error(m_path, line, token, lineNumber);
691 if (!(lineStream >> pCurrentBomDescriptionRecord->vpl_vnd))
693 throw_parse_error(m_path, line, token, lineNumber);
696 else if (line.find(ComponentsFile::BomDescriptionRecord::VPL_MPN_RECORD_TOKEN) == 0)
700 if (token != ComponentsFile::BomDescriptionRecord::VPL_MPN_RECORD_TOKEN)
702 throw_parse_error(m_path, line, token, lineNumber);
705 if (pCurrentBomDescriptionRecord ==
nullptr)
707 throw_parse_error(m_path, line, token, lineNumber);
710 if (!(lineStream >> pCurrentBomDescriptionRecord->vpl_mpn))
712 throw_parse_error(m_path, line, token, lineNumber);
715 else if (line.find(ComponentsFile::BomDescriptionRecord::VND_RECORD_TOKEN) == 0)
719 if (token != ComponentsFile::BomDescriptionRecord::VND_RECORD_TOKEN)
721 throw_parse_error(m_path, line, token, lineNumber);
724 if (pCurrentBomDescriptionRecord ==
nullptr)
726 throw_parse_error(m_path, line, token, lineNumber);
729 if (!(lineStream >> pCurrentBomDescriptionRecord->vnd))
731 throw_parse_error(m_path, line, token, lineNumber);
734 else if (line.find(ComponentsFile::BomDescriptionRecord::MPN_RECORD_TOKEN) == 0)
738 if (token != ComponentsFile::BomDescriptionRecord::MPN_RECORD_TOKEN)
740 throw_parse_error(m_path, line, token, lineNumber);
743 if (pCurrentBomDescriptionRecord ==
nullptr)
745 throw_parse_error(m_path, line, token, lineNumber);
748 if (!(lineStream >> pCurrentBomDescriptionRecord->mpn))
750 throw_parse_error(m_path, line, token, lineNumber);
760 if (pCurrentBomDescriptionRecord !=
nullptr)
763 m_bomDescriptionRecordsByCpn[pCurrentBomDescriptionRecord->cpn] = pCurrentBomDescriptionRecord;
764 pCurrentBomDescriptionRecord.reset();
768 if (pCurrentComponentRecord !=
nullptr)
771 m_componentRecords.push_back(pCurrentComponentRecord);
772 pCurrentComponentRecord.reset();
775 componentsFile.close();
777 catch (parse_error& pe)
779 auto m = pe.toString(
"Parse Error:");
781 componentsFile.close();
784 catch (std::exception& e)
786 parse_info pi(m_path, line, lineNumber);
787 const auto m = pi.toString();
788 logexception_msg(e, m);
789 componentsFile.close();
std::string ToUtf8(std::string_view input)
Converts input to valid UTF-8.