comparison Orthanc/Resources/EmbedResources.py @ 31:111689a2c177

author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 24 Jun 2015 16:20:41 +0200
parents
children 05ac3f595ba5
comparison
equal deleted inserted replaced
30:ad7b6757965a 31:111689a2c177
1 # Orthanc - A Lightweight, RESTful DICOM Store
2 # Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics
3 # Department, University Hospital of Liege, Belgium
4 #
5 # This program is free software: you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License as
7 # published by the Free Software Foundation, either version 3 of the
8 # License, or (at your option) any later version.
9 #
10 # In addition, as a special exception, the copyright holders of this
11 # program give permission to link the code of its release with the
12 # OpenSSL project's "OpenSSL" library (or with modified versions of it
13 # that use the same license as the "OpenSSL" library), and distribute
14 # the linked executables. You must obey the GNU General Public License
15 # in all respects for all of the code used other than "OpenSSL". If you
16 # modify file(s) with this exception, you may extend this exception to
17 # your version of the file(s), but you are not obligated to do so. If
18 # you do not wish to do so, delete this exception statement from your
19 # version. If you delete this exception statement from all source files
20 # in the program, then also delete it here.
21 #
22 # This program is distributed in the hope that it will be useful, but
23 # WITHOUT ANY WARRANTY; without even the implied warranty of
24 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 # General Public License for more details.
26 #
27 # You should have received a copy of the GNU General Public License
28 # along with this program. If not, see <http://www.gnu.org/licenses/>.
29
30
31 import sys
32 import os
33 import os.path
34 import pprint
35 import re
36
37 UPCASE_CHECK = True
38 ARGS = []
39 for i in range(len(sys.argv)):
40 if not sys.argv[i].startswith('--'):
41 ARGS.append(sys.argv[i])
42 elif sys.argv[i].lower() == '--no-upcase-check':
43 UPCASE_CHECK = False
44
45 if len(ARGS) < 2 or len(ARGS) % 2 != 0:
46 print ('Usage:')
47 print ('python %s [--no-upcase-check] <TargetBaseFilename> [ <Name> <Source> ]*' % sys.argv[0])
48 exit(-1)
49
50 TARGET_BASE_FILENAME = ARGS[1]
51 SOURCES = ARGS[2:]
52
53 try:
54 # Make sure the destination directory exists
55 os.makedirs(os.path.normpath(os.path.join(TARGET_BASE_FILENAME, '..')))
56 except:
57 pass
58
59
60 #####################################################################
61 ## Read each resource file
62 #####################################################################
63
64 def CheckNoUpcase(s):
65 global UPCASE_CHECK
66 if (UPCASE_CHECK and
67 re.search('[A-Z]', s) != None):
68 raise Exception("Path in a directory with an upcase letter: %s" % s)
69
70 resources = {}
71
72 counter = 0
73 i = 0
74 while i < len(SOURCES):
75 resourceName = SOURCES[i].upper()
76 pathName = SOURCES[i + 1]
77
78 if not os.path.exists(pathName):
79 raise Exception("Non existing path: %s" % pathName)
80
81 if resourceName in resources:
82 raise Exception("Twice the same resource: " + resourceName)
83
84 if os.path.isdir(pathName):
85 # The resource is a directory: Recursively explore its files
86 content = {}
87 for root, dirs, files in os.walk(pathName):
88 base = os.path.relpath(root, pathName)
89
90 # Fix issue #24 (Build fails on OSX when directory has .DS_Store files):
91 # Ignore folders whose name starts with a dot (".")
92 if base.find('/.') != -1:
93 print('Ignoring folder: %s' % root)
94 continue
95
96 for f in files:
97 if f.find('~') == -1: # Ignore Emacs backup files
98 if base == '.':
99 r = f
100 else:
101 r = os.path.join(base, f)
102
103 CheckNoUpcase(r)
104 r = '/' + r.replace('\\', '/')
105 if r in content:
106 raise Exception("Twice the same filename (check case): " + r)
107
108 content[r] = {
109 'Filename' : os.path.join(root, f),
110 'Index' : counter
111 }
112 counter += 1
113
114 resources[resourceName] = {
115 'Type' : 'Directory',
116 'Files' : content
117 }
118
119 elif os.path.isfile(pathName):
120 resources[resourceName] = {
121 'Type' : 'File',
122 'Index' : counter,
123 'Filename' : pathName
124 }
125 counter += 1
126
127 else:
128 raise Exception("Not a regular file, nor a directory: " + pathName)
129
130 i += 2
131
132 #pprint.pprint(resources)
133
134
135 #####################################################################
136 ## Write .h header
137 #####################################################################
138
139 header = open(TARGET_BASE_FILENAME + '.h', 'w')
140
141 header.write("""
142 #pragma once
143
144 #include <string>
145 #include <list>
146
147 namespace Orthanc
148 {
149 namespace EmbeddedResources
150 {
151 enum FileResourceId
152 {
153 """)
154
155 isFirst = True
156 for name in resources:
157 if resources[name]['Type'] == 'File':
158 if isFirst:
159 isFirst = False
160 else:
161 header.write(',\n')
162 header.write(' %s' % name)
163
164 header.write("""
165 };
166
167 enum DirectoryResourceId
168 {
169 """)
170
171 isFirst = True
172 for name in resources:
173 if resources[name]['Type'] == 'Directory':
174 if isFirst:
175 isFirst = False
176 else:
177 header.write(',\n')
178 header.write(' %s' % name)
179
180 header.write("""
181 };
182
183 const void* GetFileResourceBuffer(FileResourceId id);
184 size_t GetFileResourceSize(FileResourceId id);
185 void GetFileResource(std::string& result, FileResourceId id);
186
187 const void* GetDirectoryResourceBuffer(DirectoryResourceId id, const char* path);
188 size_t GetDirectoryResourceSize(DirectoryResourceId id, const char* path);
189 void GetDirectoryResource(std::string& result, DirectoryResourceId id, const char* path);
190
191 void ListResources(std::list<std::string>& result, DirectoryResourceId id);
192 }
193 }
194 """)
195 header.close()
196
197
198
199 #####################################################################
200 ## Write the resource content in the .cpp source
201 #####################################################################
202
203 PYTHON_MAJOR_VERSION = sys.version_info[0]
204
205 def WriteResource(cpp, item):
206 cpp.write(' static const uint8_t resource%dBuffer[] = {' % item['Index'])
207
208 f = open(item['Filename'], "rb")
209 content = f.read()
210 f.close()
211
212 # http://stackoverflow.com/a/1035360
213 pos = 0
214 for b in content:
215 if PYTHON_MAJOR_VERSION == 2:
216 c = ord(b[0])
217 else:
218 c = b
219
220 if pos > 0:
221 cpp.write(', ')
222
223 if (pos % 16) == 0:
224 cpp.write('\n ')
225
226 if c < 0:
227 raise Exception("Internal error")
228
229 cpp.write("0x%02x" % c)
230 pos += 1
231
232 # Zero-size array are disallowed, so we put one single void character in it.
233 if pos == 0:
234 cpp.write(' 0')
235
236 cpp.write(' };\n')
237 cpp.write(' static const size_t resource%dSize = %d;\n' % (item['Index'], pos))
238
239
240 cpp = open(TARGET_BASE_FILENAME + '.cpp', 'w')
241
242 cpp.write("""
243 #include "%s.h"
244 #include "%s/Core/OrthancException.h"
245
246 #include <stdint.h>
247 #include <string.h>
248
249 namespace Orthanc
250 {
251 namespace EmbeddedResources
252 {
253 """ % (os.path.basename(TARGET_BASE_FILENAME),
254 os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))))
255
256
257 for name in resources:
258 if resources[name]['Type'] == 'File':
259 WriteResource(cpp, resources[name])
260 else:
261 for f in resources[name]['Files']:
262 WriteResource(cpp, resources[name]['Files'][f])
263
264
265
266 #####################################################################
267 ## Write the accessors to the file resources in .cpp
268 #####################################################################
269
270 cpp.write("""
271 const void* GetFileResourceBuffer(FileResourceId id)
272 {
273 switch (id)
274 {
275 """)
276 for name in resources:
277 if resources[name]['Type'] == 'File':
278 cpp.write(' case %s:\n' % name)
279 cpp.write(' return resource%dBuffer;\n' % resources[name]['Index'])
280
281 cpp.write("""
282 default:
283 throw OrthancException(ErrorCode_ParameterOutOfRange);
284 }
285 }
286
287 size_t GetFileResourceSize(FileResourceId id)
288 {
289 switch (id)
290 {
291 """)
292
293 for name in resources:
294 if resources[name]['Type'] == 'File':
295 cpp.write(' case %s:\n' % name)
296 cpp.write(' return resource%dSize;\n' % resources[name]['Index'])
297
298 cpp.write("""
299 default:
300 throw OrthancException(ErrorCode_ParameterOutOfRange);
301 }
302 }
303 """)
304
305
306
307 #####################################################################
308 ## Write the accessors to the directory resources in .cpp
309 #####################################################################
310
311 cpp.write("""
312 const void* GetDirectoryResourceBuffer(DirectoryResourceId id, const char* path)
313 {
314 switch (id)
315 {
316 """)
317
318 for name in resources:
319 if resources[name]['Type'] == 'Directory':
320 cpp.write(' case %s:\n' % name)
321 isFirst = True
322 for path in resources[name]['Files']:
323 cpp.write(' if (!strcmp(path, "%s"))\n' % path)
324 cpp.write(' return resource%dBuffer;\n' % resources[name]['Files'][path]['Index'])
325 cpp.write(' throw OrthancException("Unknown path in a directory resource");\n\n')
326
327 cpp.write(""" default:
328 throw OrthancException(ErrorCode_ParameterOutOfRange);
329 }
330 }
331
332 size_t GetDirectoryResourceSize(DirectoryResourceId id, const char* path)
333 {
334 switch (id)
335 {
336 """)
337
338 for name in resources:
339 if resources[name]['Type'] == 'Directory':
340 cpp.write(' case %s:\n' % name)
341 isFirst = True
342 for path in resources[name]['Files']:
343 cpp.write(' if (!strcmp(path, "%s"))\n' % path)
344 cpp.write(' return resource%dSize;\n' % resources[name]['Files'][path]['Index'])
345 cpp.write(' throw OrthancException("Unknown path in a directory resource");\n\n')
346
347 cpp.write(""" default:
348 throw OrthancException(ErrorCode_ParameterOutOfRange);
349 }
350 }
351 """)
352
353
354
355
356 #####################################################################
357 ## List the resources in a directory
358 #####################################################################
359
360 cpp.write("""
361 void ListResources(std::list<std::string>& result, DirectoryResourceId id)
362 {
363 result.clear();
364
365 switch (id)
366 {
367 """)
368
369 for name in resources:
370 if resources[name]['Type'] == 'Directory':
371 cpp.write(' case %s:\n' % name)
372 for path in sorted(resources[name]['Files']):
373 cpp.write(' result.push_back("%s");\n' % path)
374 cpp.write(' break;\n\n')
375
376 cpp.write(""" default:
377 throw OrthancException(ErrorCode_ParameterOutOfRange);
378 }
379 }
380 """)
381
382
383
384
385 #####################################################################
386 ## Write the convenience wrappers in .cpp
387 #####################################################################
388
389 cpp.write("""
390 void GetFileResource(std::string& result, FileResourceId id)
391 {
392 size_t size = GetFileResourceSize(id);
393 result.resize(size);
394 if (size > 0)
395 memcpy(&result[0], GetFileResourceBuffer(id), size);
396 }
397
398 void GetDirectoryResource(std::string& result, DirectoryResourceId id, const char* path)
399 {
400 size_t size = GetDirectoryResourceSize(id, path);
401 result.resize(size);
402 if (size > 0)
403 memcpy(&result[0], GetDirectoryResourceBuffer(id, path), size);
404 }
405 }
406 }
407 """)
408 cpp.close()