edisonn@google.com | 1a191c6 | 2013-06-11 21:44:08 +0000 | [diff] [blame] | 1 | import sys |
| 2 | |
| 3 | class PdfName: |
| 4 | def __init__(self, name, abr=''): |
| 5 | self.fName = name |
| 6 | self.fAbr = abr |
| 7 | |
| 8 | class PdfInteger: |
| 9 | def __init__(self, value): |
| 10 | self.fValue = value |
| 11 | |
| 12 | class PdfReal: |
| 13 | def __init__(self, value): |
| 14 | self.fValue = value |
| 15 | |
| 16 | class PdfString: |
| 17 | def __init__(self, value): |
| 18 | self.fValue = value |
| 19 | |
| 20 | class PdfBoolean: |
| 21 | def __init__(self, value): |
| 22 | self.fValue = value |
| 23 | |
| 24 | class PdfField: |
| 25 | def __init__(self, parent, name, abr): |
| 26 | self.fParent = parent |
| 27 | self.fName = name |
| 28 | self.fAbr = abr |
| 29 | |
| 30 | self.fDefault = '' |
| 31 | self.fType = '' |
| 32 | |
| 33 | def must(self, value): |
| 34 | return self.fParent |
| 35 | |
| 36 | def default(self, value): |
| 37 | self.fDefault = value |
| 38 | return self |
| 39 | |
| 40 | def number(self): |
| 41 | self.fType = 'number' |
| 42 | return self |
| 43 | |
| 44 | def integer(self): |
| 45 | self.fType = 'integer' |
| 46 | return self |
| 47 | |
| 48 | def real(self): |
| 49 | self.fType = 'real' |
| 50 | return self |
| 51 | |
| 52 | def name(self): |
| 53 | self.fType = 'name' |
| 54 | return self |
| 55 | |
| 56 | def string(self): |
| 57 | self.fType = 'string' |
| 58 | return self |
| 59 | |
| 60 | def multiple(self, options): |
| 61 | self.fType = 'multiple' |
| 62 | self.fOptions = options |
| 63 | return self |
| 64 | |
| 65 | def done(self): |
| 66 | return self.fParent |
| 67 | |
| 68 | |
| 69 | class PdfClassField: |
| 70 | def __init__(self, parent, required): |
| 71 | self.fFields = [] |
| 72 | self.fIncludes = [] |
| 73 | self.fCC = [] |
| 74 | self.fParent = parent |
| 75 | self.fRequired = required |
| 76 | |
| 77 | def hasField(self, name, abr=''): |
| 78 | return PdfField(self, name, abr) |
| 79 | |
| 80 | def done(self): |
| 81 | return self.fParent |
| 82 | |
| 83 | class PdfClass: |
| 84 | def __init__(self, name, base): |
| 85 | self.fFields = [] |
| 86 | self.fIncludes = [] |
| 87 | self.fCC = [] |
| 88 | self.fName = name |
| 89 | self.fBase = base |
| 90 | |
edisonn@google.com | f7dd491 | 2013-06-11 23:06:16 +0000 | [diff] [blame^] | 91 | self.fEnumSubclasses = [] |
| 92 | |
| 93 | self.fEnum = '!UNDEFINED' |
| 94 | self.fEnumEnd = '!UNDEFINED' |
| 95 | |
edisonn@google.com | 1a191c6 | 2013-06-11 21:44:08 +0000 | [diff] [blame] | 96 | def required(self): |
| 97 | field = PdfClassField(self, True) |
| 98 | self.fFields.append(field) |
| 99 | return field |
| 100 | |
| 101 | def optional(self): |
| 102 | field = PdfClassField(self, False) |
| 103 | self.fFields.append(field) |
| 104 | return field |
| 105 | |
| 106 | def include(self, path): |
| 107 | self.fIncludes.append(path) |
| 108 | return self |
| 109 | |
| 110 | def carbonCopy(self, cc): |
| 111 | self.fCC.append(cc) |
| 112 | return self |
| 113 | |
| 114 | class PdfClassManager: |
| 115 | def __init__(self): |
edisonn@google.com | f7dd491 | 2013-06-11 23:06:16 +0000 | [diff] [blame^] | 116 | self.fClasses = {} |
edisonn@google.com | 1a191c6 | 2013-06-11 21:44:08 +0000 | [diff] [blame] | 117 | |
| 118 | def addClass(self, name, base=''): |
| 119 | cls = PdfClass(name, base) |
edisonn@google.com | f7dd491 | 2013-06-11 23:06:16 +0000 | [diff] [blame^] | 120 | self.fClasses[name] = cls |
edisonn@google.com | 1a191c6 | 2013-06-11 21:44:08 +0000 | [diff] [blame] | 121 | return cls |
| 122 | |
edisonn@google.com | f7dd491 | 2013-06-11 23:06:16 +0000 | [diff] [blame^] | 123 | def longName(self, name): |
| 124 | ret = '' |
| 125 | while name != '': |
| 126 | cls = self.fClasses[name] |
| 127 | ret = name + ret |
| 128 | name = cls.fBase |
| 129 | |
| 130 | return ret |
| 131 | |
| 132 | |
| 133 | def writeEnum(self, enum, enumToCls): |
| 134 | print(' ' + enum + ',') |
| 135 | cls = enumToCls[enum] |
| 136 | cls.fEnumSubclasses.sort() |
| 137 | |
| 138 | cnt = 0 |
| 139 | for sub in cls.fEnumSubclasses: |
| 140 | self.writeEnum(cls.fEnumSubclasses[cnt], enumToCls) |
| 141 | cnt = cnt + 1 |
| 142 | |
| 143 | if cnt != 0: |
| 144 | print(' ' + cls.fEnumEnd + ',') |
| 145 | |
edisonn@google.com | 1a191c6 | 2013-06-11 21:44:08 +0000 | [diff] [blame] | 146 | def write(self): |
edisonn@google.com | f7dd491 | 2013-06-11 23:06:16 +0000 | [diff] [blame^] | 147 | # generate enum |
| 148 | enumsRoot = [] |
| 149 | |
| 150 | enumToCls = {} |
| 151 | |
| 152 | for name in self.fClasses: |
| 153 | cls = self.fClasses[name] |
| 154 | enum = self.longName(name) |
| 155 | cls.fEnum = 'k' + enum + '_PdfObjectType' |
| 156 | cls.fEnumEnd = 'k' + enum + '__End_PdfObjectType' |
| 157 | |
| 158 | if cls.fBase != '': |
| 159 | self.fClasses[cls.fBase].fEnumSubclasses.append(cls.fEnum) |
| 160 | |
| 161 | if cls.fBase == '': |
| 162 | enumsRoot.append(cls.fEnum) |
| 163 | |
| 164 | enumToCls[cls.fEnum] = cls |
| 165 | |
| 166 | enumsRoot.sort() |
| 167 | |
| 168 | # write enums |
| 169 | print('enum PdfObjectType {') |
| 170 | for enum in enumsRoot: |
| 171 | self.writeEnum(enum, enumToCls) |
| 172 | print('};') |
| 173 | |
| 174 | # generate each class |
| 175 | # generate parser |
edisonn@google.com | 1a191c6 | 2013-06-11 21:44:08 +0000 | [diff] [blame] | 176 | return |
| 177 | |
| 178 | def generateCode(): |
| 179 | all = PdfClassManager() |
| 180 | |
| 181 | all.addClass('Object') |
| 182 | all.addClass('Null') |
| 183 | all.addClass('Boolean') |
| 184 | all.addClass('Integer') |
| 185 | all.addClass('Real') |
| 186 | all.addClass('Name') |
| 187 | all.addClass('Stream') |
| 188 | all.addClass('Reference') |
| 189 | all.addClass('Array') |
| 190 | all.addClass('Dictionary') |
| 191 | |
| 192 | all.addClass('XObject', 'Dictionary').required().hasField('/Type').must('/XObject') |
| 193 | |
| 194 | all.addClass('Image', 'XObject').required().hasField('/Type').must('/XObject').done()\ |
| 195 | .required().hasField('/Subtype').must('/Image').done()\ |
| 196 | .required().hasField('/Width', '/W').integer().done().done()\ |
| 197 | .required().hasField('/Height', '/H').integer().done().done()\ |
| 198 | .required().hasField('/ColorSpace').multiple([PdfName('/DeviceRGB', '/RGB'), PdfName('/DeviceGray', '/Gray')])\ |
| 199 | .done()\ |
| 200 | .done()\ |
| 201 | .optional().hasField('/BitsPerComponent', '/BPC').multiple([PdfInteger(1), PdfInteger(2), PdfInteger(4), PdfInteger(8)])\ |
| 202 | .default(PdfInteger(1))\ |
| 203 | .done().done()\ |
| 204 | .carbonCopy('SkBitmap bitmap;') |
| 205 | |
| 206 | all.addClass('Form', 'XObject').required().hasField('/Type').must('/XObject').done()\ |
| 207 | .required().hasField('/Subtype').must('/Form').done() |
| 208 | |
| 209 | |
| 210 | all.write() |
| 211 | |
| 212 | return 1 |
| 213 | |
| 214 | if '__main__' == __name__: |
| 215 | sys.exit(generateCode()) |