HAL  v4.5.0-83-g30c8f0afc
The Hardware Analyzer - a comprehensive reverse engineering and manipulation framework for gate-level netlists.
project_manager.cpp
Go to the documentation of this file.
2 
10 
11 #include <filesystem>
12 #include <fstream>
13 #include <iostream>
14 #include <rapidjson/filereadstream.h>
15 #include <rapidjson/stringbuffer.h>
16 
17 #define PRETTY_JSON_OUTPUT 0
18 #if PRETTY_JSON_OUTPUT == 1
19 #include "rapidjson/prettywriter.h"
20 #else
21 #include "rapidjson/writer.h"
22 #endif
23 
25 
26 namespace hal
27 {
28  ProjectManager* ProjectManager::inst = nullptr;
29 
30  const std::string ProjectManager::s_project_file = ".project.json";
31 
32  ProjectManager::ProjectManager() : m_project_status(ProjectStatus::NONE)
33  {
34  ;
35  }
36 
38  {
39  if (!inst)
40  inst = new ProjectManager;
41  return inst;
42  }
43 
44  void ProjectManager::register_serializer(const std::string& tagname, ProjectSerializer* serializer)
45  {
46  if (m_serializer.find(tagname) == m_serializer.end())
47  m_serializer[tagname] = serializer;
48  else
49  {
50  log_warning("project_manager", "serializer '{}' already registered.", tagname);
51  }
52  }
53 
54  void ProjectManager::unregister_serializer(const std::string& tagname)
55  {
56  auto it = m_serializer.find(tagname);
57  if (it != m_serializer.end())
58  m_serializer.erase(it);
59  }
60 
61  std::string ProjectManager::get_filename(const std::string& tagname)
62  {
63  auto it = m_filename.find(tagname);
64  if (it == m_filename.end())
65  return std::string();
66  return it->second;
67  }
68 
69  bool ProjectManager::open_project(const std::string& path)
70  {
71  if (!path.empty())
72  m_proj_dir = ProjectDirectory(path);
73  if (!std::filesystem::exists(m_proj_dir))
74  {
75  log_warning("project_manager", "cannot open project '{}', path doesn't exist.", path);
76  return false;
77  }
78  if (deserialize())
79  {
80  m_project_status = ProjectStatus::OPENED;
81  return true;
82  }
83  return false;
84  }
85 
86  void ProjectManager::set_project_directory(const std::string& path)
87  {
88  m_proj_dir = ProjectDirectory(path);
89  }
90 
92  {
93  return m_proj_dir;
94  }
95 
96  bool ProjectManager::create_project_directory(const std::string& path)
97  {
98  std::error_code errCode;
99  m_proj_dir = ProjectDirectory(path);
100  if (std::filesystem::exists(m_proj_dir))
101  return false;
102  bool success = std::filesystem::create_directory(m_proj_dir, errCode);
103  if (errCode)
104  {
105  log_warning("project_manager", "cannot create directory '{}': '{}'", m_proj_dir.string(), errCode.message());
106  return false;
107  }
108  if (!success)
109  return false;
110  m_netlist_file = m_proj_dir.get_default_filename(".hal");
111 
112  std::filesystem::create_directory(m_proj_dir.get_filename("py"));
113  std::filesystem::create_directory(m_proj_dir.get_filename(ProjectDirectory::s_shadow_dir));
114  return serialize_to_projectfile(false);
115  }
116 
118  {
119  if (m_proj_dir.empty())
120  return false;
121  return std::filesystem::remove_all(m_proj_dir);
122  }
123 
125  {
126  m_project_status = stat;
127  }
128 
130  {
131  return m_project_status;
132  }
133 
134  void ProjectManager::set_gate_library_path(const std::string& glpath)
135  {
136  m_gatelib_path = glpath;
137  }
138 
139  bool ProjectManager::serialize_project(Netlist* netlist, bool shadow)
140  {
141  if (!netlist)
142  return false;
143 
144  m_netlist_save = netlist;
145  const GateLibrary* gl = m_netlist_save->get_gate_library();
146  if (gl)
147  m_gatelib_path = gl->get_path().string();
148  if (shadow)
149  m_netlist_file = m_proj_dir.get_shadow_filename(".hal");
150  else
151  m_netlist_file = m_proj_dir.get_default_filename(".hal");
152 
153  if (!netlist_serializer::serialize_to_file(m_netlist_save, m_netlist_file))
154  return false;
155 
156  if (!serialize_external(shadow))
157  return false;
158 
159  return serialize_to_projectfile(shadow);
160  }
161 
163  {
164  std::filesystem::path filename(m_proj_dir);
165  filename.append(m_netlist_file);
166  return filename.string();
167  }
168 
169  std::unique_ptr<Netlist>& ProjectManager::get_netlist()
170  {
171  return m_netlist_load;
172  }
173 
175  {
176  std::filesystem::path projFilePath(m_proj_dir);
177  projFilePath.append(s_project_file);
178 
179  FILE* fp = fopen(projFilePath.string().c_str(), "r");
180  if (fp == NULL)
181  return;
182 
183  char buffer[65536];
184  rapidjson::FileReadStream frs(fp, buffer, sizeof(buffer));
185  rapidjson::Document doc;
186  doc.ParseStream<0, rapidjson::UTF8<>, rapidjson::FileReadStream>(frs);
187  fclose(fp);
188 
189  if (doc.HasMember("netlist"))
190  {
191  rapidjson::Value::MemberIterator netlistMember = doc.FindMember("netlist");
192  std::string netlistFilename = netlistMember->value.GetString();
193  int n = ProjectDirectory::s_shadow_dir.size() + 1;
194  if (netlistFilename.substr(0, n) == ProjectDirectory::s_shadow_dir + '/')
195  {
196  netlistFilename.erase(0, n);
197  netlistMember->value.SetString(netlistFilename.c_str(), doc.GetAllocator());
198 
199  std::ofstream of(projFilePath);
200  if (!of.good())
201  return;
202 
203  rapidjson::StringBuffer strbuf;
204 #if PRETTY_JSON_OUTPUT == 1
205  rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(strbuf);
206 #else
207  rapidjson::Writer<rapidjson::StringBuffer> writer(strbuf);
208 #endif
209  doc.Accept(writer);
210  of << strbuf.GetString();
211  of.close();
212  }
213  }
214  }
215 
216  bool ProjectManager::deserialize()
217  {
218  std::filesystem::path projFilePath(m_proj_dir);
219  projFilePath.append(s_project_file);
220 
221  FILE* fp = fopen(projFilePath.string().c_str(), "r");
222  if (fp == NULL)
223  {
224  log_error("project_manager", "cannot open project file '{}'.", projFilePath.string());
225  return false;
226  }
227 
228  char buffer[65536];
229  rapidjson::FileReadStream frs(fp, buffer, sizeof(buffer));
230  rapidjson::Document doc;
231  doc.ParseStream<0, rapidjson::UTF8<>, rapidjson::FileReadStream>(frs);
232  fclose(fp);
233 
234  if (doc.HasMember("gate_library"))
235  {
236  m_gatelib_path = doc["gate_library"].GetString();
237  std::filesystem::path gatelibPath(m_gatelib_path);
238  if (gatelibPath.is_relative())
239  gatelibPath = m_proj_dir / gatelibPath;
240 
241  if (doc.HasMember("netlist"))
242  {
243  m_netlist_file = doc["netlist"].GetString();
244  std::filesystem::path netlistPath(m_proj_dir);
245  netlistPath.append(m_netlist_file);
246  m_netlist_load = netlist_factory::load_netlist(netlistPath,gatelibPath);
247  if (!m_netlist_load)
248  {
249  log_error("project_manager", "cannot load netlist {}.", netlistPath.string());
250  return false;
251  }
252  }
253  else
254  {
255  log_error("project_manager", "no 'netlist' token found in project file {}.", projFilePath.string());
256  return false;
257  }
258  }
259  else
260  {
261  log_error("netlist", "'gate_library' token not found in project file '{}'.", projFilePath.string());
262  return false;
263  }
264 
265 
266  if (doc.HasMember("serializer"))
267  {
268  for (auto it = doc["serializer"].MemberBegin(); it != doc["serializer"].MemberEnd(); ++it)
269  {
270  m_filename[it->name.GetString()] = it->value.GetString();
271  }
272  }
273 
274  for (auto it = m_serializer.begin(); it != m_serializer.end(); ++it)
275  {
276  it->second->deserialize(m_netlist_load.get(), m_proj_dir);
277  }
278  return true;
279  }
280 
281  bool ProjectManager::serialize_external(bool shadow)
282  {
283  if (!m_netlist_save)
284  return false;
285 
286  m_filename.clear();
287 
288  for (auto it = m_serializer.begin(); it != m_serializer.end(); ++it)
289  {
290  std::string relfile = it->second->serialize(m_netlist_save, shadow ? m_proj_dir.get_filename(ProjectDirectory::s_shadow_dir) : m_proj_dir, shadow);
291  if (relfile.empty())
292  continue;
293  m_filename[it->first] = relfile;
294  }
295  return true;
296  }
297 
298  bool ProjectManager::serialize_to_projectfile(bool shadow) const
299  {
300  std::filesystem::path projFilePath = m_proj_dir.get_filename(s_project_file);
301  if (shadow)
302  {
303  std::filesystem::path shadowPath = m_proj_dir.get_filename(ProjectDirectory::s_shadow_dir);
304  std::filesystem::create_directory(shadowPath);
305  projFilePath = shadowPath;
306  projFilePath.append(s_project_file);
307  }
308 
309  JsonWriteDocument doc;
310  doc["serialization_format_version"] = SERIALIZATION_FORMAT_VERSION;
311  doc["netlist"] = m_proj_dir.get_relative_file_path(m_netlist_file).string();
312  doc["gate_library"] = m_proj_dir.get_relative_file_path(m_gatelib_path).string();
313 
314  if (!m_filename.empty())
315  {
316  JsonWriteObject& serial = doc.add_object("serializer");
317  for (auto it = m_filename.begin(); it != m_filename.end(); ++it)
318  {
319  if (it->second.empty())
320  continue;
321  serial[it->first] = it->second;
322  }
323  serial.close();
324  }
325  return doc.serialize(projFilePath.string());
326  }
327 
328  void ProjectManager::dump() const
329  {
330  for (auto it = m_filename.begin(); it != m_filename.end(); ++it)
331  {
332  std::cout << "serializer: <" << it->first << "> <" << it->second << ">" << std::endl;
333  }
334  }
335 } // namespace hal
std::filesystem::path get_path() const
const GateLibrary * get_gate_library() const
Definition: netlist.cpp:132
std::filesystem::path get_filename(const std::string &relative_filename) const
std::filesystem::path get_relative_file_path(const std::string &filename) const
static const std::string s_shadow_dir
std::filesystem::path get_shadow_filename(const std::string &extension=std::string()) const
std::filesystem::path get_default_filename(const std::string &extension=std::string()) const
static ProjectManager * instance()
void set_project_status(ProjectStatus status)
bool create_project_directory(const std::string &path)
void unregister_serializer(const std::string &tagname)
bool serialize_project(Netlist *netlist, bool shadow=false)
std::unique_ptr< Netlist > & get_netlist()
void register_serializer(const std::string &tagname, ProjectSerializer *serializer)
void set_gate_library_path(const std::string &gl_path)
std::string get_filename(const std::string &serializer_name)
ProjectStatus get_project_status() const
void restore_project_file_from_autosave()
static const std::string s_project_file
std::string get_netlist_filename() const
bool open_project(const std::string &path="")
const ProjectDirectory & get_project_directory() const
void set_project_directory(const std::string &path)
#define log_error(channel,...)
Definition: log.h:78
#define log_warning(channel,...)
Definition: log.h:76
std::unique_ptr< Netlist > load_netlist(const std::filesystem::path &netlist_file, const std::filesystem::path &gate_library_file=std::filesystem::path())
Create a netlist from the given file.
bool serialize_to_file(const Netlist *netlist, const std::filesystem::path &hal_file)
Definition: defines.h:45
std::error_code error_code
Definition: defines.h:46
const int SERIALIZATION_FORMAT_VERSION
This file contains various functions to create and load netlists.