1 | /** \file |
2 | * \brief Small helper program to generate a source file with the |
3 | * contents of all test resources, so that they may be compiled |
4 | * into the test binaries. |
5 | * |
6 | * \author Jöran Schierbaum |
7 | * |
8 | * \par License: |
9 | * This file is part of the Open Graph Drawing Framework (OGDF). |
10 | * |
11 | * \par |
12 | * Copyright (C)<br> |
13 | * See README.md in the OGDF root directory for details. |
14 | * |
15 | * \par |
16 | * This program is free software; you can redistribute it and/or |
17 | * modify it under the terms of the GNU General Public License |
18 | * Version 2 or 3 as published by the Free Software Foundation; |
19 | * see the file LICENSE.txt included in the packaging of this file |
20 | * for details. |
21 | * |
22 | * \par |
23 | * This program is distributed in the hope that it will be useful, |
24 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
25 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
26 | * GNU General Public License for more details. |
27 | * |
28 | * \par |
29 | * You should have received a copy of the GNU General Public |
30 | * License along with this program; if not, see |
31 | * http://www.gnu.org/copyleft/gpl.html |
32 | */ |
33 | |
34 | #include <fstream> |
35 | #include <functional> |
36 | #include <iostream> |
37 | #include <string> |
38 | #include <algorithm> |
39 | #include <tinydir.h> |
40 | |
41 | /* |
42 | * These constants define where to read the resources from and |
43 | * where to place the generated source file respectively. These |
44 | * paths need to be relative to where this program is run from. |
45 | */ |
46 | const std::string RESOURCE_DIR = "test/resources" ; |
47 | |
48 | std::ofstream gfs; |
49 | |
50 | // VisualStudio does not like string literals over 16380 bytes. |
51 | #ifdef _MSC_VER |
52 | #define STRING_LITERAL_MAX_LENGTH 16379 |
53 | #else |
54 | #define STRING_LITERAL_MAX_LENGTH 65530 |
55 | #endif |
56 | |
57 | /** |
58 | * Tests whether the resource directory is present (i.e. the working directory is correct). |
59 | * |
60 | * \return true iff the resource directory was found |
61 | */ |
62 | inline bool resourceCheck() { |
63 | tinydir_dir dir; |
64 | bool result = (tinydir_open(&dir, RESOURCE_DIR.c_str()) != -1); |
65 | tinydir_close(&dir); |
66 | |
67 | return result; |
68 | } |
69 | |
70 | /** |
71 | * Load a file and write its content into the generated source file |
72 | * |
73 | * @param directory the directory the file is in, relative to execution point |
74 | * @param filename the name of the file in the directory |
75 | */ |
76 | void load_file(const std::string& directory, const std::string& filename) { |
77 | std::string filepath = directory + '/' + filename; |
78 | std::ifstream fs(filepath.c_str()); |
79 | char next; |
80 | |
81 | // Write file path and name, but strip the common resource folder prefix |
82 | gfs << " registerResource(\"" << directory.substr(RESOURCE_DIR.length() + 1) << "\", \"" << filename << "\", std::string(\"" ; |
83 | int count = 0; |
84 | while (fs.get(next)) { |
85 | if (count == STRING_LITERAL_MAX_LENGTH) { |
86 | // Make sure our string literals don't get too big. |
87 | // Apparently concatenation is not a problem for any compiler. |
88 | gfs << "\") + std::string(\"" ; |
89 | count = 0; |
90 | } |
91 | // Escape special characters to not accidentally close the string early |
92 | switch (next) { |
93 | case '\t': gfs << "\\t" ; break; |
94 | case '\r': gfs << "\\r" ; break; |
95 | case '\n': gfs << "\\n" ; break; |
96 | case '\\': gfs << "\\\\" ; break; |
97 | case '"': gfs << "\\\"" ; break; |
98 | default: gfs << next; |
99 | } |
100 | count++; |
101 | } |
102 | gfs << "\"));\n" ; |
103 | } |
104 | |
105 | /** |
106 | * Recursively load files and write their contents into the generated source |
107 | * |
108 | * @param directory the current directory to look at, relative to execution point |
109 | * @return true on success, false on any error |
110 | */ |
111 | bool load_files(const std::string& directory) { |
112 | tinydir_dir dir; |
113 | |
114 | if (tinydir_open(&dir, directory.c_str()) == -1) { |
115 | return false; |
116 | } |
117 | |
118 | while (dir.has_next) { |
119 | tinydir_file file; |
120 | |
121 | if (tinydir_readfile(&dir, &file) == -1) { |
122 | return false; |
123 | } |
124 | |
125 | if (!file.is_dir) { |
126 | load_file(directory, file.name); |
127 | } else if (strcmp(file.name, "." ) && strcmp(file.name, ".." )) { |
128 | load_files(directory + "/" + file.name); |
129 | } |
130 | |
131 | tinydir_next(&dir); |
132 | } |
133 | |
134 | tinydir_close(&dir); |
135 | return true; |
136 | } |
137 | |
138 | int main(int argc, char** argv) { |
139 | if (!resourceCheck()) { |
140 | std::cerr << "Could not find the resource directory.\n" |
141 | << "Make sure you run this program from within the OGDF source directory." << std::endl; |
142 | return 1; |
143 | } |
144 | |
145 | if (argc != 2) { |
146 | std::cerr << "Usage: " << argv[0] << " <generated source path>\n" |
147 | << "Make sure you run this program from within the OGDF source directory." << std::endl; |
148 | return 1; |
149 | } |
150 | |
151 | gfs.open(argv[1]); |
152 | |
153 | if (gfs.fail()) { |
154 | std::cerr << "Could not open file " << argv[1] << "!" << std::endl; |
155 | return 1; |
156 | } |
157 | |
158 | gfs << "/* FILE GENERATED AUTOMATICALLY BY " __FILE__ ". DO NOT EDIT. */\n" |
159 | "#include <resources.h>\n" |
160 | "namespace resources {\n" |
161 | "using internal::registerResource;\n" |
162 | "void load_resources() {\n" ; |
163 | |
164 | load_files(RESOURCE_DIR); |
165 | |
166 | gfs << "}\n" |
167 | "}\n" ; |
168 | gfs.close(); |
169 | |
170 | return 0; |
171 | } |
172 | |