blob: 1ac6bba4f57a81ae9a2dd0b177ff4999332b4b69 [file] [log] [blame]
edisonn@google.com1a191c62013-06-11 21:44:08 +00001import sys
2
3class PdfName:
4 def __init__(self, name, abr=''):
5 self.fName = name
6 self.fAbr = abr
edisonn@google.comaf3daa02013-06-12 19:07:45 +00007
8 def toCpp(self):
9 return '\"' + self.fName + '\"'
10
11class PdfString:
12 def __init__(self, value):
13 self.fValue = value
14
15 def toCpp(self):
16 return '\"' + self.fValue + '\"'
edisonn@google.com1a191c62013-06-11 21:44:08 +000017
18class PdfInteger:
19 def __init__(self, value):
20 self.fValue = value
21
edisonn@google.comaf3daa02013-06-12 19:07:45 +000022 def toCpp(self):
23 return str(self.fValue)
24
edisonn@google.com1a191c62013-06-11 21:44:08 +000025class PdfReal:
26 def __init__(self, value):
27 self.fValue = value
28
edisonn@google.comaf3daa02013-06-12 19:07:45 +000029 def toCpp(self):
30 return str(self.fValue)
31
edisonn@google.com1a191c62013-06-11 21:44:08 +000032class PdfString:
33 def __init__(self, value):
34 self.fValue = value
35
edisonn@google.comaf3daa02013-06-12 19:07:45 +000036 def toCpp(self):
37 return self.fValue
38
edisonn@google.com1a191c62013-06-11 21:44:08 +000039class PdfBoolean:
40 def __init__(self, value):
41 self.fValue = value
42
edisonn@google.comaf3daa02013-06-12 19:07:45 +000043 def toCpp(self):
44 return self.fValue
45
edisonn@google.com1a191c62013-06-11 21:44:08 +000046class PdfField:
47 def __init__(self, parent, name, abr):
48 self.fParent = parent
49 self.fName = name
50 self.fAbr = abr
51
52 self.fDefault = ''
53 self.fType = ''
edisonn@google.comaf3daa02013-06-12 19:07:45 +000054 self.fCppName = ''
55 self.fCppType = ''
56 self.fCppReader = ''
57 self.fValidOptions = []
58 self.fHasMust = False
59 self.fMustBe = ''
edisonn@google.com1a191c62013-06-11 21:44:08 +000060
61 def must(self, value):
edisonn@google.comaf3daa02013-06-12 19:07:45 +000062 self.fHasMust = True
63 self.fMustBe = value
64 return self
edisonn@google.com1a191c62013-06-11 21:44:08 +000065
66 def default(self, value):
67 self.fDefault = value
68 return self
69
edisonn@google.comaf3daa02013-06-12 19:07:45 +000070 def number(self, name):
edisonn@google.com1a191c62013-06-11 21:44:08 +000071 self.fType = 'number'
edisonn@google.comaf3daa02013-06-12 19:07:45 +000072 self.fCppName = name
73 self.fCppType = 'double'
74 self.fCppReader = 'DoubleFromDictionary'
edisonn@google.com1a191c62013-06-11 21:44:08 +000075 return self
76
edisonn@google.comaf3daa02013-06-12 19:07:45 +000077 def integer(self, name):
edisonn@google.com1a191c62013-06-11 21:44:08 +000078 self.fType = 'integer'
edisonn@google.comaf3daa02013-06-12 19:07:45 +000079 self.fCppName = name
80 self.fCppType = 'long'
81 self.fCppReader = 'LongFromDictionary'
edisonn@google.com1a191c62013-06-11 21:44:08 +000082 return self
83
edisonn@google.comaf3daa02013-06-12 19:07:45 +000084 def real(self, name):
edisonn@google.com1a191c62013-06-11 21:44:08 +000085 self.fType = 'real'
edisonn@google.comaf3daa02013-06-12 19:07:45 +000086 self.fCppName = name
87 self.fCppType = 'double'
88 self.fCppReader = 'DoubleFromDictionary'
edisonn@google.com1a191c62013-06-11 21:44:08 +000089 return self
90
edisonn@google.comaf3daa02013-06-12 19:07:45 +000091 def name(self, name):
edisonn@google.com1a191c62013-06-11 21:44:08 +000092 self.fType = 'name'
edisonn@google.comaf3daa02013-06-12 19:07:45 +000093 self.fCppName = name
94 self.fCppType = 'std::string'
95 self.fCppReader = 'NameFromDictionary'
edisonn@google.com1a191c62013-06-11 21:44:08 +000096 return self
97
edisonn@google.comaf3daa02013-06-12 19:07:45 +000098 def string(self, name):
edisonn@google.com1a191c62013-06-11 21:44:08 +000099 self.fType = 'string'
edisonn@google.comaf3daa02013-06-12 19:07:45 +0000100 self.fCppName = name
101 self.fCppType = 'std::string'
102 self.fCppReader = 'StringFromDictionary'
edisonn@google.com1a191c62013-06-11 21:44:08 +0000103 return self
104
edisonn@google.comaf3daa02013-06-12 19:07:45 +0000105 def multiple(self, validOptions):
106 self.fValidOptions = validOptions
edisonn@google.com1a191c62013-06-11 21:44:08 +0000107 return self
108
109 def done(self):
110 return self.fParent
111
112
113class PdfClassField:
114 def __init__(self, parent, required):
edisonn@google.comaf3daa02013-06-12 19:07:45 +0000115 #self.fProp = ''
edisonn@google.com1a191c62013-06-11 21:44:08 +0000116 self.fParent = parent
117 self.fRequired = required
118
edisonn@google.comaf3daa02013-06-12 19:07:45 +0000119 def field(self, name, abr=''):
120 self.fProp = PdfField(self, name, abr)
121 return self.fProp
edisonn@google.com1a191c62013-06-11 21:44:08 +0000122
123 def done(self):
124 return self.fParent
125
126class PdfClass:
127 def __init__(self, name, base):
128 self.fFields = []
129 self.fIncludes = []
edisonn@google.comaf3daa02013-06-12 19:07:45 +0000130 self.fCCPublic = []
131 self.fCCPrivate = []
edisonn@google.com1a191c62013-06-11 21:44:08 +0000132 self.fName = name
133 self.fBase = base
134
edisonn@google.comf7dd4912013-06-11 23:06:16 +0000135 self.fEnumSubclasses = []
136
137 self.fEnum = '!UNDEFINED'
138 self.fEnumEnd = '!UNDEFINED'
139
edisonn@google.comaf3daa02013-06-12 19:07:45 +0000140 def required(self, badDefault):
edisonn@google.com1a191c62013-06-11 21:44:08 +0000141 field = PdfClassField(self, True)
edisonn@google.comaf3daa02013-06-12 19:07:45 +0000142 field.fBadDefault = badDefault
edisonn@google.com1a191c62013-06-11 21:44:08 +0000143 self.fFields.append(field)
144 return field
145
146 def optional(self):
147 field = PdfClassField(self, False)
148 self.fFields.append(field)
149 return field
150
151 def include(self, path):
152 self.fIncludes.append(path)
153 return self
154
edisonn@google.comaf3daa02013-06-12 19:07:45 +0000155 def carbonCopyPublic(self, cc):
156 self.fCCPublic.append(cc)
157 return self
158
159 def carbonCopyPrivate(self, cc):
160 self.fCCPrivate.append(cc)
edisonn@google.com1a191c62013-06-11 21:44:08 +0000161 return self
162
163class PdfClassManager:
164 def __init__(self):
edisonn@google.comf7dd4912013-06-11 23:06:16 +0000165 self.fClasses = {}
edisonn@google.comaf3daa02013-06-12 19:07:45 +0000166 self.fClassesNamesInOrder = []
edisonn@google.com1a191c62013-06-11 21:44:08 +0000167
edisonn@google.comaf3daa02013-06-12 19:07:45 +0000168 def addClass(self, name, base='Object'):
169 if name == 'Object':
170 cls = PdfClass(name, '')
171 else:
172 cls = PdfClass(name, base)
edisonn@google.comf7dd4912013-06-11 23:06:16 +0000173 self.fClasses[name] = cls
edisonn@google.comaf3daa02013-06-12 19:07:45 +0000174 self.fClassesNamesInOrder.append(name)
edisonn@google.com1a191c62013-06-11 21:44:08 +0000175 return cls
176
edisonn@google.comf7dd4912013-06-11 23:06:16 +0000177 def longName(self, name):
178 ret = ''
179 while name != '':
180 cls = self.fClasses[name]
181 ret = name + ret
182 name = cls.fBase
183
184 return ret
185
186
187 def writeEnum(self, enum, enumToCls):
188 print(' ' + enum + ',')
189 cls = enumToCls[enum]
190 cls.fEnumSubclasses.sort()
191
192 cnt = 0
193 for sub in cls.fEnumSubclasses:
194 self.writeEnum(cls.fEnumSubclasses[cnt], enumToCls)
195 cnt = cnt + 1
196
197 if cnt != 0:
198 print(' ' + cls.fEnumEnd + ',')
edisonn@google.comaf3daa02013-06-12 19:07:45 +0000199
200
201 def writeAsNull(self, cls, enumToCls):
202 print(' virtual SkPdf' + cls.fName +'* as' + cls.fName + '() {return NULL;}')
203 print(' virtual const SkPdf' + cls.fName +'* as' + cls.fName + '() const {return NULL;}')
204 print
205
206 cnt = 0
207 for sub in cls.fEnumSubclasses:
208 self.writeAsNull(enumToCls[cls.fEnumSubclasses[cnt]], enumToCls)
209 cnt = cnt + 1
210
211
212 def writeAsFoo(self, cls, enumToCls):
213 # TODO(edisonn): add a container, with sections, public, private, default, ...
214 # the end code will be grouped
215
216 # me
217 print('public:')
218 print(' virtual SkPdf' + cls.fName +'* as' + cls.fName + '() {return this;}')
219 print(' virtual const SkPdf' + cls.fName +'* as' + cls.fName + '() const {return this;}')
220 print
221
222 if cls.fName == 'Object':
223 cnt = 0
224 for sub in cls.fEnumSubclasses:
225 self.writeAsNull(enumToCls[cls.fEnumSubclasses[cnt]], enumToCls)
226 cnt = cnt + 1
227
228 if cls.fName != 'Object':
229 print('private:')
230 base = self.fClasses[cls.fBase]
231 cnt = 0
232 for sub in base.fEnumSubclasses:
233 if enumToCls[base.fEnumSubclasses[cnt]].fName != cls.fName:
234 self.writeAsNull(enumToCls[base.fEnumSubclasses[cnt]], enumToCls)
235 cnt = cnt + 1
236
237
edisonn@google.comf7dd4912013-06-11 23:06:16 +0000238
edisonn@google.com1a191c62013-06-11 21:44:08 +0000239 def write(self):
edisonn@google.comf7dd4912013-06-11 23:06:16 +0000240 # generate enum
241 enumsRoot = []
242
243 enumToCls = {}
244
245 for name in self.fClasses:
246 cls = self.fClasses[name]
247 enum = self.longName(name)
edisonn@google.comaf3daa02013-06-12 19:07:45 +0000248 cls.fEnum = 'k' + enum + '_SkPdfObjectType'
249 cls.fEnumEnd = 'k' + enum + '__End_SkPdfObjectType'
edisonn@google.comf7dd4912013-06-11 23:06:16 +0000250
251 if cls.fBase != '':
252 self.fClasses[cls.fBase].fEnumSubclasses.append(cls.fEnum)
253
254 if cls.fBase == '':
255 enumsRoot.append(cls.fEnum)
256
257 enumToCls[cls.fEnum] = cls
258
259 enumsRoot.sort()
260
edisonn@google.comaf3daa02013-06-12 19:07:45 +0000261
262 # TODO(edisonn): move each .h in it's own file
263 # write imports
264
edisonn@google.comf7dd4912013-06-11 23:06:16 +0000265 # write enums
edisonn@google.comaf3daa02013-06-12 19:07:45 +0000266 print('enum SkPdfObjectType {')
edisonn@google.comf7dd4912013-06-11 23:06:16 +0000267 for enum in enumsRoot:
268 self.writeEnum(enum, enumToCls)
269 print('};')
edisonn@google.comaf3daa02013-06-12 19:07:45 +0000270 print
271
272 # write forward class declaration
273 for name in self.fClassesNamesInOrder:
274 print('class SkPdf' + name + ';')
275 print
276
277 for name in self.fClassesNamesInOrder:
278 cls = self.fClasses[name]
279 enum = cls.fEnum
edisonn@google.comf7dd4912013-06-11 23:06:16 +0000280
edisonn@google.comaf3daa02013-06-12 19:07:45 +0000281 if cls.fBase == '':
282 print('class SkPdf' + cls.fName + ' {')
283 else:
284 print('class SkPdf' + cls.fName + ' : public SkPdf' + cls.fBase + ' {')
285
286 print('public:')
287 print(' virtual SkPdfObjectType getType() const { return ' + cls.fEnum + ';}')
288 if len(cls.fEnumSubclasses) == 0:
289 print(' virtual SkPdfObjectType getTypeEnd() const { return (SkPdfObjectType)(' + cls.fEnum + ' + 1);}')
290 else:
291 print(' virtual SkPdfObjectType getTypeEnd() const { return ' + cls.fEnumEnd + ';}')
292
293
294 self.writeAsFoo(cls, enumToCls)
295
296 print('public:')
297 for cc in cls.fCCPublic:
298 print(' ' + cc)
299
300 print('private:')
301 for cc in cls.fCCPrivate:
302 print(' ' + cc)
303
304 if cls.fBase == '':
305 print('protected:')
306 print(' const PdfMemDocument* fPodofoDoc;')
307 print(' const PdfObject* fPodofoObj;')
308 print
309 print('public:')
310 print(' SkPdf' + cls.fName + '(const PdfMemDocument* podofoDoc, const PdfObject* podofoObj) : fPodofoDoc(podofoDoc), fPodofoObj(podofoObj) {}')
311 print(' const PdfObject* podofo() const { return fPodofoObj;}')
312 else:
313 print('public:')
314 print(' SkPdf' + cls.fName + '(const PdfMemDocument* podofoDoc, const PdfObject* podofoObj) : SkPdf' + cls.fBase + '(podofoDoc, podofoObj) {}')
315
316 #check required fieds, also, there should be an internal_valid() manually wrote for complex
317 # situations
318 # right now valid return true
319 print(' virtual bool valid() const {return true;}')
320
321 for field in cls.fFields:
322 prop = field.fProp
323 if prop.fCppName != '':
324 print(' ' + prop.fCppType + ' ' + prop.fCppName + '() const {')
325 print(' ' + prop.fCppType + ' ret;')
326 print(' if (' + prop.fCppReader + '(fPodofoDoc, fPodofoObj->GetDictionary(), \"' + prop.fName + '\", \"' + prop.fAbr + '\", &ret)) return ret;')
327 if field.fRequired == False:
328 print(' return ' + prop.fDefault.toCpp() + ';');
329 if field.fRequired == True:
330 print(' // TODO(edisonn): warn about missing required field, assert for known good pdfs')
331 print(' return ' + field.fBadDefault + ';');
332 print(' }')
333 print
334
335 print('};')
336 print
337 print
338
339
340
341 # generate constructor when knowing the type
342 # later, p2, generate constructor when not knowing the type - very similar with parsing?
343
edisonn@google.comf7dd4912013-06-11 23:06:16 +0000344 # generate parser
edisonn@google.comaf3daa02013-06-12 19:07:45 +0000345
346 # TODO(edisonn): fast recognition based on must attributes.
347 print('class PodofoMapper {')
348 print('public:')
349 for name in self.fClassesNamesInOrder:
350 cls = self.fClasses[name]
351
352 print(' static bool map' + name + '(const PdfMemDocument& podofoDoc, const PdfObject& podofoObj, SkPdfObject** out) {')
353 print(' if (!isA' + name + '(podofoDoc, podofoObj)) return false;')
354 print
355
356 for sub in cls.fEnumSubclasses:
357 print(' if (map' + enumToCls[sub].fName + '(podofoDoc, podofoObj, out)) return true;')
358
359 print
360
361 print(' *out = new SkPdf' + name + '(&podofoDoc, &podofoObj);')
362 print(' return true;')
363 print(' }')
364 print
365
366 for name in self.fClassesNamesInOrder:
367 cls = self.fClasses[name]
368
369 print(' static bool isA' + name + '(const PdfMemDocument& podofoDoc, const PdfObject& podofoObj) {')
370
371 cntMust = 0
372 for field in cls.fFields:
373 prop = field.fProp
374 if prop.fHasMust:
375 cntMust = cntMust + 1
376 print(' ' + prop.fCppType + ' ' + prop.fCppName + ';')
377 print(' if (!' + prop.fCppReader + '(&podofoDoc, podofoObj.GetDictionary(), \"' + prop.fName + '\", \"' + prop.fAbr + '\", &' + prop.fCppName + ')) return false;')
378 print(' if (' + prop.fCppName + ' != ' + prop.fMustBe.toCpp() + ') return false;')
379 print
380
381 # hack, we only care about dictionaries now, so ret tru only if there is a match
382 if cntMust != 0 or name == 'Object' or name == 'Dictionary':
383 print(' return true;')
384 else:
385 print(' return false;')
386
387 print(' }')
388 print
389
390 print('};')
391 print
392
edisonn@google.com1a191c62013-06-11 21:44:08 +0000393 return
394
395def generateCode():
396 all = PdfClassManager()
397
398 all.addClass('Object')
399 all.addClass('Null')
400 all.addClass('Boolean')
401 all.addClass('Integer')
402 all.addClass('Real')
403 all.addClass('Name')
404 all.addClass('Stream')
405 all.addClass('Reference')
406 all.addClass('Array')
407 all.addClass('Dictionary')
408
edisonn@google.comaf3daa02013-06-12 19:07:45 +0000409 all.addClass('XObject', 'Dictionary').required('""').field('Type').must(PdfName('XObject')).name('t')
edisonn@google.com1a191c62013-06-11 21:44:08 +0000410
edisonn@google.comaf3daa02013-06-12 19:07:45 +0000411 all.addClass('Image', 'XObject').required('""').field('Type').must(PdfName('XObject')).name('t').done()\
412 .done()\
413 .required('""').field('Subtype').must(PdfName('Image')).name('s').done()\
414 .done()\
415 .required('-1').field('Width', 'W').integer('w').done()\
416 .done()\
417 .required('-1').field('Height', 'H').integer('h').done()\
418 .done()\
419 .required('""').field('ColorSpace').name('cs').multiple([PdfName('/DeviceRGB', '/RGB'), PdfName('/DeviceGray', '/Gray')]).done()\
420 .done()\
421 .optional().field('BitsPerComponent', 'BPC').integer('bpc').multiple([PdfInteger(1), PdfInteger(2), PdfInteger(4), PdfInteger(8)])\
422 .default(PdfInteger(1)).done()\
edisonn@google.com1a191c62013-06-11 21:44:08 +0000423 .done()\
edisonn@google.comaf3daa02013-06-12 19:07:45 +0000424 .carbonCopyPrivate('SkBitmap bitmap;')
edisonn@google.com1a191c62013-06-11 21:44:08 +0000425
edisonn@google.comaf3daa02013-06-12 19:07:45 +0000426 all.addClass('Form', 'XObject').required('""').field('Type').must(PdfName('XObject')).name('t').done()\
427 .done()\
428 .required('""').field('Subtype').must(PdfName('Form')).name('s').done()\
429 .done()\
430 .carbonCopyPublic('void test() {}')
edisonn@google.com1a191c62013-06-11 21:44:08 +0000431
432
433 all.write()
434
435 return 1
436
437if '__main__' == __name__:
438 sys.exit(generateCode())