summaryrefslogtreecommitdiff
path: root/libmat/hachoir_editor
diff options
context:
space:
mode:
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)