1#include "FileArchive.h"
3#include "ArchiveExtractor.h"
4#include "CrossPlatform.h"
5#include "MiscInfoFile.h"
7#include "../invalid_odb_error.h"
10#include <system_error>
16using namespace std::filesystem;
18namespace Odb::Lib::FileModel::Design
20 FileArchive::FileArchive()
25 FileArchive::FileArchive(
const std::string& path)
30 FileArchive::~FileArchive()
32 m_stepsByName.clear();
33 m_symbolsDirectoriesByName.clear();
36 std::string FileArchive::GetRootDir()
const
41 std::string FileArchive::GetProductName()
const
46 std::string FileArchive::GetFilePath()
const
51 std::string FileArchive::GetFilename()
const
54 return path(m_filePath).filename().string();
57 const StepDirectory::StringMap& FileArchive::GetStepsByName()
const
62 const SymbolsDirectory::StringMap& FileArchive::GetSymbolsDirectoriesByName()
const
64 return m_symbolsDirectoriesByName;
67 bool FileArchive::ParseFileModel()
71 StopWatch timer(
true);
73 if (!exists(m_filePath))
return false;
75 if (is_regular_file(m_filePath))
78 if (!ExtractDesignArchive(m_filePath, extractedPath))
80 logerror(
"failed to extract archive: (" + m_filePath +
")");
84 m_rootDir = findRootDir(extractedPath);
87 if (is_directory(m_rootDir))
89 loginfo(
"Parsing... ");
91 if (ParseDesignDirectory(m_rootDir))
94 auto s = timer.getElapsedSecondsString();
95 loginfo(
"Successfully parsed. (" + s +
"s)");
101 logerror(
"Parsing failed.");
102 throw std::runtime_error(
"Parsing failed.");
107 logerror(
"Failed to find root directory");
119 bool FileArchive::SaveFileModel(
const path& directory)
121 return SaveFileModel(directory, m_productName);
124 bool FileArchive::SaveFileModel(
const path& directory,
const std::string& archiveName)
131 std::string tempName;
132 if (!CrossPlatform::tmpnam_safe(tempName))
return false;
134 auto tempPath = temp_directory_path() / tempName;
135 if (!create_directory(tempPath))
return false;
137 auto rootPath = tempPath / archiveName;
138 if (!create_directory(rootPath))
return false;
139 if (!Save(rootPath))
return false;
142 std::string createdArchivePath;
143 if (! Utils::ArchiveExtractor::CompressDir(rootPath.string(), tempPath.string(), archiveName, createdArchivePath))
return false;
144 if (createdArchivePath.empty())
return false;
147 path archiveFilename = path(createdArchivePath).filename();
148 path destPath = directory / archiveFilename;
150 Utils::fastmove_file(createdArchivePath, destPath,
true, ec);
151 if (ec.value() != 0)
return false;
156 bool FileArchive::Save(
const path& directory)
159 auto miscPath = directory /
"misc";
160 if (!create_directory(miscPath))
return false;
162 std::ofstream ofs1(miscPath /
"info", std::ios::out);
163 if (!m_miscInfoFile.Save(ofs1))
return false;
167 std::ofstream ofs2(miscPath /
"sysattr");
168 if (!m_miscAttrListFile.Save(ofs2))
return false;
172 auto fontsPath = directory /
"fonts";
173 if (!create_directory(fontsPath))
return false;
174 std::ofstream ofs3(fontsPath /
"standard");
175 if (!m_standardFontsFile.Save(ofs3))
return false;
179 auto matrixPath = directory /
"matrix";
180 if (!create_directory(matrixPath))
return false;
181 std::ofstream ofs4(matrixPath /
"matrix");
182 if (!m_matrixFile.Save(ofs4))
return false;
186 const auto stepsDirectory = directory /
"steps";
187 if (!create_directory(stepsDirectory))
return false;
188 for (
auto& kvStepDirectory : m_stepsByName)
190 if (!kvStepDirectory.second->Save(stepsDirectory))
return false;
194 const auto symbolsDirectory = directory /
"symbols";
195 if (!create_directory(symbolsDirectory))
return false;
196 for (
auto& kvSymbolsDirectory : m_symbolsDirectoriesByName)
198 if (!kvSymbolsDirectory.second->Save(symbolsDirectory))
return false;
204 bool FileArchive::ExtractDesignArchive(
const path& archivePath, path& extractedPath)
206 loginfo(
"Extracting... ");
208 if (!Utils::ArchiveExtractor::IsArchiveTypeSupported(archivePath))
210 logerror(
"Unsupported archive type: (" + archivePath.string() +
")");
214 Utils::ArchiveExtractor extractor(archivePath.string());
215 if (!extractor.Extract())
return false;
217 auto extracted = path(extractor.GetExtractionDirectory());
218 if (!exists(extracted))
return false;
220 extractedPath = extracted;
222 loginfo(
"Successfully extracted.");
228 std::string FileArchive::findRootDir(
const path& extractedPath)
230 if (pathContainsTopLevelDesignDirs(extractedPath))
232 return extractedPath.string();
236 for (
const auto& p : directory_iterator(extractedPath))
240 if (pathContainsTopLevelDesignDirs(p.path()))
242 return p.path().string();
251 bool FileArchive::pathContainsTopLevelDesignDirs(
const path& path)
253 for (
const auto& topLevelRootDirName : TOPLEVEL_DESIGN_DIR_NAMES)
255 auto rootLevelDirPath = path / topLevelRootDirName;
256 if (!exists(rootLevelDirPath))
return false;
261 std::unique_ptr<Protobuf::FileArchive> FileArchive::to_protobuf()
const
263 std::unique_ptr<Protobuf::FileArchive> pFileArchiveMessage(
new Protobuf::FileArchive);
264 pFileArchiveMessage->set_productname(m_productName);
265 pFileArchiveMessage->set_filename(m_filename);
267 pFileArchiveMessage->mutable_matrixfile()->CopyFrom(*m_matrixFile.to_protobuf());
268 pFileArchiveMessage->mutable_miscinfofile()->CopyFrom(*m_miscInfoFile.to_protobuf());
269 pFileArchiveMessage->mutable_standardfontsfile()->CopyFrom(*m_standardFontsFile.to_protobuf());
270 pFileArchiveMessage->mutable_miscattrlistfile()->CopyFrom(*m_miscAttrListFile.to_protobuf());
272 for (
const auto& kvStepDirectoryRecord : m_stepsByName)
274 (*pFileArchiveMessage->mutable_stepsbyname())[kvStepDirectoryRecord.first] = *kvStepDirectoryRecord.second->to_protobuf();
277 for (
const auto& kvSymbolsDirectory : m_symbolsDirectoriesByName)
279 (*pFileArchiveMessage->mutable_symbolsdirectoriesbyname())[kvSymbolsDirectory.first] = *kvSymbolsDirectory.second->to_protobuf();
282 return pFileArchiveMessage;
285 void FileArchive::from_protobuf(
const Protobuf::FileArchive& message)
287 m_productName = message.productname();
288 m_filename = message.filename();
290 m_matrixFile.from_protobuf(message.matrixfile());
291 m_miscInfoFile.from_protobuf(message.miscinfofile());
292 m_standardFontsFile.from_protobuf(message.standardfontsfile());
293 m_miscAttrListFile.from_protobuf(message.miscattrlistfile());
295 for (
const auto& kvStepDirectoryRecord : message.stepsbyname())
297 auto pStepDirectory = std::make_shared<StepDirectory>(
"");
298 pStepDirectory->from_protobuf(kvStepDirectoryRecord.second);
299 m_stepsByName[kvStepDirectoryRecord.first] = pStepDirectory;
302 for (
const auto& kvSymbolsDirectory : message.symbolsdirectoriesbyname())
304 auto pSymbolsDirectory = std::make_shared<SymbolsDirectory>(
"");
305 pSymbolsDirectory->from_protobuf(kvSymbolsDirectory.second);
306 m_symbolsDirectoriesByName[kvSymbolsDirectory.first] = pSymbolsDirectory;
310 bool FileArchive::ParseDesignDirectory(
const path& path)
312 if (!exists(path))
return false;
313 else if (!is_directory(path))
return false;
315 m_productName = path.stem().string();
317 if (! ParseStepDirectories(path))
return false;
318 if (! ParseMiscInfoFile(path))
return false;
319 if (! ParseMatrixFile(path))
return false;
320 if (! ParseStandardFontsFile(path))
return false;
321 if (! ParseSymbolsDirectories(path))
return false;
322 if (! ParseMiscAttrListFile(path))
return false;
327 bool FileArchive::ParseStepDirectories(
const path& path)
329 loginfo(
"Parsing steps...");
331 auto stepsPath = path /
"steps";
332 for (
auto& d : directory_iterator(stepsPath))
336 auto pStep = std::make_shared<StepDirectory>(d.path());
339 m_stepsByName[pStep->GetName()] = pStep;
343 logwarn(
"Failed to parse step: " + pStep->GetName());
349 loginfo(
"Parsing steps complete");
354 bool FileArchive::ParseMiscInfoFile(
const path& path)
356 loginfo(
"Parsing misc/info file...");
358 auto miscDirectory = path /
"misc";
359 if (!exists(miscDirectory))
361 auto message =
"misc directory does not exist: [" + miscDirectory.string() +
"]";
362 throw invalid_odb_error(message);
364 if (!is_directory(miscDirectory))
366 auto message =
"misc path is not a directory: [" + miscDirectory.string() +
"]";
367 throw invalid_odb_error(message);
370 if (!m_miscInfoFile.Parse(miscDirectory))
return false;
372 loginfo(
"Parsing misc/info file complete");
377 bool FileArchive::ParseMiscAttrListFile(
const path& path)
379 loginfo(
"Parsing misc/attrlist file...");
381 auto miscDirectory = path /
"misc";
382 if (!exists(miscDirectory))
384 auto message =
"misc directory does not exist: [" + miscDirectory.string() +
"]";
385 throw invalid_odb_error(message);
387 if (!is_directory(miscDirectory))
389 auto message =
"misc path is not a directory: [" + miscDirectory.string() +
"]";
390 throw invalid_odb_error(message);
393 if (!m_miscAttrListFile.Parse(miscDirectory))
return false;
395 loginfo(
"Parsing misc/attrlist file complete");
400 bool FileArchive::ParseMatrixFile(
const path& path)
402 loginfo(
"Parsing matrix/matrix file...");
404 auto matrixDir = path /
"matrix";
405 if (!exists(matrixDir))
407 auto message =
"matrix directory does not exist: [" + matrixDir.string() +
"]";
408 throw invalid_odb_error(message);
410 if (!is_directory(matrixDir))
412 auto message =
"matrix path is not a directory: [" + matrixDir.string() +
"]";
413 throw invalid_odb_error(message);
416 if (!m_matrixFile.Parse(matrixDir))
return false;
418 loginfo(
"Parsing matrix/matrix file complete");
422 bool FileArchive::ParseStandardFontsFile(
const path& path)
424 loginfo(
"Parsing fonts/standard file...");
426 auto fontsDir = path /
"fonts";
427 if (!exists(fontsDir))
429 auto message =
"fonts directory does not exist: [" + fontsDir.string() +
"]";
430 throw invalid_odb_error(message);
432 if (!is_directory(fontsDir))
434 auto message =
"fonts path is not a directory: [" + fontsDir.string() +
"]";
435 throw invalid_odb_error(message);
438 if (!m_standardFontsFile.Parse(fontsDir))
return false;
440 loginfo(
"Parsing fonts/standard file complete");
445 bool FileArchive::ParseSymbolsDirectories(
const path& path)
447 loginfo(
"Parsing symbols root directory...");
449 auto symbolsDirectory = path /
"symbols";
451 if (!exists(symbolsDirectory))
453 logwarn(
"symbols root directory does not exist (" + symbolsDirectory.string() +
")");
456 else if (!is_directory(symbolsDirectory))
458 logerror(
"symbols root directory exists but is a regular file/not a directory (" + symbolsDirectory.string() +
")");
462 for (
auto& d : directory_iterator(symbolsDirectory))
466 auto pSymbolsDirectory = std::make_shared<SymbolsDirectory>(d.path());
467 if (pSymbolsDirectory->Parse())
471 m_symbolsDirectoriesByName[pSymbolsDirectory->GetName()] = pSymbolsDirectory;
475 logerror(
"Parsing symbol directory: " + pSymbolsDirectory->GetName() +
" failed");
481 loginfo(
"Parsing symbols root directory complete");
486 const MiscInfoFile &FileArchive::GetMiscInfoFile()
const
488 return m_miscInfoFile;
491 const MatrixFile& FileArchive::GetMatrixFile()
const
496 const StandardFontsFile& FileArchive::GetStandardFontsFile()
const
498 return m_standardFontsFile;
501 const AttrListFile& FileArchive::GetMiscAttrListFile()
const
503 return m_miscAttrListFile;
506 std::shared_ptr<StepDirectory> FileArchive::GetStepDirectory(
const std::string& stepName )
const
508 std::shared_ptr<FileModel::Design::StepDirectory> pStepDirectory;
510 const auto& steps = GetStepsByName();
513 if (stepName.empty())
516 pStepDirectory = steps.begin()->second;
520 auto findIt = steps.find(stepName);
521 if (findIt != steps.end())
523 pStepDirectory = findIt->second;
528 return pStepDirectory;