comparison Plugins/Samples/WebSkeleton/Framework/EmbedResources.py @ 1181:17302d83abfd

Sample plugin framework to serve static resources
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 30 Sep 2014 14:13:20 +0200
parents
children 6e7e5ed91c2d
comparison
equal deleted inserted replaced
1180:dea1c786e1c6 1181:17302d83abfd
1 # Orthanc - A Lightweight, RESTful DICOM Store
2 # Copyright (C) 2012-2014 Medical Physics Department, CHU of Liege,
3 # 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 for f in files:
90 if f.find('~') == -1: # Ignore Emacs backup files
91 if base == '.':
92 r = f
93 else:
94 r = os.path.join(base, f)
95
96 CheckNoUpcase(r)
97 r = '/' + r.replace('\\', '/')
98 if r in content:
99 raise Exception("Twice the same filename (check case): " + r)
100
101 content[r] = {
102 'Filename' : os.path.join(root, f),
103 'Index' : counter
104 }
105 counter += 1
106
107 resources[resourceName] = {
108 'Type' : 'Directory',
109 'Files' : content
110 }
111
112 elif os.path.isfile(pathName):
113 resources[resourceName] = {
114 'Type' : 'File',
115 'Index' : counter,
116 'Filename' : pathName
117 }
118 counter += 1
119
120 else:
121 raise Exception("Not a regular file, nor a directory: " + pathName)
122
123 i += 2
124
125 #pprint.pprint(resources)
126
127
128 #####################################################################
129 ## Write .h header
130 #####################################################################
131
132 header = open(TARGET_BASE_FILENAME + '.h', 'w')
133
134 header.write("""
135 #pragma once
136
137 #include <string>
138 #include <list>
139
140 namespace Orthanc
141 {
142 namespace EmbeddedResources
143 {
144 enum FileResourceId
145 {
146 """)
147
148 isFirst = True
149 for name in resources:
150 if resources[name]['Type'] == 'File':
151 if isFirst:
152 isFirst = False
153 else:
154 header.write(',\n')
155 header.write(' %s' % name)
156
157 header.write("""
158 };
159
160 enum DirectoryResourceId
161 {
162 """)
163
164 isFirst = True
165 for name in resources:
166 if resources[name]['Type'] == 'Directory':
167 if isFirst:
168 isFirst = False
169 else:
170 header.write(',\n')
171 header.write(' %s' % name)
172
173 header.write("""
174 };
175
176 const void* GetFileResourceBuffer(FileResourceId id);
177 size_t GetFileResourceSize(FileResourceId id);
178 void GetFileResource(std::string& result, FileResourceId id);
179
180 const void* GetDirectoryResourceBuffer(DirectoryResourceId id, const char* path);
181 size_t GetDirectoryResourceSize(DirectoryResourceId id, const char* path);
182 void GetDirectoryResource(std::string& result, DirectoryResourceId id, const char* path);
183
184 void ListResources(std::list<std::string>& result, DirectoryResourceId id);
185 }
186 }
187 """)
188 header.close()
189
190
191
192 #####################################################################
193 ## Write the resource content in the .cpp source
194 #####################################################################
195
196 PYTHON_MAJOR_VERSION = sys.version_info[0]
197
198 def WriteResource(cpp, item):
199 cpp.write(' static const uint8_t resource%dBuffer[] = {' % item['Index'])
200
201 f = open(item['Filename'], "rb")
202 content = f.read()
203 f.close()
204
205 # http://stackoverflow.com/a/1035360
206 pos = 0
207 for b in content:
208 if PYTHON_MAJOR_VERSION == 2:
209 c = ord(b[0])
210 else:
211 c = b
212
213 if pos > 0:
214 cpp.write(', ')
215
216 if (pos % 16) == 0:
217 cpp.write('\n ')
218
219 if c < 0:
220 raise Exception("Internal error")
221
222 cpp.write("0x%02x" % c)
223 pos += 1
224
225 cpp.write(' };\n')
226 cpp.write(' static const size_t resource%dSize = %d;\n' % (item['Index'], pos))
227
228
229 cpp = open(TARGET_BASE_FILENAME + '.cpp', 'w')
230
231 print os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
232
233 cpp.write("""
234 #include "%s.h"
235
236 #include <stdint.h>
237 #include <string.h>
238 #include <stdexcept>
239
240 namespace Orthanc
241 {
242 namespace EmbeddedResources
243 {
244 """ % (os.path.basename(TARGET_BASE_FILENAME)))
245
246
247 for name in resources:
248 if resources[name]['Type'] == 'File':
249 WriteResource(cpp, resources[name])
250 else:
251 for f in resources[name]['Files']:
252 WriteResource(cpp, resources[name]['Files'][f])
253
254
255
256 #####################################################################
257 ## Write the accessors to the file resources in .cpp
258 #####################################################################
259
260 cpp.write("""
261 const void* GetFileResourceBuffer(FileResourceId id)
262 {
263 switch (id)
264 {
265 """)
266 for name in resources:
267 if resources[name]['Type'] == 'File':
268 cpp.write(' case %s:\n' % name)
269 cpp.write(' return resource%dBuffer;\n' % resources[name]['Index'])
270
271 cpp.write("""
272 default:
273 throw std::runtime_error("Unknown resource");
274 }
275 }
276
277 size_t GetFileResourceSize(FileResourceId id)
278 {
279 switch (id)
280 {
281 """)
282
283 for name in resources:
284 if resources[name]['Type'] == 'File':
285 cpp.write(' case %s:\n' % name)
286 cpp.write(' return resource%dSize;\n' % resources[name]['Index'])
287
288 cpp.write("""
289 default:
290 throw std::runtime_error("Unknown resource");
291 }
292 }
293 """)
294
295
296
297 #####################################################################
298 ## Write the accessors to the directory resources in .cpp
299 #####################################################################
300
301 cpp.write("""
302 const void* GetDirectoryResourceBuffer(DirectoryResourceId id, const char* path)
303 {
304 switch (id)
305 {
306 """)
307
308 for name in resources:
309 if resources[name]['Type'] == 'Directory':
310 cpp.write(' case %s:\n' % name)
311 isFirst = True
312 for path in resources[name]['Files']:
313 cpp.write(' if (!strcmp(path, "%s"))\n' % path)
314 cpp.write(' return resource%dBuffer;\n' % resources[name]['Files'][path]['Index'])
315 cpp.write(' throw std::runtime_error("Unknown path in a directory resource");\n\n')
316
317 cpp.write(""" default:
318 throw std::runtime_error("Unknown resource");
319 }
320 }
321
322 size_t GetDirectoryResourceSize(DirectoryResourceId id, const char* path)
323 {
324 switch (id)
325 {
326 """)
327
328 for name in resources:
329 if resources[name]['Type'] == 'Directory':
330 cpp.write(' case %s:\n' % name)
331 isFirst = True
332 for path in resources[name]['Files']:
333 cpp.write(' if (!strcmp(path, "%s"))\n' % path)
334 cpp.write(' return resource%dSize;\n' % resources[name]['Files'][path]['Index'])
335 cpp.write(' throw std::runtime_error("Unknown path in a directory resource");\n\n')
336
337 cpp.write(""" default:
338 throw std::runtime_error("Unknown resource");
339 }
340 }
341 """)
342
343
344
345
346 #####################################################################
347 ## List the resources in a directory
348 #####################################################################
349
350 cpp.write("""
351 void ListResources(std::list<std::string>& result, DirectoryResourceId id)
352 {
353 result.clear();
354
355 switch (id)
356 {
357 """)
358
359 for name in resources:
360 if resources[name]['Type'] == 'Directory':
361 cpp.write(' case %s:\n' % name)
362 for path in sorted(resources[name]['Files']):
363 cpp.write(' result.push_back("%s");\n' % path)
364 cpp.write(' break;\n\n')
365
366 cpp.write(""" default:
367 throw std::runtime_error("Unknown resource");
368 }
369 }
370 """)
371
372
373
374
375 #####################################################################
376 ## Write the convenience wrappers in .cpp
377 #####################################################################
378
379 cpp.write("""
380 void GetFileResource(std::string& result, FileResourceId id)
381 {
382 size_t size = GetFileResourceSize(id);
383 result.resize(size);
384 if (size > 0)
385 memcpy(&result[0], GetFileResourceBuffer(id), size);
386 }
387
388 void GetDirectoryResource(std::string& result, DirectoryResourceId id, const char* path)
389 {
390 size_t size = GetDirectoryResourceSize(id, path);
391 result.resize(size);
392 if (size > 0)
393 memcpy(&result[0], GetDirectoryResourceBuffer(id, path), size);
394 }
395 }
396 }
397 """)
398 cpp.close()