OdbDesignLib
OdbDesign ODB++ Parsing Library
 
Loading...
Searching...
No Matches
MatrixFile.cpp
1//
2// Created by nmill on 10/13/2023.
3//
4
5#include "MatrixFile.h"
6#include <fstream>
7#include "str_utils.h"
8#include <string>
9#include "../../Constants.h"
10#include <sstream>
11#include "../parse_error.h"
12#include <Logger.h>
13#include "../invalid_odb_error.h"
14#include "enums.pb.h"
15#include "../../enums.h"
16#include "../OdbFile.h"
17#include <memory>
18#include <ostream>
19#include "../../Text/Utf8Sanitizer.h"
20
21namespace Odb::Lib::FileModel::Design
22{
23 MatrixFile::~MatrixFile()
24 {
25 m_layerRecords.clear();
26 m_stepRecords.clear();
27 }
28
29 const MatrixFile::LayerRecord::Vector& MatrixFile::GetLayerRecords() const
30 {
31 return m_layerRecords;
32 }
33
34 const MatrixFile::StepRecord::Vector& MatrixFile::GetStepRecords() const
35 {
36 return m_stepRecords;
37 }
38
39 bool MatrixFile::Parse(std::filesystem::path path)
40 {
41 std::ifstream matrixFile;
42 int lineNumber = 0;
43 std::string line;
44
45 try
46 {
47 if (!OdbFile::Parse(path)) return false;
48
49 auto matrixFilePath = path / "matrix";
50 if (!std::filesystem::exists(matrixFilePath))
51 {
52 auto message = "matrix/matrix file does not exist: [" + matrixFilePath.string() + "]";
53 throw invalid_odb_error(message.c_str());
54 }
55
56 matrixFile.open(matrixFilePath, std::ios::in);
57 if (!matrixFile.is_open())
58 {
59 auto message = "unable to open matrix/matrix file: [" + matrixFilePath.string() + "]";
60 throw invalid_odb_error(message.c_str());
61 }
62
63 std::shared_ptr<StepRecord> pCurrentStepRecord;
64 std::shared_ptr<LayerRecord> pCurrentLayerRecord;
65 bool openBraceFound = false;
66
67 while (std::getline(matrixFile, line))
68 {
69 lineNumber++;
70 // trim whitespace from beginning and end of line
71 Utils::str_trim(line);
72 if (!line.empty())
73 {
74 std::stringstream lineStream(line);
75 if (line.find(Constants::COMMENT_TOKEN) == 0)
76 {
77 // comment line
78 }
79 else if (line.find(StepRecord::RECORD_TOKEN) == 0)
80 {
81 std::string token;
82 if (!(lineStream >> token))
83 {
84 throw_parse_error(m_path, line, token, lineNumber);
85 }
86
87 // any existing previous step record
88 if (token != StepRecord::RECORD_TOKEN || pCurrentStepRecord != nullptr)
89 {
90 throw_parse_error(m_path, line, token, lineNumber);
91 }
92
93 // open a new STEP array record
94 pCurrentStepRecord = std::make_shared<StepRecord>();
95
96 if (lineStream >> token)
97 {
98 // open brace is at the end on the same line
99 if (token == Constants::ARRAY_RECORD_OPEN_TOKEN)
100 {
101 openBraceFound = true;
102 }
103 }
104 }
105 else if (line.find(LayerRecord::RECORD_TOKEN) == 0)
106 {
107 std::string token;
108 if (!(lineStream >> token))
109 {
110 throw_parse_error(m_path, line, token, lineNumber);
111 }
112
113 // any existing previous layer record
114 if (token != LayerRecord::RECORD_TOKEN || pCurrentLayerRecord != nullptr)
115 {
116 throw_parse_error(m_path, line, token, lineNumber);
117 }
118
119 // open a new LAYER array record
120 pCurrentLayerRecord = std::make_shared<LayerRecord>();
121
122 if (lineStream >> token)
123 {
124 // open brace is on same line
125 if (token == Constants::ARRAY_RECORD_OPEN_TOKEN)
126 {
127 openBraceFound = true;
128 }
129 }
130 }
131 else if (line.find(Constants::ARRAY_RECORD_OPEN_TOKEN) == 0)
132 {
133 // TODO: how to determine if you are opening a step or layer array record?
134 // (maybe a boolean flag? stepArrayOpen = true/false)
135
136 // no current opening of a layer or step array record found yet
137 if (pCurrentStepRecord == nullptr && pCurrentLayerRecord == nullptr)
138 {
139 throw_parse_error(m_path, line, "", lineNumber);
140 }
141
142 // found another open brace while still parsing after the previous record's open brace
143 if (openBraceFound)
144 {
145 throw_parse_error(m_path, line, "", lineNumber);
146 }
147
148 openBraceFound = true;
149
150 // TODO: finish any existing previous layer or step record
151 // (same code as finding a close brace on an empty line)
152
153 // open a new LAYER array record
154 //pCurrentLayerRecord = std::make_shared<LayerRecord>();
155 }
156 else if (line.find(Constants::ARRAY_RECORD_CLOSE_TOKEN) == 0)
157 {
158 if (pCurrentStepRecord != nullptr && openBraceFound)
159 {
160 m_stepRecords.push_back(pCurrentStepRecord);
161 pCurrentStepRecord.reset();
162 openBraceFound = false;
163 }
164 else if (pCurrentLayerRecord != nullptr && openBraceFound)
165 {
166 m_layerRecords.push_back(pCurrentLayerRecord);
167 pCurrentLayerRecord.reset();
168 openBraceFound = false;
169 }
170 else
171 {
172 // found a close brace but aren't currently parsing a step or layer array record
173 throw_parse_error(m_path, line, "", lineNumber);
174 }
175 }
176 else
177 {
178 // it should be a name-value pair line (i.e. element of a step or layer array)
179 std::string attribute;
180 std::string value;
181
182 if (!std::getline(lineStream, attribute, '='))
183 {
184 throw_parse_error(m_path, line, attribute, lineNumber);
185 }
186
187 if (std::getline(lineStream, value))
188 {
189 Utils::str_trim(attribute);
190 Utils::str_trim(value);
191
192 if (pCurrentStepRecord != nullptr && openBraceFound)
193 {
194 if (attribute == StepRecord::COLUMN_KEY || attribute == "col")
195 {
196 pCurrentStepRecord->column = std::stoi(value);
197 }
198 else if (attribute == StepRecord::NAME_KEY || attribute == "name")
199 {
200 pCurrentStepRecord->name = value;
201 }
202 else if (attribute == StepRecord::ID_KEY || attribute == "id")
203 {
204 pCurrentStepRecord->id = static_cast<unsigned int>(std::stoul(value));
205 }
206 else
207 {
208 throw_parse_error(m_path, line, attribute, lineNumber);
209 }
210 }
211 else if (pCurrentLayerRecord != nullptr && openBraceFound)
212 {
213 if (attribute == "ROW" || attribute == "row")
214 {
215 pCurrentLayerRecord->row = std::stoi(value);
216 }
217 else if (attribute == "NAME" || attribute == "name")
218 {
219 pCurrentLayerRecord->name = value;
220 }
221 else if (attribute == "ID" || attribute == "id")
222 {
223 pCurrentLayerRecord->id = (unsigned int)std::stoul(value);
224 }
225 else if (attribute == "TYPE" || attribute == "type")
226 {
227 if (LayerRecord::typeMap.contains(value))
228 {
229 pCurrentLayerRecord->type = LayerRecord::typeMap.getValue(value);
230 }
231 else
232 {
233 throw_parse_error(m_path, line, attribute, lineNumber);
234 }
235 }
236 else if (attribute == LayerRecord::CONTEXT_KEY || attribute == "context")
237 {
238 if (LayerRecord::contextMap.contains(value))
239 {
240 pCurrentLayerRecord->context = LayerRecord::contextMap.getValue(value);
241 }
242 else
243 {
244 throw_parse_error(m_path, line, attribute, lineNumber);
245 }
246 }
247 else if (attribute == "OLD_NAME" || attribute == "old_name")
248 {
249 pCurrentLayerRecord->oldName = value;
250 }
251 else if (attribute == LayerRecord::POLARITY_KEY || attribute == "polarity")
252 {
253 if (LayerRecord::polarityMap.contains(value))
254 {
255 pCurrentLayerRecord->polarity = LayerRecord::polarityMap.getValue(value);
256 }
257 else
258 {
259 throw_parse_error(m_path, line, attribute, lineNumber);
260 }
261 }
262 else if (attribute == LayerRecord::DIELECTRIC_TYPE_KEY || attribute == "dielectric_type")
263 {
264 if (LayerRecord::dielectricTypeMap.contains(value))
265 {
266 pCurrentLayerRecord->dielectricType = LayerRecord::dielectricTypeMap.getValue(value);
267 }
268 else
269 {
270 throw_parse_error(m_path, line, attribute, lineNumber);
271 }
272 }
273 else if (attribute == "DIELECTRIC_NAME" || attribute == "dielectric_name")
274 {
275 pCurrentLayerRecord->dielectricName = value;
276 }
277 else if (attribute == LayerRecord::FORM_KEY || attribute == "form")
278 {
279 if (LayerRecord::formMap.contains(value))
280 {
281 pCurrentLayerRecord->form = LayerRecord::formMap.getValue(value);
282 }
283 else
284 {
285 throw_parse_error(m_path, line, attribute, lineNumber);
286 }
287 }
288 else if (attribute == "CU_TOP" || attribute == "cu_top")
289 {
290 pCurrentLayerRecord->cuTop = std::stoul(value);
291 }
292 else if (attribute == "CU_TOP" || attribute == "cu_top")
293 {
294 pCurrentLayerRecord->cuTop = std::stoul(value);
295 }
296 else if (attribute == "CU_BOTTOM" || attribute == "cu_bottom")
297 {
298 pCurrentLayerRecord->cuBottom = std::stoul(value);
299 }
300 else if (attribute == "REF" || attribute == "ref")
301 {
302 pCurrentLayerRecord->ref = std::stoul(value);
303 }
304 else if (attribute == "START_NAME" || attribute == "start_name")
305 {
306 pCurrentLayerRecord->startName = value;
307 }
308 else if (attribute == "END_NAME" || attribute == "end_name")
309 {
310 pCurrentLayerRecord->endName = value;
311 }
312 else if (attribute == "ADD_TYPE" || attribute == "add_type")
313 {
314 pCurrentLayerRecord->addType = value;
315 }
316 else if (attribute == "COLOR" || attribute == "color")
317 {
318 if (!pCurrentLayerRecord->color.from_string(value)) return false;
319 }
320 else
321 {
322 throw_parse_error(m_path, line, attribute, lineNumber);
323 }
324 }
325 else
326 {
327 // found a name-value pair but aren't currently parsing a step or layer array record
328 //return false;
329 throw_parse_error(m_path, line, attribute, lineNumber);
330 }
331 }
332 else if (!attributeValueIsOptional(attribute))
333 {
334 logwarn("matrix/matrix file: no value for non-optional attribute: " + attribute);
335 }
336 }
337 }
338 }
339
340 matrixFile.close();
341 }
342 catch (parse_error& pe)
343 {
344 auto m = pe.toString("Parse Error:");
345 logerror(m);
346 // cleanup file
347 matrixFile.close();
348 throw pe;
349 }
350 catch (invalid_odb_error& ioe)
351 {
352 parse_info pi(m_path, line, lineNumber);
353 const auto m = pi.toString();
354 logexception_msg(ioe, m);
355 // cleanup file
356 matrixFile.close();
357 throw ioe;
358 }
359
360 return true;
361 }
362
363 std::unique_ptr<Odb::Lib::Protobuf::MatrixFile> Odb::Lib::FileModel::Design::MatrixFile::to_protobuf() const
364 {
365 std::unique_ptr<Odb::Lib::Protobuf::MatrixFile> pMatrixFileMessage(new Odb::Lib::Protobuf::MatrixFile);
366 for (const auto& stepRecord : m_stepRecords)
367 {
368 auto pStepRecordMessage = pMatrixFileMessage->add_steps();
369 pStepRecordMessage->CopyFrom(*stepRecord->to_protobuf());
370 }
371 for (const auto& layerRecord : m_layerRecords)
372 {
373 auto pLayerRecordMessage = pMatrixFileMessage->add_layers();
374 pLayerRecordMessage->CopyFrom(*layerRecord->to_protobuf());
375 }
376 return pMatrixFileMessage;
377
378 }
379
380 void Odb::Lib::FileModel::Design::MatrixFile::from_protobuf(const Odb::Lib::Protobuf::MatrixFile& message)
381 {
382 for (const auto& stepRecord : message.steps())
383 {
384 auto pStepRecord = std::make_shared<StepRecord>();
385 pStepRecord->from_protobuf(stepRecord);
386 m_stepRecords.push_back(pStepRecord);
387 }
388 for (const auto& layerRecord : message.layers())
389 {
390 auto pLayerRecord = std::make_shared<LayerRecord>();
391 pLayerRecord->from_protobuf(layerRecord);
392 m_layerRecords.push_back(pLayerRecord);
393 }
394 }
395
396 bool MatrixFile::Save(std::ostream& os)
397 {
398 for (const auto& stepRecord : m_stepRecords)
399 {
400 os << StepRecord::RECORD_TOKEN << " " << Constants::ARRAY_RECORD_OPEN_TOKEN << std::endl;
401
402 os << '\t' << StepRecord::COLUMN_KEY << "=" << stepRecord->column << std::endl;
403 os << '\t' << StepRecord::NAME_KEY << "=" << stepRecord->name << std::endl;
404 os << '\t' << StepRecord::ID_KEY << "=" << stepRecord->id << std::endl;
405
406 os << Constants::ARRAY_RECORD_CLOSE_TOKEN << std::endl;
407 os << std::endl;
408 }
409
410 for (const auto& layerRecord : m_layerRecords)
411 {
412 os << LayerRecord::RECORD_TOKEN << " " << Constants::ARRAY_RECORD_OPEN_TOKEN << std::endl;
413
414 os << '\t' << LayerRecord::ROW_KEY << "=" << layerRecord->row << std::endl;
415 os << '\t' << LayerRecord::CONTEXT_KEY << "=" << LayerRecord::contextMap.getValue(layerRecord->context) << std::endl;
416 os << '\t' << LayerRecord::TYPE_KEY << "=" << LayerRecord::typeMap.getValue(layerRecord->type) << std::endl;
417 os << '\t' << LayerRecord::NAME_KEY << "=" << layerRecord->name << std::endl;
418 os << '\t' << LayerRecord::POLARITY_KEY << "=" << LayerRecord::polarityMap.getValue(layerRecord->polarity) << std::endl;
419 os << '\t' << LayerRecord::FORM_KEY << "=" << LayerRecord::formMap.getValue(layerRecord->form) << std::endl;
420 os << '\t' << LayerRecord::DIELECTRIC_TYPE_KEY << "=" << LayerRecord::dielectricTypeMap.getValue(layerRecord->dielectricType) << std::endl;
421 os << '\t' << LayerRecord::DIELECTRIC_NAME_KEY << "=" << layerRecord->dielectricName << std::endl;
422 os << '\t' << LayerRecord::CU_TOP_KEY << "=";
423 if (layerRecord->cuTop != (unsigned int)-1)
424 {
425 os << layerRecord->cuTop;
426 }
427 os << std::endl;
428 os << '\t' << LayerRecord::CU_BOTTOM_KEY << "=";
429 if (layerRecord->cuBottom != (unsigned int)-1)
430 {
431 os << layerRecord->cuBottom;
432 }
433 os << std::endl;
434 os << '\t' << LayerRecord::REF_KEY << "=";
435 if (layerRecord->ref != (unsigned int)-1)
436 {
437 os << layerRecord->ref;
438 }
439 os << std::endl;
440 os << '\t' << LayerRecord::START_NAME_KEY << "=" << layerRecord->startName << std::endl;
441 os << '\t' << LayerRecord::END_NAME_KEY << "=" << layerRecord->endName << std::endl;
442 os << '\t' << LayerRecord::OLD_NAME_KEY << "=" << layerRecord->oldName << std::endl;
443 os << '\t' << LayerRecord::ADD_TYPE_KEY << "=" << layerRecord->addType << std::endl;
444 os << '\t' << LayerRecord::COLOR_KEY << "=" << layerRecord->color.to_string() << std::endl;
445 os << '\t' << LayerRecord::ID_KEY << "=" << layerRecord->id << std::endl;
446
447 os << Constants::ARRAY_RECORD_CLOSE_TOKEN << std::endl;
448 os << std::endl;
449 }
450
451 return true;
452 }
453
454 std::unique_ptr<Odb::Lib::Protobuf::MatrixFile::StepRecord> Odb::Lib::FileModel::Design::MatrixFile::StepRecord::to_protobuf() const
455 {
456 std::unique_ptr<Odb::Lib::Protobuf::MatrixFile::StepRecord> pStepRecordMessage(new Odb::Lib::Protobuf::MatrixFile::StepRecord);
457 pStepRecordMessage->set_column(column);
458 pStepRecordMessage->set_name(Odb::Lib::Text::ToUtf8(name));
459 pStepRecordMessage->set_id(id);
460 return pStepRecordMessage;
461 }
462
463 void Odb::Lib::FileModel::Design::MatrixFile::StepRecord::from_protobuf(const Odb::Lib::Protobuf::MatrixFile::StepRecord& message)
464 {
465 column = message.column();
466 name = message.name();
467 id = message.id();
468 }
469
470 std::unique_ptr<Odb::Lib::Protobuf::MatrixFile::LayerRecord> Odb::Lib::FileModel::Design::MatrixFile::LayerRecord::to_protobuf() const
471 {
472 std::unique_ptr<Odb::Lib::Protobuf::MatrixFile::LayerRecord> pLayerRecordMessage(new Odb::Lib::Protobuf::MatrixFile::LayerRecord);
473 pLayerRecordMessage->set_addtype(Odb::Lib::Text::ToUtf8(addType));
474 pLayerRecordMessage->set_context(static_cast<Odb::Lib::Protobuf::MatrixFile::LayerRecord::Context>(context));
475 pLayerRecordMessage->set_cubottom(cuBottom);
476 pLayerRecordMessage->set_cutop(cuTop);
477 pLayerRecordMessage->set_dielectricname(Odb::Lib::Text::ToUtf8(dielectricName));
478 pLayerRecordMessage->set_dielectrictype(static_cast<Odb::Lib::Protobuf::MatrixFile::LayerRecord::DielectricType>(dielectricType));
479 pLayerRecordMessage->set_endname(Odb::Lib::Text::ToUtf8(endName));
480 pLayerRecordMessage->set_form(static_cast<Odb::Lib::Protobuf::MatrixFile::LayerRecord::Form>(form));
481 pLayerRecordMessage->set_id(id);
482 pLayerRecordMessage->set_name(Odb::Lib::Text::ToUtf8(name));
483 pLayerRecordMessage->set_oldname(Odb::Lib::Text::ToUtf8(oldName));
484 pLayerRecordMessage->set_polarity(static_cast<Odb::Lib::Protobuf::Polarity>(polarity));
485 pLayerRecordMessage->set_ref(ref);
486 pLayerRecordMessage->set_row(row);
487 pLayerRecordMessage->set_startname(Odb::Lib::Text::ToUtf8(startName));
488 pLayerRecordMessage->set_type(static_cast<Odb::Lib::Protobuf::MatrixFile::LayerRecord::Type>(type));
489 pLayerRecordMessage->mutable_color()->set_red(color.red);
490 pLayerRecordMessage->mutable_color()->set_green(color.green);
491 pLayerRecordMessage->mutable_color()->set_blue(color.blue);
492 pLayerRecordMessage->mutable_color()->set_nopreference(color.noPreference);
493
494
495 return pLayerRecordMessage;
496 }
497
498 void Odb::Lib::FileModel::Design::MatrixFile::LayerRecord::from_protobuf(const Odb::Lib::Protobuf::MatrixFile::LayerRecord& message)
499 {
500 addType = message.addtype();
501 context = static_cast<Context>(message.context());
502 cuBottom = message.cubottom();
503 cuTop = message.cutop();
504 dielectricName = message.dielectricname();
505 dielectricType = static_cast<DielectricType>(message.dielectrictype());
506 endName = message.endname();
507 form = static_cast<Form>(message.form());
508 id = message.id();
509 name = message.name();
510 oldName = message.oldname();
511 polarity = static_cast<Polarity>(message.polarity());
512 ref = message.ref();
513 row = message.row();
514 startName = message.startname();
515 type = static_cast<Type>(message.type());
516 color.red = message.color().red();
517 color.green = message.color().green();
518 color.blue = message.color().blue();
519 color.noPreference = message.color().nopreference();
520 }
521}