summaryrefslogtreecommitdiff
path: root/libmat/hachoir_editor
diff options
context:
space:
mode:
authorjvoisin2015-12-02 17:07:19 +0100
committerjvoisin2015-12-02 17:22:45 +0100
commit80ece3001895ea13d50915a5215fd47e313bab4c (patch)
treec5ede43867c5d7fe2af4178b34b0e6dc219f6aac /libmat/hachoir_editor
parent3cf80e8b5d6faf410e9ad3aad77f23cf6418a587 (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__.py8
-rw-r--r--libmat/hachoir_editor/field.py69
-rw-r--r--libmat/hachoir_editor/fieldset.py352
-rw-r--r--libmat/hachoir_editor/typed_field.py268
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 @@
1from field import (
2 EditorError, FakeField)
3from typed_field import (
4 EditableField, EditableBits, EditableBytes,
5 EditableInteger, EditableString,
6 createEditableField)
7from 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 @@
1from hachoir_core.error import HachoirError
2from hachoir_core.field import joinPath, MissingField
3
4class EditorError(HachoirError):
5 pass
6
7class 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 @@
1from hachoir_core.dict import UniqKeyError
2from hachoir_core.field import MissingField, Float32, Float64, FakeArray
3from hachoir_core.compatibility import any
4from hachoir_core.i18n import _
5from typed_field import createEditableField
6from field import EditorError
7from collections import deque # Python 2.4
8import weakref # Python 2.1
9import struct
10
11class 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
297class 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
320def 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
328class 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
350def 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 @@
1from hachoir_core.field import (
2 RawBits, Bit, Bits, PaddingBits,
3 RawBytes, Bytes, PaddingBytes,
4 GenericString, Character,
5 isInteger, isString)
6from field import FakeField
7
8
9class 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
67class 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
85class 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
113class 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
126class 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
183class 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
208class 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
255def 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)