diff options
| author | jvoisin | 2015-12-02 17:07:19 +0100 |
|---|---|---|
| committer | jvoisin | 2015-12-02 17:22:45 +0100 |
| commit | 80ece3001895ea13d50915a5215fd47e313bab4c (patch) | |
| tree | c5ede43867c5d7fe2af4178b34b0e6dc219f6aac /libmat/hachoir_editor | |
| parent | 3cf80e8b5d6faf410e9ad3aad77f23cf6418a587 (diff) | |
Remove hachoir from MAT.
This (huge) commit removes completely hachoir from MAT.
Audio files are now processed with mutagen, and images
with exiftool, since the main python imaging library (PIL)
isn't super-great to deal with metadata (and damaged/non-standard
files).
Package maintainer should change the dependencies to reflect this.
Diffstat (limited to 'libmat/hachoir_editor')
| -rw-r--r-- | libmat/hachoir_editor/__init__.py | 8 | ||||
| -rw-r--r-- | libmat/hachoir_editor/field.py | 69 | ||||
| -rw-r--r-- | libmat/hachoir_editor/fieldset.py | 352 | ||||
| -rw-r--r-- | libmat/hachoir_editor/typed_field.py | 268 |
4 files changed, 0 insertions, 697 deletions
diff --git a/libmat/hachoir_editor/__init__.py b/libmat/hachoir_editor/__init__.py deleted file mode 100644 index 1835676..0000000 --- a/libmat/hachoir_editor/__init__.py +++ /dev/null | |||
| @@ -1,8 +0,0 @@ | |||
| 1 | from field import ( | ||
| 2 | EditorError, FakeField) | ||
| 3 | from typed_field import ( | ||
| 4 | EditableField, EditableBits, EditableBytes, | ||
| 5 | EditableInteger, EditableString, | ||
| 6 | createEditableField) | ||
| 7 | from fieldset import EditableFieldSet, NewFieldSet, createEditor | ||
| 8 | |||
diff --git a/libmat/hachoir_editor/field.py b/libmat/hachoir_editor/field.py deleted file mode 100644 index 6b1efe3..0000000 --- a/libmat/hachoir_editor/field.py +++ /dev/null | |||
| @@ -1,69 +0,0 @@ | |||
| 1 | from hachoir_core.error import HachoirError | ||
| 2 | from hachoir_core.field import joinPath, MissingField | ||
| 3 | |||
| 4 | class EditorError(HachoirError): | ||
| 5 | pass | ||
| 6 | |||
| 7 | class FakeField(object): | ||
| 8 | """ | ||
| 9 | This class have API looks similar to Field API, but objects don't contain | ||
| 10 | any value: all values are _computed_ by parent methods. | ||
| 11 | |||
| 12 | Example: FakeField(editor, "abc").size calls editor._getFieldSize("abc"). | ||
| 13 | """ | ||
| 14 | is_field_set = False | ||
| 15 | |||
| 16 | def __init__(self, parent, name): | ||
| 17 | self._parent = parent | ||
| 18 | self._name = name | ||
| 19 | |||
| 20 | def _getPath(self): | ||
| 21 | return joinPath(self._parent.path, self._name) | ||
| 22 | path = property(_getPath) | ||
| 23 | |||
| 24 | def _getName(self): | ||
| 25 | return self._name | ||
| 26 | name = property(_getName) | ||
| 27 | |||
| 28 | def _getAddress(self): | ||
| 29 | return self._parent._getFieldAddress(self._name) | ||
| 30 | address = property(_getAddress) | ||
| 31 | |||
| 32 | def _getSize(self): | ||
| 33 | return self._parent.input[self._name].size | ||
| 34 | size = property(_getSize) | ||
| 35 | |||
| 36 | def _getValue(self): | ||
| 37 | return self._parent.input[self._name].value | ||
| 38 | value = property(_getValue) | ||
| 39 | |||
| 40 | def createDisplay(self): | ||
| 41 | # TODO: Returns new value if field is altered | ||
| 42 | return self._parent.input[self._name].display | ||
| 43 | display = property(createDisplay) | ||
| 44 | |||
| 45 | def _getParent(self): | ||
| 46 | return self._parent | ||
| 47 | parent = property(_getParent) | ||
| 48 | |||
| 49 | def hasValue(self): | ||
| 50 | return self._parent.input[self._name].hasValue() | ||
| 51 | |||
| 52 | def __getitem__(self, key): | ||
| 53 | # TODO: Implement this function! | ||
| 54 | raise MissingField(self, key) | ||
| 55 | |||
| 56 | def _isAltered(self): | ||
| 57 | return False | ||
| 58 | is_altered = property(_isAltered) | ||
| 59 | |||
| 60 | def writeInto(self, output): | ||
| 61 | size = self.size | ||
| 62 | addr = self._parent._getFieldInputAddress(self._name) | ||
| 63 | input = self._parent.input | ||
| 64 | stream = input.stream | ||
| 65 | if size % 8: | ||
| 66 | output.copyBitsFrom(stream, addr, size, input.endian) | ||
| 67 | else: | ||
| 68 | output.copyBytesFrom(stream, addr, size//8) | ||
| 69 | |||
diff --git a/libmat/hachoir_editor/fieldset.py b/libmat/hachoir_editor/fieldset.py deleted file mode 100644 index b7c9b07..0000000 --- a/libmat/hachoir_editor/fieldset.py +++ /dev/null | |||
| @@ -1,352 +0,0 @@ | |||
| 1 | from hachoir_core.dict import UniqKeyError | ||
| 2 | from hachoir_core.field import MissingField, Float32, Float64, FakeArray | ||
| 3 | from hachoir_core.compatibility import any | ||
| 4 | from hachoir_core.i18n import _ | ||
| 5 | from typed_field import createEditableField | ||
| 6 | from field import EditorError | ||
| 7 | from collections import deque # Python 2.4 | ||
| 8 | import weakref # Python 2.1 | ||
| 9 | import struct | ||
| 10 | |||
| 11 | class EditableFieldSet(object): | ||
| 12 | MAX_SIZE = (1 << 40) # Arbitrary limit to catch errors | ||
| 13 | is_field_set = True | ||
| 14 | |||
| 15 | def __init__(self, parent, fieldset): | ||
| 16 | self._parent = parent | ||
| 17 | self.input = fieldset # original FieldSet | ||
| 18 | self._fields = {} # cache of editable fields | ||
| 19 | self._deleted = set() # Names of deleted fields | ||
| 20 | self._inserted = {} # Inserted field (name => list of field, | ||
| 21 | # where name is the name after) | ||
| 22 | |||
| 23 | def array(self, key): | ||
| 24 | # FIXME: Use cache? | ||
| 25 | return FakeArray(self, key) | ||
| 26 | |||
| 27 | def _getParent(self): | ||
| 28 | return self._parent | ||
| 29 | parent = property(_getParent) | ||
| 30 | |||
| 31 | def _isAltered(self): | ||
| 32 | if self._inserted: | ||
| 33 | return True | ||
| 34 | if self._deleted: | ||
| 35 | return True | ||
| 36 | return any(field.is_altered for field in self._fields.itervalues()) | ||
| 37 | is_altered = property(_isAltered) | ||
| 38 | |||
| 39 | def reset(self): | ||
| 40 | """ | ||
| 41 | Reset the field set and the input field set. | ||
| 42 | """ | ||
| 43 | for key, field in self._fields.iteritems(): | ||
| 44 | if not field.is_altered: | ||
| 45 | del self._fields[key] | ||
| 46 | self.input.reset() | ||
| 47 | |||
| 48 | def __len__(self): | ||
| 49 | return len(self.input) \ | ||
| 50 | - len(self._deleted) \ | ||
| 51 | + sum( len(new) for new in self._inserted.itervalues() ) | ||
| 52 | |||
| 53 | def __iter__(self): | ||
| 54 | for field in self.input: | ||
| 55 | name = field.name | ||
| 56 | if name in self._inserted: | ||
| 57 | for newfield in self._inserted[name]: | ||
| 58 | yield weakref.proxy(newfield) | ||
| 59 | if name not in self._deleted: | ||
| 60 | yield self[name] | ||
| 61 | if None in self._inserted: | ||
| 62 | for newfield in self._inserted[None]: | ||
| 63 | yield weakref.proxy(newfield) | ||
| 64 | |||
| 65 | def insertBefore(self, name, *new_fields): | ||
| 66 | self._insert(name, new_fields, False) | ||
| 67 | |||
| 68 | def insertAfter(self, name, *new_fields): | ||
| 69 | self._insert(name, new_fields, True) | ||
| 70 | |||
| 71 | def insert(self, *new_fields): | ||
| 72 | self._insert(None, new_fields, True) | ||
| 73 | |||
| 74 | def _insert(self, key, new_fields, next): | ||
| 75 | """ | ||
| 76 | key is the name of the field before which new_fields | ||
| 77 | will be inserted. If next is True, the fields will be inserted | ||
| 78 | _after_ this field. | ||
| 79 | """ | ||
| 80 | # Set unique field name | ||
| 81 | for field in new_fields: | ||
| 82 | if field._name.endswith("[]"): | ||
| 83 | self.input.setUniqueFieldName(field) | ||
| 84 | |||
| 85 | # Check that there is no duplicate in inserted fields | ||
| 86 | new_names = list(field.name for field in new_fields) | ||
| 87 | names_set = set(new_names) | ||
| 88 | if len(names_set) != len(new_fields): | ||
| 89 | duplicates = (name for name in names_set if 1 < new_names.count(name)) | ||
| 90 | raise UniqKeyError(_("Duplicates in inserted fields: %s") % ", ".join(duplicates)) | ||
| 91 | |||
| 92 | # Check that field names are not in input | ||
| 93 | if self.input: # Write special version for NewFieldSet? | ||
| 94 | for name in new_names: | ||
| 95 | if name in self.input and name not in self._deleted: | ||
| 96 | raise UniqKeyError(_("Field name '%s' already exists") % name) | ||
| 97 | |||
| 98 | # Check that field names are not in inserted fields | ||
| 99 | for fields in self._inserted.itervalues(): | ||
| 100 | for field in fields: | ||
| 101 | if field.name in new_names: | ||
| 102 | raise UniqKeyError(_("Field name '%s' already exists") % field.name) | ||
| 103 | |||
| 104 | # Input have already inserted field? | ||
| 105 | if key in self._inserted: | ||
| 106 | if next: | ||
| 107 | self._inserted[key].extend( reversed(new_fields) ) | ||
| 108 | else: | ||
| 109 | self._inserted[key].extendleft( reversed(new_fields) ) | ||
| 110 | return | ||
| 111 | |||
| 112 | # Whould like to insert in inserted fields? | ||
| 113 | if key: | ||
| 114 | for fields in self._inserted.itervalues(): | ||
| 115 | names = [item.name for item in fields] | ||
| 116 | try: | ||
| 117 | pos = names.index(key) | ||
| 118 | except ValueError: | ||
| 119 | continue | ||
| 120 | if 0 <= pos: | ||
| 121 | if next: | ||
| 122 | pos += 1 | ||
| 123 | fields.rotate(-pos) | ||
| 124 | fields.extendleft( reversed(new_fields) ) | ||
| 125 | fields.rotate(pos) | ||
| 126 | return | ||
| 127 | |||
| 128 | # Get next field. Use None if we are at the end. | ||
| 129 | if next: | ||
| 130 | index = self.input[key].index + 1 | ||
| 131 | try: | ||
| 132 | key = self.input[index].name | ||
| 133 | except IndexError: | ||
| 134 | key = None | ||
| 135 | |||
| 136 | # Check that field names are not in input | ||
| 137 | if key not in self.input: | ||
| 138 | raise MissingField(self, key) | ||
| 139 | |||
| 140 | # Insert in original input | ||
| 141 | self._inserted[key]= deque(new_fields) | ||
| 142 | |||
| 143 | def _getDescription(self): | ||
| 144 | return self.input.description | ||
| 145 | description = property(_getDescription) | ||
| 146 | |||
| 147 | def _getStream(self): | ||
| 148 | # FIXME: This property is maybe a bad idea since address may be differents | ||
| 149 | return self.input.stream | ||
| 150 | stream = property(_getStream) | ||
| 151 | |||
| 152 | def _getName(self): | ||
| 153 | return self.input.name | ||
| 154 | name = property(_getName) | ||
| 155 | |||
| 156 | def _getEndian(self): | ||
| 157 | return self.input.endian | ||
| 158 | endian = property(_getEndian) | ||
| 159 | |||
| 160 | def _getAddress(self): | ||
| 161 | if self._parent: | ||
| 162 | return self._parent._getFieldAddress(self.name) | ||
| 163 | else: | ||
| 164 | return 0 | ||
| 165 | address = property(_getAddress) | ||
| 166 | |||
| 167 | def _getAbsoluteAddress(self): | ||
| 168 | address = self.address | ||
| 169 | current = self._parent | ||
| 170 | while current: | ||
| 171 | address += current.address | ||
| 172 | current = current._parent | ||
| 173 | return address | ||
| 174 | absolute_address = property(_getAbsoluteAddress) | ||
| 175 | |||
| 176 | def hasValue(self): | ||
| 177 | return False | ||
| 178 | # return self._parent.input[self.name].hasValue() | ||
| 179 | |||
| 180 | def _getSize(self): | ||
| 181 | if self.is_altered: | ||
| 182 | return sum(field.size for field in self) | ||
| 183 | else: | ||
| 184 | return self.input.size | ||
| 185 | size = property(_getSize) | ||
| 186 | |||
| 187 | def _getPath(self): | ||
| 188 | return self.input.path | ||
| 189 | path = property(_getPath) | ||
| 190 | |||
| 191 | def _getOriginalField(self, name): | ||
| 192 | assert name in self.input | ||
| 193 | return self.input[name] | ||
| 194 | |||
| 195 | def _getFieldInputAddress(self, name): | ||
| 196 | """ | ||
| 197 | Absolute address of a field from the input field set. | ||
| 198 | """ | ||
| 199 | assert name in self.input | ||
| 200 | return self.input[name].absolute_address | ||
| 201 | |||
| 202 | def _getFieldAddress(self, name): | ||
| 203 | """ | ||
| 204 | Compute relative address of a field. The operation takes care of | ||
| 205 | deleted and resized fields. | ||
| 206 | """ | ||
| 207 | #assert name not in self._deleted | ||
| 208 | addr = 0 | ||
| 209 | for field in self: | ||
| 210 | if field.name == name: | ||
| 211 | return addr | ||
| 212 | addr += field.size | ||
| 213 | raise MissingField(self, name) | ||
| 214 | |||
| 215 | def _getItemByPath(self, path): | ||
| 216 | if not path[0]: | ||
| 217 | path = path[1:] | ||
| 218 | field = self | ||
| 219 | for name in path: | ||
| 220 | field = field[name] | ||
| 221 | return field | ||
| 222 | |||
| 223 | def __contains__(self, name): | ||
| 224 | try: | ||
| 225 | field = self[name] | ||
| 226 | return (field is not None) | ||
| 227 | except MissingField: | ||
| 228 | return False | ||
| 229 | |||
| 230 | def __getitem__(self, key): | ||
| 231 | """ | ||
| 232 | Create a weak reference to an editable field (EditableField) for the | ||
| 233 | field with specified name. If the field is removed later, using the | ||
| 234 | editable field will raise a weakref.ReferenceError exception. | ||
| 235 | |||
| 236 | May raise a MissingField error if the field doesn't exist in original | ||
| 237 | field set or it has been deleted. | ||
| 238 | """ | ||
| 239 | if "/" in key: | ||
| 240 | return self._getItemByPath(key.split("/")) | ||
| 241 | if isinstance(key, (int, long)): | ||
| 242 | raise EditorError("Integer index are not supported") | ||
| 243 | |||
| 244 | if (key in self._deleted) or (key not in self.input): | ||
| 245 | raise MissingField(self, key) | ||
| 246 | if key not in self._fields: | ||
| 247 | field = self.input[key] | ||
| 248 | if field.is_field_set: | ||
| 249 | self._fields[key] = createEditableFieldSet(self, field) | ||
| 250 | else: | ||
| 251 | self._fields[key] = createEditableField(self, field) | ||
| 252 | return weakref.proxy(self._fields[key]) | ||
| 253 | |||
| 254 | def __delitem__(self, name): | ||
| 255 | """ | ||
| 256 | Remove a field from the field set. May raise an MissingField exception | ||
| 257 | if the field has already been deleted. | ||
| 258 | """ | ||
| 259 | parts = name.partition('/') | ||
| 260 | if parts[2]: | ||
| 261 | fieldset = self[parts[0]] | ||
| 262 | del fieldset[parts[2]] | ||
| 263 | return | ||
| 264 | if name in self._deleted: | ||
| 265 | raise MissingField(self, name) | ||
| 266 | self._deleted.add(name) | ||
| 267 | if name in self._fields: | ||
| 268 | del self._fields[name] | ||
| 269 | |||
| 270 | def writeInto(self, output): | ||
| 271 | """ | ||
| 272 | Write the content if this field set into the output stream | ||
| 273 | (OutputStream). | ||
| 274 | """ | ||
| 275 | if not self.is_altered: | ||
| 276 | # Not altered: just copy bits/bytes | ||
| 277 | input = self.input | ||
| 278 | if input.size % 8: | ||
| 279 | output.copyBitsFrom(input.stream, | ||
| 280 | input.absolute_address, input.size, input.endian) | ||
| 281 | else: | ||
| 282 | output.copyBytesFrom(input.stream, | ||
| 283 | input.absolute_address, input.size//8) | ||
| 284 | else: | ||
| 285 | # Altered: call writeInto() method of each field | ||
| 286 | realaddr = 0 | ||
| 287 | for field in self: | ||
| 288 | field.writeInto(output) | ||
| 289 | realaddr += field.size | ||
| 290 | |||
| 291 | def _getValue(self): | ||
| 292 | raise EditorError('Field set "%s" has no value' % self.path) | ||
| 293 | def _setValue(self, value): | ||
| 294 | raise EditorError('Field set "%s" value is read only' % self.path) | ||
| 295 | value = property(_getValue, _setValue, "Value of field") | ||
| 296 | |||
| 297 | class EditableFloat(EditableFieldSet): | ||
| 298 | _value = None | ||
| 299 | |||
| 300 | def _isAltered(self): | ||
| 301 | return (self._value is not None) | ||
| 302 | is_altered = property(_isAltered) | ||
| 303 | |||
| 304 | def writeInto(self, output): | ||
| 305 | if self._value is not None: | ||
| 306 | self._write(output) | ||
| 307 | else: | ||
| 308 | EditableFieldSet.writeInto(self, output) | ||
| 309 | |||
| 310 | def _write(self, output): | ||
| 311 | format = self.input.struct_format | ||
| 312 | raw = struct.pack(format, self._value) | ||
| 313 | output.writeBytes(raw) | ||
| 314 | |||
| 315 | def _setValue(self, value): | ||
| 316 | self.parent._is_altered = True | ||
| 317 | self._value = value | ||
| 318 | value = property(EditableFieldSet._getValue, _setValue) | ||
| 319 | |||
| 320 | def createEditableFieldSet(parent, field): | ||
| 321 | cls = field.__class__ | ||
| 322 | # FIXME: Support Float80 | ||
| 323 | if cls in (Float32, Float64): | ||
| 324 | return EditableFloat(parent, field) | ||
| 325 | else: | ||
| 326 | return EditableFieldSet(parent, field) | ||
| 327 | |||
| 328 | class NewFieldSet(EditableFieldSet): | ||
| 329 | def __init__(self, parent, name): | ||
| 330 | EditableFieldSet.__init__(self, parent, None) | ||
| 331 | self._name = name | ||
| 332 | self._endian = parent.endian | ||
| 333 | |||
| 334 | def __iter__(self): | ||
| 335 | if None in self._inserted: | ||
| 336 | return iter(self._inserted[None]) | ||
| 337 | else: | ||
| 338 | raise StopIteration() | ||
| 339 | |||
| 340 | def _getName(self): | ||
| 341 | return self._name | ||
| 342 | name = property(_getName) | ||
| 343 | |||
| 344 | def _getEndian(self): | ||
| 345 | return self._endian | ||
| 346 | endian = property(_getEndian) | ||
| 347 | |||
| 348 | is_altered = property(lambda self: True) | ||
| 349 | |||
| 350 | def createEditor(fieldset): | ||
| 351 | return EditableFieldSet(None, fieldset) | ||
| 352 | |||
diff --git a/libmat/hachoir_editor/typed_field.py b/libmat/hachoir_editor/typed_field.py deleted file mode 100644 index 606d39b..0000000 --- a/libmat/hachoir_editor/typed_field.py +++ /dev/null | |||
| @@ -1,268 +0,0 @@ | |||
| 1 | from hachoir_core.field import ( | ||
| 2 | RawBits, Bit, Bits, PaddingBits, | ||
| 3 | RawBytes, Bytes, PaddingBytes, | ||
| 4 | GenericString, Character, | ||
| 5 | isInteger, isString) | ||
| 6 | from field import FakeField | ||
| 7 | |||
| 8 | |||
| 9 | class EditableField(FakeField): | ||
| 10 | """ | ||
| 11 | Pure virtual class used to write editable field class. | ||
| 12 | """ | ||
| 13 | |||
| 14 | _is_altered = False | ||
| 15 | |||
| 16 | def __init__(self, parent, name, value=None): | ||
| 17 | FakeField.__init__(self, parent, name) | ||
| 18 | self._value = value | ||
| 19 | |||
| 20 | def _isAltered(self): | ||
| 21 | return self._is_altered | ||
| 22 | |||
| 23 | is_altered = property(_isAltered) | ||
| 24 | |||
| 25 | def hasValue(self): | ||
| 26 | return True | ||
| 27 | |||
| 28 | def _computeSize(self): | ||
| 29 | raise NotImplementedError() | ||
| 30 | |||
| 31 | def _getValue(self): | ||
| 32 | return self._value | ||
| 33 | |||
| 34 | def _setValue(self, value): | ||
| 35 | self._value = value | ||
| 36 | |||
| 37 | def _propGetValue(self): | ||
| 38 | if self._value is not None: | ||
| 39 | return self._getValue() | ||
| 40 | else: | ||
| 41 | return FakeField._getValue(self) | ||
| 42 | |||
| 43 | def _propSetValue(self, value): | ||
| 44 | self._setValue(value) | ||
| 45 | self._is_altered = True | ||
| 46 | |||
| 47 | value = property(_propGetValue, _propSetValue) | ||
| 48 | |||
| 49 | def _getSize(self): | ||
| 50 | if self._value is not None: | ||
| 51 | return self._computeSize() | ||
| 52 | else: | ||
| 53 | return FakeField._getSize(self) | ||
| 54 | |||
| 55 | size = property(_getSize) | ||
| 56 | |||
| 57 | def _write(self, output): | ||
| 58 | raise NotImplementedError() | ||
| 59 | |||
| 60 | def writeInto(self, output): | ||
| 61 | if self._is_altered: | ||
| 62 | self._write(output) | ||
| 63 | else: | ||
| 64 | return FakeField.writeInto(self, output) | ||
| 65 | |||
| 66 | |||
| 67 | class EditableFixedField(EditableField): | ||
| 68 | """ | ||
| 69 | Editable field with fixed size. | ||
| 70 | """ | ||
| 71 | |||
| 72 | def __init__(self, parent, name, value=None, size=None): | ||
| 73 | EditableField.__init__(self, parent, name, value) | ||
| 74 | if size is not None: | ||
| 75 | self._size = size | ||
| 76 | else: | ||
| 77 | self._size = self._parent._getOriginalField(self._name).size | ||
| 78 | |||
| 79 | def _getSize(self): | ||
| 80 | return self._size | ||
| 81 | |||
| 82 | size = property(_getSize) | ||
| 83 | |||
| 84 | |||
| 85 | class EditableBits(EditableFixedField): | ||
| 86 | def __init__(self, parent, name, *args): | ||
| 87 | if args: | ||
| 88 | if len(args) != 2: | ||
| 89 | raise TypeError( | ||
| 90 | "Wrong argument count, EditableBits constructor prototype is: " | ||
| 91 | "(parent, name, [size, value])") | ||
| 92 | size = args[0] | ||
| 93 | value = args[1] | ||
| 94 | assert isinstance(value, (int, long)) | ||
| 95 | else: | ||
| 96 | size = None | ||
| 97 | value = None | ||
| 98 | EditableFixedField.__init__(self, parent, name, value, size) | ||
| 99 | if args: | ||
| 100 | self._setValue(args[1]) | ||
| 101 | self._is_altered = True | ||
| 102 | |||
| 103 | def _setValue(self, value): | ||
| 104 | if not (0 <= value < (1 << self._size)): | ||
| 105 | raise ValueError("Invalid value, must be in range %s..%s" | ||
| 106 | % (0, (1 << self._size) - 1)) | ||
| 107 | self._value = value | ||
| 108 | |||
| 109 | def _write(self, output): | ||
| 110 | output.writeBits(self._size, self._value, self._parent.endian) | ||
| 111 | |||
| 112 | |||
| 113 | class EditableBytes(EditableField): | ||
| 114 | def _setValue(self, value): | ||
| 115 | if not value: raise ValueError( | ||
| 116 | "Unable to set empty string to a EditableBytes field") | ||
| 117 | self._value = value | ||
| 118 | |||
| 119 | def _computeSize(self): | ||
| 120 | return len(self._value) * 8 | ||
| 121 | |||
| 122 | def _write(self, output): | ||
| 123 | output.writeBytes(self._value) | ||
| 124 | |||
| 125 | |||
| 126 | class EditableString(EditableField): | ||
| 127 | MAX_SIZE = { | ||
| 128 | "Pascal8": (1 << 8) - 1, | ||
| 129 | "Pascal16": (1 << 16) - 1, | ||
| 130 | "Pascal32": (1 << 32) - 1, | ||
| 131 | } | ||
| 132 | |||
| 133 | def __init__(self, parent, name, *args, **kw): | ||
| 134 | if len(args) == 2: | ||
| 135 | value = args[1] | ||
| 136 | assert isinstance(value, str) # TODO: support Unicode | ||
| 137 | elif not args: | ||
| 138 | value = None | ||
| 139 | else: | ||
| 140 | raise TypeError( | ||
| 141 | "Wrong argument count, EditableString constructor prototype is:" | ||
| 142 | "(parent, name, [format, value])") | ||
| 143 | EditableField.__init__(self, parent, name, value) | ||
| 144 | if len(args) == 2: | ||
| 145 | self._charset = kw.get('charset', None) | ||
| 146 | self._format = args[0] | ||
| 147 | if self._format in GenericString.PASCAL_FORMATS: | ||
| 148 | self._prefix_size = GenericString.PASCAL_FORMATS[self._format] | ||
| 149 | else: | ||
| 150 | self._prefix_size = 0 | ||
| 151 | self._suffix_str = GenericString.staticSuffixStr( | ||
| 152 | self._format, self._charset, self._parent.endian) | ||
| 153 | self._is_altered = True | ||
| 154 | else: | ||
| 155 | orig = self._parent._getOriginalField(name) | ||
| 156 | self._charset = orig.charset | ||
| 157 | self._format = orig.format | ||
| 158 | self._prefix_size = orig.content_offset | ||
| 159 | self._suffix_str = orig.suffix_str | ||
| 160 | |||
| 161 | def _setValue(self, value): | ||
| 162 | size = len(value) | ||
| 163 | if self._format in self.MAX_SIZE and self.MAX_SIZE[self._format] < size: | ||
| 164 | raise ValueError("String is too big") | ||
| 165 | self._value = value | ||
| 166 | |||
| 167 | def _computeSize(self): | ||
| 168 | return (self._prefix_size + len(self._value) + len(self._suffix_str)) * 8 | ||
| 169 | |||
| 170 | def _write(self, output): | ||
| 171 | if self._format in GenericString.SUFFIX_FORMAT: | ||
| 172 | output.writeBytes(self._value) | ||
| 173 | output.writeBytes(self._suffix_str) | ||
| 174 | elif self._format == "fixed": | ||
| 175 | output.writeBytes(self._value) | ||
| 176 | else: | ||
| 177 | assert self._format in GenericString.PASCAL_FORMATS | ||
| 178 | size = GenericString.PASCAL_FORMATS[self._format] | ||
| 179 | output.writeInteger(len(self._value), False, size, self._parent.endian) | ||
| 180 | output.writeBytes(self._value) | ||
| 181 | |||
| 182 | |||
| 183 | class EditableCharacter(EditableFixedField): | ||
| 184 | def __init__(self, parent, name, *args): | ||
| 185 | if args: | ||
| 186 | if len(args) != 3: | ||
| 187 | raise TypeError( | ||
| 188 | "Wrong argument count, EditableCharacter " | ||
| 189 | "constructor prototype is: (parent, name, [value])") | ||
| 190 | value = args[0] | ||
| 191 | if not isinstance(value, str) or len(value) != 1: | ||
| 192 | raise TypeError("EditableCharacter needs a character") | ||
| 193 | else: | ||
| 194 | value = None | ||
| 195 | EditableFixedField.__init__(self, parent, name, value, 8) | ||
| 196 | if args: | ||
| 197 | self._is_altered = True | ||
| 198 | |||
| 199 | def _setValue(self, value): | ||
| 200 | if not isinstance(value, str) or len(value) != 1: | ||
| 201 | raise TypeError("EditableCharacter needs a character") | ||
| 202 | self._value = value | ||
| 203 | |||
| 204 | def _write(self, output): | ||
| 205 | output.writeBytes(self._value) | ||
| 206 | |||
| 207 | |||
| 208 | class EditableInteger(EditableFixedField): | ||
| 209 | VALID_VALUE_SIGNED = { | ||
| 210 | 8: (-(1 << 8), (1 << 8) - 1), | ||
| 211 | 16: (-(1 << 15), (1 << 15) - 1), | ||
| 212 | 32: (-(1 << 31), (1 << 31) - 1), | ||
| 213 | } | ||
| 214 | VALID_VALUE_UNSIGNED = { | ||
| 215 | 8: (0, (1 << 8) - 1), | ||
| 216 | 16: (0, (1 << 16) - 1), | ||
| 217 | 32: (0, (1 << 32) - 1) | ||
| 218 | } | ||
| 219 | |||
| 220 | def __init__(self, parent, name, *args): | ||
| 221 | if args: | ||
| 222 | if len(args) != 3: | ||
| 223 | raise TypeError( | ||
| 224 | "Wrong argument count, EditableInteger constructor prototype is: " | ||
| 225 | "(parent, name, [signed, size, value])") | ||
| 226 | size = args[1] | ||
| 227 | value = args[2] | ||
| 228 | assert isinstance(value, (int, long)) | ||
| 229 | else: | ||
| 230 | size = None | ||
| 231 | value = None | ||
| 232 | EditableFixedField.__init__(self, parent, name, value, size) | ||
| 233 | if args: | ||
| 234 | self._signed = args[0] | ||
| 235 | self._is_altered = True | ||
| 236 | else: | ||
| 237 | self._signed = self._parent._getOriginalField(self._name).signed | ||
| 238 | |||
| 239 | def _setValue(self, value): | ||
| 240 | if self._signed: | ||
| 241 | valid = self.VALID_VALUE_SIGNED | ||
| 242 | else: | ||
| 243 | valid = self.VALID_VALUE_UNSIGNED | ||
| 244 | minval, maxval = valid[self._size] | ||
| 245 | if not (minval <= value <= maxval): | ||
| 246 | raise ValueError("Invalid value, must be in range %s..%s" | ||
| 247 | % (minval, maxval)) | ||
| 248 | self._value = value | ||
| 249 | |||
| 250 | def _write(self, output): | ||
| 251 | output.writeInteger( | ||
| 252 | self.value, self._signed, self._size // 8, self._parent.endian) | ||
| 253 | |||
| 254 | |||
| 255 | def createEditableField(fieldset, field): | ||
| 256 | if isInteger(field): | ||
| 257 | cls = EditableInteger | ||
| 258 | elif isString(field): | ||
| 259 | cls = EditableString | ||
| 260 | elif field.__class__ in (RawBytes, Bytes, PaddingBytes): | ||
| 261 | cls = EditableBytes | ||
| 262 | elif field.__class__ in (RawBits, Bits, Bit, PaddingBits): | ||
| 263 | cls = EditableBits | ||
| 264 | elif field.__class__ == Character: | ||
| 265 | cls = EditableCharacter | ||
| 266 | else: | ||
| 267 | cls = FakeField | ||
| 268 | return cls(fieldset, field.name) | ||
