AFLOW
 
Loading...
Searching...
No Matches
aurostd_data.cpp
Go to the documentation of this file.
1// ***************************************************************************
2// * *
3// * Aflow STEFANO CURTAROLO - Duke University 2003-2024 *
4// * *
5// ***************************************************************************
6// Written by hagen.eckert@duke.edu
7
8#ifndef _AUROSTD_DATA_CPP_
9#define _AUROSTD_DATA_CPP_
10
11#include <cstring>
12#include <filesystem>
13#include <fstream>
14#include <ios>
15#include <map>
16#include <string>
17#include <utility>
18
19#include <archive.h>
20#include <archive_entry.h>
21
22#include "aurostd.h"
23#include "aurostd_incbin_defs.h"
24#include "aurostd_xerror.h"
25#include "aurostd_xfile.h"
27
28#ifndef CMAKE_SOURCE_DIR
29#define CMAKE_SOURCE_DIR ""
30#endif
31
33// Include files either as text (INCTXT) or binary (INCBIN) into the aflow binary
34// see AUROSTD/aurostd_incbin_defs.h
35 extern "C" {
36 // strings used for unittests
37 INCBIN(FINDSYM, CMAKE_SOURCE_DIR "DATA/FINDSYM.tar.xz");
38 INCBIN(FROZSL, CMAKE_SOURCE_DIR "DATA/FROZSL.tar.xz");
39 INCBIN(PHVASP, CMAKE_SOURCE_DIR "DATA/PHVASP.tar.xz");
40 INCBIN(ReadMe, CMAKE_SOURCE_DIR "DATA/README.tar.xz");
41 INCBIN(Test, CMAKE_SOURCE_DIR "DATA/TEST.tar.xz");
42 INCBIN(Images, CMAKE_SOURCE_DIR "DATA/IMAGES.tar.xz");
43 INCBIN(Scripts, CMAKE_SOURCE_DIR "DATA/SCRIPTS.tar.xz");
44 INCBIN(Prototypes, CMAKE_SOURCE_DIR "DATA/PROTO.tar.xz");
45 }
46
47 static const std::map<std::string, std::pair<char *, unsigned int>> aflow_data_collections = {
48 { "README", {(char *) &afdataReadMeData[0], afdataReadMeSize}},
49 {"FINDSYM", {(char *) &afdataFINDSYMData[0], afdataFINDSYMSize}},
50 { "FROZSL", {(char *) &afdataFROZSLData[0], afdataFROZSLSize}},
51 { "PHVASP", {(char *) &afdataPHVASPData[0], afdataPHVASPSize}},
52 { "TEST", {(char *) &afdataTestData[0], afdataTestSize}},
53 { "IMAGES", {(char *) &afdataImagesData[0], afdataImagesSize}},
54 {"SCRIPTS", {(char *) &afdataScriptsData[0], afdataScriptsSize}},
55 { "PROTO", {(char *) &afdataPrototypesData[0], afdataPrototypesSize}},
56 };
57
58 std::string read_data(struct archive *ar) {
59 std::string content;
60 const size_t buff_size = 16384;
61 char buff[buff_size + 1];
62 size_t size;
63 for (;;) {
64 size = archive_read_data(ar, &buff, buff_size);
65 if (size == 0) {
66 break;
67 }
68 buff[size] = '\0';
69 content += buff;
70 }
71 return content;
72 }
73
74 void write_collection_folder(const std::pair<char *, unsigned int> raw_data, const std::string &path, const std::string &folder_out_raw) {
75 if (path.back() != '/') {
76 const std::string message = "The requested path (" + path + ") is not a folder - use write_collection_file";
78 }
79
80 struct archive *a = archive_read_new();
81 struct archive_entry *entry;
82 static char buff[16384];
83 bool found = false;
84 size_t len;
85 int r;
86 std::filesystem::path file_out;
87 std::filesystem::path raw_out;
88 const std::filesystem::path folder_out = std::filesystem::path(aurostd::CleanFileName(folder_out_raw));
89 archive_read_support_format_tar(a);
90 archive_read_support_filter_xz(a);
91
92 if (archive_read_open_memory(a, raw_data.first, raw_data.second)) {
93 const std::string message = "Embedded archive could not be open while trying to read \"" + path + "\". " + archive_error_string(a);
95 }
96
97 for (;;) {
98 r = archive_read_next_header(a, &entry);
99 if (r == ARCHIVE_EOF) {
100 break;
101 }
102 if (r != ARCHIVE_OK) {
103 const std::string message = "Failed to open entries in archive while trying to read \"" + path + "\". " + archive_error_string(a);
105 }
106
107 // check if the beginning of the entries filename equals the path
108 if (strncmp(archive_entry_pathname(entry), path.c_str(), path.size()) == 0) {
109 // build the new file path relative to folder_out
110 raw_out = std::filesystem::path(archive_entry_pathname(entry));
111 file_out = folder_out / std::filesystem::proximate(raw_out, path);
112 // ensure that the folder exist
113 std::filesystem::create_directories(file_out.parent_path());
114 // write the data
115 std::fstream fs(file_out, std::ios::out);
116 len = archive_read_data(a, buff, sizeof(buff));
117 while (len > 0) { // read until archive is empty
118 fs.write(buff, len);
119 len = archive_read_data(a, buff, sizeof(buff));
120 }
121 fs.close();
122 found = true;
123 } else {
124 archive_read_data_skip(a);
125 }
126 }
127 if (not found) {
128 throw aurostd::xerror(__AFLOW_FILE__, __AFLOW_FUNC__, "Failed to find any entry at \"" + path + "\" in archive.", _FILE_NOT_FOUND_);
129 }
130 archive_read_free(a);
131 }
132
133 void write_collection_file(const std::pair<char *, unsigned int> raw_data, const std::string &filename, const std::string &outfile_raw) {
134 string outfile(CleanFileName(outfile_raw));
135 struct archive *a = archive_read_new();
136 struct archive_entry *entry;
137 static char buff[16384];
138 bool found = false;
139 size_t len;
140
141 const std::filesystem::path path = std::filesystem::path(outfile);
142 archive_read_support_format_tar(a);
143 archive_read_support_filter_xz(a);
144
145 int r;
146 if (archive_read_open_memory(a, raw_data.first, raw_data.second)) {
147 const std::string message = "Embedded archive could not be open while trying to read \"" + filename + "\". " + archive_error_string(a);
149 }
150 for (;;) {
151 r = archive_read_next_header(a, &entry);
152 if (r == ARCHIVE_EOF) {
153 break;
154 }
155 if (r != ARCHIVE_OK) {
156 const std::string message = "Failed to open entries in archive while trying to read \"" + filename + "\". " + archive_error_string(a);
158 }
159
160 if (archive_entry_pathname(entry) == filename) {
161 // open the new file and write it in chunks
162 if (outfile.empty()) {
163 outfile = path.parent_path().string() + "/" + path.stem().string();
164 }
165 std::fstream fs(outfile, std::ios::out);
166 len = archive_read_data(a, buff, sizeof(buff));
167 while (len > 0) { // read until archive is empty
168 fs.write(buff, len);
169 len = archive_read_data(a, buff, sizeof(buff));
170 }
171 fs.close();
172 found = true;
173 break;
174 } else {
175 archive_read_data_skip(a);
176 }
177 }
178 if (not found) {
179 throw aurostd::xerror(__AFLOW_FILE__, __AFLOW_FUNC__, "Failed to find \"" + filename + "\" in archive.", _FILE_NOT_FOUND_);
180 }
181 archive_read_free(a);
182 }
183
184 std::string get_collection_text(const std::pair<char *, unsigned int> raw_data, const std::string &filename) {
185 struct archive *a = archive_read_new();
186 struct archive_entry *entry;
187 bool found = false;
188 archive_read_support_format_tar(a);
189 archive_read_support_filter_xz(a);
190 std::string content;
191 int r;
192
193 if (archive_read_open_memory(a, raw_data.first, raw_data.second)) {
194 const std::string message = "Embedded archive could not be open while trying to read \"" + filename + "\". " + archive_error_string(a);
196 }
197 for (;;) {
198 r = archive_read_next_header(a, &entry);
199 if (r == ARCHIVE_EOF) {
200 break;
201 }
202 if (r != ARCHIVE_OK) {
203 const std::string message = "Failed to open entries in archive while trying to read \"" + filename + "\". " + archive_error_string(a);
205 }
206 if (archive_entry_pathname(entry) == filename) {
207 content = read_data(a);
208 found = true;
209 break;
210 } else {
211 archive_read_data_skip(a);
212 }
213 }
214 if (not found) {
215 throw aurostd::xerror(__AFLOW_FILE__, __AFLOW_FUNC__, "Failed to find \"" + filename + "\" in archive.", _FILE_NOT_FOUND_);
216 }
217 archive_read_free(a);
218 return content;
219 }
220
224 return aurostd::JSON::loadString(get_content("unit_test.json", "TEST"));
225 }
226
229 string get_test_file(string file) {
230 return get_content(file, "TEST");
231 }
232
237 std::string get_content(const std::string &filename, const std::string &collection) {
238 if (aflow_data_collections.count(collection)) {
239 return get_collection_text(aflow_data_collections.at(collection), filename);
240 } else {
241 const string message = "Collection \"" + collection + " \" was not embedded";
243 }
244 }
245
251 void save_to_file(const std::string &filename, const std::string &collection, const std::string &target_path) {
252 if (aflow_data_collections.count(collection)) {
253 write_collection_file(aflow_data_collections.at(collection), filename, target_path);
254 } else {
255 const string message = "Collection \"" + collection + " \" was not embedded";
257 }
258 }
259
265 void save_to_folder(const std::string &path, const std::string &collection, const std::string &target_path) {
266 if (aflow_data_collections.count(collection)) {
267 write_collection_folder(aflow_data_collections.at(collection), path, target_path);
268 } else {
269 const string message = "Collection \"" + collection + " \" was not embedded";
271 }
272 }
273
274} // end namespace aurostd::EmbData
275
276#endif //_AUROSTD_DATA_CPP_
static char buff[16384]
Definition apack.c:19
#define __AFLOW_FILE__
Definition aurostd.h:44
#define __AFLOW_FUNC__
Definition aurostd.h:43
#define CMAKE_SOURCE_DIR
#define INCBIN(...)
Include a binary file into the current translation unit.
#define _FILE_NOT_FOUND_
std::string read_data(struct archive *ar)
void save_to_file(const std::string &filename, const std::string &collection, const std::string &target_path)
write a embedded file into the filesystem
static const std::map< std::string, std::pair< char *, unsigned int > > aflow_data_collections
std::string get_content(const std::string &filename, const std::string &collection)
get the content of an embedded file
string get_test_file(string file)
return data for unittests
void write_collection_folder(const std::pair< char *, unsigned int > raw_data, const std::string &path, const std::string &folder_out_raw)
void save_to_folder(const std::string &path, const std::string &collection, const std::string &target_path)
write a embedded file into the filesystem
std::string get_collection_text(const std::pair< char *, unsigned int > raw_data, const std::string &filename)
void write_collection_file(const std::pair< char *, unsigned int > raw_data, const std::string &filename, const std::string &outfile_raw)
aurostd::JSON::object get_unit_test()
return data for unittests
object loadString(const std::string &content)
create a JSON::object from raw string
string CleanFileName(const string &fileIN)
cleans file names from obvious things
storge container for a JSON object