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 */
46const std::string RESOURCE_DIR = "test/resources";
47
48std::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 */
62inline 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 */
76void 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 */
111bool 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
138int 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