blob: 5d0558b10bd365384202bc268fb63be4bc66b58d [file] [log] [blame]
edisonn@google.coma2fab9d2013-06-14 19:22:19 +00001
2
edisonn@google.com1a191c62013-06-11 21:44:08 +00003import sys
4
edisonn@google.coma2fab9d2013-06-14 19:22:19 +00005import datatypes
6import pdfspec_autogen
edisonn@google.comaf3daa02013-06-12 19:07:45 +00007
edisonn@google.com1a191c62013-06-11 21:44:08 +00008
edisonn@google.com45327112013-06-13 20:02:29 +00009
10
edisonn@google.com1a191c62013-06-11 21:44:08 +000011class PdfField:
12 def __init__(self, parent, name, abr):
13 self.fParent = parent
14 self.fName = name
15 self.fAbr = abr
16
17 self.fDefault = ''
18 self.fType = ''
edisonn@google.comaf3daa02013-06-12 19:07:45 +000019 self.fCppName = ''
20 self.fCppType = ''
21 self.fCppReader = ''
22 self.fValidOptions = []
23 self.fHasMust = False
24 self.fMustBe = ''
edisonn@google.com1a191c62013-06-11 21:44:08 +000025
26 def must(self, value):
edisonn@google.comaf3daa02013-06-12 19:07:45 +000027 self.fHasMust = True
28 self.fMustBe = value
29 return self
edisonn@google.com1a191c62013-06-11 21:44:08 +000030
31 def default(self, value):
32 self.fDefault = value
33 return self
34
edisonn@google.comaf3daa02013-06-12 19:07:45 +000035 def number(self, name):
edisonn@google.com1a191c62013-06-11 21:44:08 +000036 self.fType = 'number'
edisonn@google.comaf3daa02013-06-12 19:07:45 +000037 self.fCppName = name
38 self.fCppType = 'double'
39 self.fCppReader = 'DoubleFromDictionary'
edisonn@google.com1a191c62013-06-11 21:44:08 +000040 return self
41
edisonn@google.comaf3daa02013-06-12 19:07:45 +000042 def integer(self, name):
edisonn@google.com1a191c62013-06-11 21:44:08 +000043 self.fType = 'integer'
edisonn@google.comaf3daa02013-06-12 19:07:45 +000044 self.fCppName = name
45 self.fCppType = 'long'
46 self.fCppReader = 'LongFromDictionary'
edisonn@google.com1a191c62013-06-11 21:44:08 +000047 return self
48
edisonn@google.comaf3daa02013-06-12 19:07:45 +000049 def name(self, name):
edisonn@google.com1a191c62013-06-11 21:44:08 +000050 self.fType = 'name'
edisonn@google.comaf3daa02013-06-12 19:07:45 +000051 self.fCppName = name
52 self.fCppType = 'std::string'
53 self.fCppReader = 'NameFromDictionary'
edisonn@google.com1a191c62013-06-11 21:44:08 +000054 return self
55
edisonn@google.comaf3daa02013-06-12 19:07:45 +000056 def string(self, name):
edisonn@google.com1a191c62013-06-11 21:44:08 +000057 self.fType = 'string'
edisonn@google.comaf3daa02013-06-12 19:07:45 +000058 self.fCppName = name
59 self.fCppType = 'std::string'
60 self.fCppReader = 'StringFromDictionary'
edisonn@google.com1a191c62013-06-11 21:44:08 +000061 return self
62
edisonn@google.comaf3daa02013-06-12 19:07:45 +000063 def multiple(self, validOptions):
64 self.fValidOptions = validOptions
edisonn@google.com1a191c62013-06-11 21:44:08 +000065 return self
66
edisonn@google.com45327112013-06-13 20:02:29 +000067 def dictionary(self, name):
68 self.fType = 'dictionary'
69 self.fCppName = name
edisonn@google.coma2fab9d2013-06-14 19:22:19 +000070 self.fDictionaryType = 'Dictionary'
71 self.fCppType = 'SkPdfDictionary*'
edisonn@google.com45327112013-06-13 20:02:29 +000072 self.fCppReader = 'DictionaryFromDictionary'
edisonn@google.coma2fab9d2013-06-14 19:22:19 +000073 self.fDefault = datatypes.CppNull()
edisonn@google.com45327112013-06-13 20:02:29 +000074 return self
75
76 def type(self, type):
77 # TODO (edisonn): if simple type, use it, otherwise set it to Dictionary, and set a mask for valid types, like array or name
edisonn@google.coma2fab9d2013-06-14 19:22:19 +000078 type = type.replace('or', ' ')
79 type = type.replace(',', ' ')
80 type = type.replace('text', ' ') # TODO(edisonn): what is the difference between 'text string' and 'string'?
81
82 type = type.strip()
83 types = type.split()
84
85 if len(types) == 1:
86 if type == 'integer':
87 self.integer(self.fCppName)
88 self.default(datatypes.PdfInteger(0))
89 return self
90
91 if type == 'number':
92 self.number(self.fCppName)
93 self.default(datatypes.PdfNumber(0))
94 return self
95
96 if type == 'string':
97 self.string(self.fCppName)
98 self.default(datatypes.PdfString('""'))
99 return self
100
101 if type == 'name':
102 self.name(self.fCppName)
103 self.default(datatypes.PdfName('""'))
104 return self
105
106 if type == 'dictionary':
107 self.dictionary(self.fCppName)
108 self.default(datatypes.CppNull())
109 return self
110
111 self.fType = 'object'
112 self.fDictionaryType = 'Object'
113 self.fCppType = 'SkPdfObject*'
114 self.fCppReader = 'ObjectFromDictionary'
115 self.fDefault = datatypes.CppNull()
edisonn@google.com45327112013-06-13 20:02:29 +0000116 return self
117
118 def comment(self, comment):
119 return self
120
edisonn@google.com1a191c62013-06-11 21:44:08 +0000121 def done(self):
122 return self.fParent
123
124
125class PdfClassField:
edisonn@google.com45327112013-06-13 20:02:29 +0000126 def __init__(self, parent, required, version='', inheritable=False, comment=''):
edisonn@google.comaf3daa02013-06-12 19:07:45 +0000127 #self.fProp = ''
edisonn@google.com1a191c62013-06-11 21:44:08 +0000128 self.fParent = parent
129 self.fRequired = required
edisonn@google.com45327112013-06-13 20:02:29 +0000130 self.fVersion = version
131 self.fInheritable = inheritable
132 self.fComment = comment
edisonn@google.com1a191c62013-06-11 21:44:08 +0000133
edisonn@google.comaf3daa02013-06-12 19:07:45 +0000134 def field(self, name, abr=''):
135 self.fProp = PdfField(self, name, abr)
136 return self.fProp
edisonn@google.com1a191c62013-06-11 21:44:08 +0000137
138 def done(self):
139 return self.fParent
140
141class PdfClass:
edisonn@google.com45327112013-06-13 20:02:29 +0000142 def __init__(self, name, base, comment):
edisonn@google.com1a191c62013-06-11 21:44:08 +0000143 self.fFields = []
144 self.fIncludes = []
edisonn@google.comaf3daa02013-06-12 19:07:45 +0000145 self.fCCPublic = []
146 self.fCCPrivate = []
edisonn@google.com1a191c62013-06-11 21:44:08 +0000147 self.fName = name
148 self.fBase = base
edisonn@google.com45327112013-06-13 20:02:29 +0000149 self.fComment = comment
edisonn@google.com1a191c62013-06-11 21:44:08 +0000150
edisonn@google.comf7dd4912013-06-11 23:06:16 +0000151 self.fEnumSubclasses = []
152
153 self.fEnum = '!UNDEFINED'
154 self.fEnumEnd = '!UNDEFINED'
edisonn@google.coma2fab9d2013-06-14 19:22:19 +0000155 self.fCheck = ''
edisonn@google.comf7dd4912013-06-11 23:06:16 +0000156
edisonn@google.coma2fab9d2013-06-14 19:22:19 +0000157 def check(self, ifCheck):
158 self.fCheck = ifCheck
159 return self
160
edisonn@google.comaf3daa02013-06-12 19:07:45 +0000161 def required(self, badDefault):
edisonn@google.com1a191c62013-06-11 21:44:08 +0000162 field = PdfClassField(self, True)
edisonn@google.comaf3daa02013-06-12 19:07:45 +0000163 field.fBadDefault = badDefault
edisonn@google.com1a191c62013-06-11 21:44:08 +0000164 self.fFields.append(field)
165 return field
166
167 def optional(self):
168 field = PdfClassField(self, False)
169 self.fFields.append(field)
170 return field
edisonn@google.com45327112013-06-13 20:02:29 +0000171
172 #([Required] [;] [inheritable] [;] [version]; [comments])
173 # version: PDF [d].[d]
174 # ; separate props
175 #inheritable
176 #version
177 #required, if
178 #optional, if
edisonn@google.com1a191c62013-06-11 21:44:08 +0000179
180 def include(self, path):
181 self.fIncludes.append(path)
182 return self
183
edisonn@google.comaf3daa02013-06-12 19:07:45 +0000184 def carbonCopyPublic(self, cc):
185 self.fCCPublic.append(cc)
186 return self
187
188 def carbonCopyPrivate(self, cc):
189 self.fCCPrivate.append(cc)
edisonn@google.com1a191c62013-06-11 21:44:08 +0000190 return self
edisonn@google.com45327112013-06-13 20:02:29 +0000191
192 def done(self):
193 return
edisonn@google.com1a191c62013-06-11 21:44:08 +0000194
195class PdfClassManager:
196 def __init__(self):
edisonn@google.comf7dd4912013-06-11 23:06:16 +0000197 self.fClasses = {}
edisonn@google.comaf3daa02013-06-12 19:07:45 +0000198 self.fClassesNamesInOrder = []
edisonn@google.com1a191c62013-06-11 21:44:08 +0000199
edisonn@google.com45327112013-06-13 20:02:29 +0000200 def addClass(self, name, base='Object', comment=''):
edisonn@google.comaf3daa02013-06-12 19:07:45 +0000201 if name == 'Object':
edisonn@google.com45327112013-06-13 20:02:29 +0000202 cls = PdfClass(name, '', comment)
edisonn@google.comaf3daa02013-06-12 19:07:45 +0000203 else:
edisonn@google.com45327112013-06-13 20:02:29 +0000204 cls = PdfClass(name, base, comment)
edisonn@google.comf7dd4912013-06-11 23:06:16 +0000205 self.fClasses[name] = cls
edisonn@google.comaf3daa02013-06-12 19:07:45 +0000206 self.fClassesNamesInOrder.append(name)
edisonn@google.com1a191c62013-06-11 21:44:08 +0000207 return cls
208
edisonn@google.comf7dd4912013-06-11 23:06:16 +0000209 def longName(self, name):
edisonn@google.coma2fab9d2013-06-14 19:22:19 +0000210 #return name
211 # TODO(edisonn): we need the long name to nenerate and sort enums, but we can generate them recursively
edisonn@google.comf7dd4912013-06-11 23:06:16 +0000212 ret = ''
213 while name != '':
214 cls = self.fClasses[name]
215 ret = name + ret
216 name = cls.fBase
217
218 return ret
219
220
221 def writeEnum(self, enum, enumToCls):
222 print(' ' + enum + ',')
223 cls = enumToCls[enum]
224 cls.fEnumSubclasses.sort()
225
226 cnt = 0
227 for sub in cls.fEnumSubclasses:
228 self.writeEnum(cls.fEnumSubclasses[cnt], enumToCls)
229 cnt = cnt + 1
230
231 if cnt != 0:
232 print(' ' + cls.fEnumEnd + ',')
edisonn@google.comaf3daa02013-06-12 19:07:45 +0000233
234
235 def writeAsNull(self, cls, enumToCls):
236 print(' virtual SkPdf' + cls.fName +'* as' + cls.fName + '() {return NULL;}')
237 print(' virtual const SkPdf' + cls.fName +'* as' + cls.fName + '() const {return NULL;}')
238 print
239
240 cnt = 0
241 for sub in cls.fEnumSubclasses:
242 self.writeAsNull(enumToCls[cls.fEnumSubclasses[cnt]], enumToCls)
243 cnt = cnt + 1
244
245
246 def writeAsFoo(self, cls, enumToCls):
247 # TODO(edisonn): add a container, with sections, public, private, default, ...
248 # the end code will be grouped
249
250 # me
251 print('public:')
252 print(' virtual SkPdf' + cls.fName +'* as' + cls.fName + '() {return this;}')
253 print(' virtual const SkPdf' + cls.fName +'* as' + cls.fName + '() const {return this;}')
254 print
255
256 if cls.fName == 'Object':
257 cnt = 0
258 for sub in cls.fEnumSubclasses:
259 self.writeAsNull(enumToCls[cls.fEnumSubclasses[cnt]], enumToCls)
260 cnt = cnt + 1
261
262 if cls.fName != 'Object':
263 print('private:')
264 base = self.fClasses[cls.fBase]
265 cnt = 0
266 for sub in base.fEnumSubclasses:
267 if enumToCls[base.fEnumSubclasses[cnt]].fName != cls.fName:
268 self.writeAsNull(enumToCls[base.fEnumSubclasses[cnt]], enumToCls)
269 cnt = cnt + 1
270
271
edisonn@google.comf7dd4912013-06-11 23:06:16 +0000272
edisonn@google.com1a191c62013-06-11 21:44:08 +0000273 def write(self):
edisonn@google.comf7dd4912013-06-11 23:06:16 +0000274 # generate enum
275 enumsRoot = []
276
277 enumToCls = {}
278
279 for name in self.fClasses:
280 cls = self.fClasses[name]
281 enum = self.longName(name)
edisonn@google.comaf3daa02013-06-12 19:07:45 +0000282 cls.fEnum = 'k' + enum + '_SkPdfObjectType'
283 cls.fEnumEnd = 'k' + enum + '__End_SkPdfObjectType'
edisonn@google.comf7dd4912013-06-11 23:06:16 +0000284
285 if cls.fBase != '':
286 self.fClasses[cls.fBase].fEnumSubclasses.append(cls.fEnum)
287
288 if cls.fBase == '':
289 enumsRoot.append(cls.fEnum)
290
291 enumToCls[cls.fEnum] = cls
292
293 enumsRoot.sort()
294
edisonn@google.comaf3daa02013-06-12 19:07:45 +0000295
296 # TODO(edisonn): move each .h in it's own file
297 # write imports
298
edisonn@google.comf7dd4912013-06-11 23:06:16 +0000299 # write enums
edisonn@google.comaf3daa02013-06-12 19:07:45 +0000300 print('enum SkPdfObjectType {')
edisonn@google.comf7dd4912013-06-11 23:06:16 +0000301 for enum in enumsRoot:
302 self.writeEnum(enum, enumToCls)
303 print('};')
edisonn@google.comaf3daa02013-06-12 19:07:45 +0000304 print
305
306 # write forward class declaration
307 for name in self.fClassesNamesInOrder:
308 print('class SkPdf' + name + ';')
309 print
310
311 for name in self.fClassesNamesInOrder:
312 cls = self.fClasses[name]
313 enum = cls.fEnum
edisonn@google.comf7dd4912013-06-11 23:06:16 +0000314
edisonn@google.comaf3daa02013-06-12 19:07:45 +0000315 if cls.fBase == '':
316 print('class SkPdf' + cls.fName + ' {')
317 else:
318 print('class SkPdf' + cls.fName + ' : public SkPdf' + cls.fBase + ' {')
319
320 print('public:')
321 print(' virtual SkPdfObjectType getType() const { return ' + cls.fEnum + ';}')
322 if len(cls.fEnumSubclasses) == 0:
323 print(' virtual SkPdfObjectType getTypeEnd() const { return (SkPdfObjectType)(' + cls.fEnum + ' + 1);}')
324 else:
325 print(' virtual SkPdfObjectType getTypeEnd() const { return ' + cls.fEnumEnd + ';}')
326
327
328 self.writeAsFoo(cls, enumToCls)
329
330 print('public:')
331 for cc in cls.fCCPublic:
332 print(' ' + cc)
333
334 print('private:')
335 for cc in cls.fCCPrivate:
336 print(' ' + cc)
337
338 if cls.fBase == '':
339 print('protected:')
340 print(' const PdfMemDocument* fPodofoDoc;')
341 print(' const PdfObject* fPodofoObj;')
342 print
343 print('public:')
344 print(' SkPdf' + cls.fName + '(const PdfMemDocument* podofoDoc, const PdfObject* podofoObj) : fPodofoDoc(podofoDoc), fPodofoObj(podofoObj) {}')
345 print(' const PdfObject* podofo() const { return fPodofoObj;}')
346 else:
347 print('public:')
edisonn@google.com45327112013-06-13 20:02:29 +0000348 print(' SkPdf' + cls.fName + '(const PdfMemDocument* podofoDoc, const PdfObject* podofoObj) : SkPdf' + cls.fBase + '(podofoDoc, podofoObj) {}')
349 print
edisonn@google.comaf3daa02013-06-12 19:07:45 +0000350
351 #check required fieds, also, there should be an internal_valid() manually wrote for complex
352 # situations
353 # right now valid return true
354 print(' virtual bool valid() const {return true;}')
edisonn@google.com45327112013-06-13 20:02:29 +0000355 print
edisonn@google.comaf3daa02013-06-12 19:07:45 +0000356
357 for field in cls.fFields:
358 prop = field.fProp
359 if prop.fCppName != '':
edisonn@google.coma2fab9d2013-06-14 19:22:19 +0000360 if prop.fCppName[0] == '[':
361 print('/*') # comment code of the atributes that can have any name
362
363 print(' ' + prop.fCppType + ' ' + prop.fCppName + '() const {')
364 print(' ' + prop.fCppType + ' ret;')
365 print(' if (' + prop.fCppReader + '(fPodofoDoc, fPodofoObj->GetDictionary(), \"' + prop.fName + '\", \"' + prop.fAbr + '\", &ret)) return ret;')
366 if field.fRequired == False:
367 print(' return ' + prop.fDefault.toCpp() + ';');
368 if field.fRequired == True:
369 print(' // TODO(edisonn): warn about missing required field, assert for known good pdfs')
370 print(' return ' + field.fBadDefault + ';');
371 print(' }')
372 print
edisonn@google.com45327112013-06-13 20:02:29 +0000373
edisonn@google.coma2fab9d2013-06-14 19:22:19 +0000374 if prop.fCppName[0] == '[':
375 print('*/') # comment code of the atributes that can have any name
edisonn@google.com45327112013-06-13 20:02:29 +0000376
edisonn@google.comaf3daa02013-06-12 19:07:45 +0000377
378 print('};')
379 print
380 print
381
382
383
384 # generate constructor when knowing the type
385 # later, p2, generate constructor when not knowing the type - very similar with parsing?
386
edisonn@google.comf7dd4912013-06-11 23:06:16 +0000387 # generate parser
edisonn@google.comaf3daa02013-06-12 19:07:45 +0000388
389 # TODO(edisonn): fast recognition based on must attributes.
390 print('class PodofoMapper {')
391 print('public:')
392 for name in self.fClassesNamesInOrder:
393 cls = self.fClasses[name]
394
395 print(' static bool map' + name + '(const PdfMemDocument& podofoDoc, const PdfObject& podofoObj, SkPdfObject** out) {')
396 print(' if (!isA' + name + '(podofoDoc, podofoObj)) return false;')
397 print
398
399 for sub in cls.fEnumSubclasses:
400 print(' if (map' + enumToCls[sub].fName + '(podofoDoc, podofoObj, out)) return true;')
401
402 print
403
404 print(' *out = new SkPdf' + name + '(&podofoDoc, &podofoObj);')
405 print(' return true;')
406 print(' }')
407 print
408
409 for name in self.fClassesNamesInOrder:
410 cls = self.fClasses[name]
411
412 print(' static bool isA' + name + '(const PdfMemDocument& podofoDoc, const PdfObject& podofoObj) {')
413
edisonn@google.coma2fab9d2013-06-14 19:22:19 +0000414 if cls.fCheck != '':
415 print(' return ' + cls.fCheck + ';')
edisonn@google.comaf3daa02013-06-12 19:07:45 +0000416 else:
edisonn@google.coma2fab9d2013-06-14 19:22:19 +0000417 cntMust = 0
418 for field in cls.fFields:
419 prop = field.fProp
420 if prop.fHasMust:
421 cntMust = cntMust + 1
422 print(' ' + prop.fCppType + ' ' + prop.fCppName + ';')
423 print(' if (!' + prop.fCppReader + '(&podofoDoc, podofoObj.GetDictionary(), \"' + prop.fName + '\", \"' + prop.fAbr + '\", &' + prop.fCppName + ')) return false;')
424 print(' if (' + prop.fCppName + ' != ' + prop.fMustBe.toCpp() + ') return false;')
425 print
426
427 # hack, we only care about dictionaries now, so ret tru only if there is a match
428 if cntMust != 0 or len(cls.fEnumSubclasses) > 0:
429 print(' return true;')
430 else:
431 print(' return false;')
edisonn@google.comaf3daa02013-06-12 19:07:45 +0000432
433 print(' }')
434 print
435
436 print('};')
437 print
438
edisonn@google.com1a191c62013-06-11 21:44:08 +0000439 return
440
441def generateCode():
edisonn@google.coma2fab9d2013-06-14 19:22:19 +0000442 manager = PdfClassManager()
edisonn@google.com1a191c62013-06-11 21:44:08 +0000443
edisonn@google.coma2fab9d2013-06-14 19:22:19 +0000444 manager.addClass('Object')
edisonn@google.com1a191c62013-06-11 21:44:08 +0000445
edisonn@google.coma2fab9d2013-06-14 19:22:19 +0000446 manager.addClass('Null').check('podofoObj.GetDataType() == ePdfDataType_Null')
447 manager.addClass('Boolean').check('podofoObj.GetDataType() == ePdfDataType_Bool')
448 manager.addClass('Integer').check('podofoObj.GetDataType() == ePdfDataType_Number')
449 manager.addClass('Number').check('podofoObj.GetDataType() == ePdfDataType_Real')
450 manager.addClass('Name').check('podofoObj.GetDataType() == ePdfDataType_Name')
451 #manager.addClass('Stream') - attached to a dictionary
452 manager.addClass('Reference').check('podofoObj.GetDataType() == ePdfDataType_Reference')
453 manager.addClass('Array').check('podofoObj.GetDataType() == ePdfDataType_Array')
454 manager.addClass('String').check('podofoObj.GetDataType() == ePdfDataType_String')
455 manager.addClass('HexString').check('podofoObj.GetDataType() == ePdfDataType_HexString')
456
457 manager.addClass('Dictionary').check('podofoObj.GetDataType() == ePdfDataType_Dictionary')
458
459 # these classes are not explicitely backed by a table in the pdf spec
460 manager.addClass('XObjectDictionary', 'Dictionary')
461
462 manager.addClass('FontDictionary', 'Dictionary')
463
464 manager.addClass('TrueTypeFontDictionary', 'FontDictionary')
465
466 pdfspec_autogen.buildPdfSpec(manager)
edisonn@google.com1a191c62013-06-11 21:44:08 +0000467
edisonn@google.coma2fab9d2013-06-14 19:22:19 +0000468 manager.addClass('MultiMasterFontDictionary', 'Type1FontDictionary')\
469 .required('NULL')\
470 .field('Subtype')\
471 .name('Subtype')\
edisonn@google.com45327112013-06-13 20:02:29 +0000472 .type('name')\
edisonn@google.coma2fab9d2013-06-14 19:22:19 +0000473 .comment('')\
474 .must(datatypes.PdfName('MMType1'))\
edisonn@google.com45327112013-06-13 20:02:29 +0000475 .done().done()\
edisonn@google.com45327112013-06-13 20:02:29 +0000476
477
edisonn@google.coma2fab9d2013-06-14 19:22:19 +0000478 manager.write()
edisonn@google.com1a191c62013-06-11 21:44:08 +0000479
480 return 1
481
482if '__main__' == __name__:
483 sys.exit(generateCode())
edisonn@google.com45327112013-06-13 20:02:29 +0000484
485