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/fieldset.py | |
| 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/fieldset.py')
| -rw-r--r-- | libmat/hachoir_editor/fieldset.py | 352 |
1 files changed, 0 insertions, 352 deletions
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 | |||
