Update Hachoir library 1.3.3 to 1.3.4 (r1383)

This commit is contained in:
JackDandy 2015-08-15 15:22:29 +01:00
parent 1dd69dee20
commit a86dccd99d
180 changed files with 7071 additions and 2458 deletions

View file

@ -1,2 +1,2 @@
from lib.hachoir_core.version import VERSION as __version__, PACKAGE, WEBSITE, LICENSE from hachoir_core.version import VERSION as __version__, PACKAGE, WEBSITE, LICENSE

View file

@ -1,5 +1,5 @@
from lib.hachoir_core.tools import humanDurationNanosec from hachoir_core.tools import humanDurationNanosec
from lib.hachoir_core.i18n import _ from hachoir_core.i18n import _
from math import floor from math import floor
from time import time from time import time

View file

@ -3,8 +3,8 @@ Utilities to convert integers and binary strings to binary (number), binary
string, number, hexadecimal, etc. string, number, hexadecimal, etc.
""" """
from lib.hachoir_core.endian import BIG_ENDIAN, LITTLE_ENDIAN from hachoir_core.endian import BIG_ENDIAN, LITTLE_ENDIAN, MIDDLE_ENDIAN
from lib.hachoir_core.compatibility import reversed from hachoir_core.compatibility import reversed
from itertools import chain, repeat from itertools import chain, repeat
from struct import calcsize, unpack, error as struct_error from struct import calcsize, unpack, error as struct_error
@ -30,6 +30,28 @@ def swap32(value):
| ((value & 0x00FF0000L) >> 8) \ | ((value & 0x00FF0000L) >> 8) \
| ((value & 0xFF000000L) >> 24) | ((value & 0xFF000000L) >> 24)
def arrswapmid(data):
r"""
Convert an array of characters from middle-endian to big-endian and vice-versa.
>>> arrswapmid("badcfehg")
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
"""
assert len(data)%2 == 0
ret = ['']*len(data)
ret[1::2] = data[0::2]
ret[0::2] = data[1::2]
return ret
def strswapmid(data):
r"""
Convert raw data from middle-endian to big-endian and vice-versa.
>>> strswapmid("badcfehg")
'abcdefgh'
"""
return ''.join(arrswapmid(data))
def bin2long(text, endian): def bin2long(text, endian):
""" """
Convert binary number written in a string into an integer. Convert binary number written in a string into an integer.
@ -45,9 +67,10 @@ def bin2long(text, endian):
assert endian in (LITTLE_ENDIAN, BIG_ENDIAN) assert endian in (LITTLE_ENDIAN, BIG_ENDIAN)
bits = [ (ord(character)-ord("0")) \ bits = [ (ord(character)-ord("0")) \
for character in text if character in "01" ] for character in text if character in "01" ]
assert len(bits) != 0
if endian is not BIG_ENDIAN: if endian is not BIG_ENDIAN:
bits = reversed(bits) bits = bits[::-1]
size = len(bits)
assert 0 < size
value = 0 value = 0
for bit in bits: for bit in bits:
value *= 2 value *= 2
@ -142,7 +165,7 @@ def long2raw(value, endian, size=None):
'\x19\x12\x00\x00' '\x19\x12\x00\x00'
""" """
assert (not size and 0 < value) or (0 <= value) assert (not size and 0 < value) or (0 <= value)
assert endian in (LITTLE_ENDIAN, BIG_ENDIAN) assert endian in (LITTLE_ENDIAN, BIG_ENDIAN, MIDDLE_ENDIAN)
text = [] text = []
while (value != 0 or text == ""): while (value != 0 or text == ""):
byte = value % 256 byte = value % 256
@ -153,13 +176,15 @@ def long2raw(value, endian, size=None):
else: else:
need = 0 need = 0
if need: if need:
if endian is BIG_ENDIAN: if endian is LITTLE_ENDIAN:
text = chain(repeat("\0", need), reversed(text))
else:
text = chain(text, repeat("\0", need)) text = chain(text, repeat("\0", need))
else:
text = chain(repeat("\0", need), reversed(text))
else: else:
if endian is BIG_ENDIAN: if endian is not LITTLE_ENDIAN:
text = reversed(text) text = reversed(text)
if endian is MIDDLE_ENDIAN:
text = arrswapmid(text)
return "".join(text) return "".join(text)
def long2bin(size, value, endian, classic_mode=False): def long2bin(size, value, endian, classic_mode=False):
@ -257,6 +282,8 @@ def str2long(data, endian):
True True
>>> str2long("\xff\xff\xff\xff\xff\xff\xff\xff", BIG_ENDIAN) == (2**64-1) >>> str2long("\xff\xff\xff\xff\xff\xff\xff\xff", BIG_ENDIAN) == (2**64-1)
True True
>>> str2long("\x0b\x0a\x0d\x0c", MIDDLE_ENDIAN) == 0x0a0b0c0d
True
""" """
assert 1 <= len(data) <= 32 # arbitrary limit: 256 bits assert 1 <= len(data) <= 32 # arbitrary limit: 256 bits
try: try:
@ -264,14 +291,15 @@ def str2long(data, endian):
except KeyError: except KeyError:
pass pass
assert endian in (BIG_ENDIAN, LITTLE_ENDIAN) assert endian in (BIG_ENDIAN, LITTLE_ENDIAN, MIDDLE_ENDIAN)
shift = 0 shift = 0
value = 0 value = 0
if endian is BIG_ENDIAN: if endian is BIG_ENDIAN:
data = reversed(data) data = reversed(data)
elif endian is MIDDLE_ENDIAN:
data = reversed(strswapmid(data))
for character in data: for character in data:
byte = ord(character) byte = ord(character)
value += (byte << shift) value += (byte << shift)
shift += 8 shift += 8
return value return value

View file

@ -1,8 +1,8 @@
from optparse import OptionGroup from optparse import OptionGroup
from lib.hachoir_core.log import log from hachoir_core.log import log
from lib.hachoir_core.i18n import _, getTerminalCharset from hachoir_core.i18n import _, getTerminalCharset
from lib.hachoir_core.tools import makePrintable from hachoir_core.tools import makePrintable
import lib.hachoir_core.config as config import hachoir_core.config as config
def getHachoirOptions(parser): def getHachoirOptions(parser):
""" """

View file

@ -2,8 +2,8 @@
Dictionnary classes which store values order. Dictionnary classes which store values order.
""" """
from lib.hachoir_core.error import HachoirError from hachoir_core.error import HachoirError
from lib.hachoir_core.i18n import _ from hachoir_core.i18n import _
class UniqKeyError(HachoirError): class UniqKeyError(HachoirError):
""" """

View file

@ -2,14 +2,15 @@
Constant values about endian. Constant values about endian.
""" """
from lib.hachoir_core.i18n import _ from hachoir_core.i18n import _
BIG_ENDIAN = "ABCD" BIG_ENDIAN = "ABCD"
LITTLE_ENDIAN = "DCBA" LITTLE_ENDIAN = "DCBA"
MIDDLE_ENDIAN = "BADC"
NETWORK_ENDIAN = BIG_ENDIAN NETWORK_ENDIAN = BIG_ENDIAN
endian_name = { endian_name = {
BIG_ENDIAN: _("Big endian"), BIG_ENDIAN: _("Big endian"),
LITTLE_ENDIAN: _("Little endian"), LITTLE_ENDIAN: _("Little endian"),
MIDDLE_ENDIAN: _("Middle endian"),
} }

View file

@ -2,8 +2,8 @@
Functions to display an error (error, warning or information) message. Functions to display an error (error, warning or information) message.
""" """
from lib.hachoir_core.log import log from hachoir_core.log import log
from lib.hachoir_core.tools import makePrintable from hachoir_core.tools import makePrintable
import sys, traceback import sys, traceback
def getBacktrace(empty="Empty backtrace."): def getBacktrace(empty="Empty backtrace."):

View file

@ -1,44 +1,44 @@
# Field classes # Field classes
from lib.hachoir_core.field.field import Field, FieldError, MissingField, joinPath from hachoir_core.field.field import Field, FieldError, MissingField, joinPath
from lib.hachoir_core.field.bit_field import Bit, Bits, RawBits from hachoir_core.field.bit_field import Bit, Bits, RawBits
from lib.hachoir_core.field.byte_field import Bytes, RawBytes from hachoir_core.field.byte_field import Bytes, RawBytes
from lib.hachoir_core.field.sub_file import SubFile, CompressedField from hachoir_core.field.sub_file import SubFile, CompressedField
from lib.hachoir_core.field.character import Character from hachoir_core.field.character import Character
from lib.hachoir_core.field.integer import ( from hachoir_core.field.integer import (
Int8, Int16, Int24, Int32, Int64, Int8, Int16, Int24, Int32, Int64,
UInt8, UInt16, UInt24, UInt32, UInt64, UInt8, UInt16, UInt24, UInt32, UInt64,
GenericInteger) GenericInteger)
from lib.hachoir_core.field.enum import Enum from hachoir_core.field.enum import Enum
from lib.hachoir_core.field.string_field import (GenericString, from hachoir_core.field.string_field import (GenericString,
String, CString, UnixLine, String, CString, UnixLine,
PascalString8, PascalString16, PascalString32) PascalString8, PascalString16, PascalString32)
from lib.hachoir_core.field.padding import (PaddingBits, PaddingBytes, from hachoir_core.field.padding import (PaddingBits, PaddingBytes,
NullBits, NullBytes) NullBits, NullBytes)
# Functions # Functions
from lib.hachoir_core.field.helper import (isString, isInteger, from hachoir_core.field.helper import (isString, isInteger,
createPaddingField, createNullField, createRawField, createPaddingField, createNullField, createRawField,
writeIntoFile, createOrphanField) writeIntoFile, createOrphanField)
# FieldSet classes # FieldSet classes
from lib.hachoir_core.field.fake_array import FakeArray from hachoir_core.field.fake_array import FakeArray
from lib.hachoir_core.field.basic_field_set import (BasicFieldSet, from hachoir_core.field.basic_field_set import (BasicFieldSet,
ParserError, MatchError) ParserError, MatchError)
from lib.hachoir_core.field.generic_field_set import GenericFieldSet from hachoir_core.field.generic_field_set import GenericFieldSet
from lib.hachoir_core.field.seekable_field_set import SeekableFieldSet, RootSeekableFieldSet from hachoir_core.field.seekable_field_set import SeekableFieldSet, RootSeekableFieldSet
from lib.hachoir_core.field.field_set import FieldSet from hachoir_core.field.field_set import FieldSet
from lib.hachoir_core.field.static_field_set import StaticFieldSet from hachoir_core.field.static_field_set import StaticFieldSet
from lib.hachoir_core.field.parser import Parser from hachoir_core.field.parser import Parser
from lib.hachoir_core.field.vector import GenericVector, UserVector from hachoir_core.field.vector import GenericVector, UserVector
# Complex types # Complex types
from lib.hachoir_core.field.float import Float32, Float64, Float80 from hachoir_core.field.float import Float32, Float64, Float80
from lib.hachoir_core.field.timestamp import (GenericTimestamp, from hachoir_core.field.timestamp import (GenericTimestamp,
TimestampUnix32, TimestampUnix64, TimestampMac32, TimestampUUID60, TimestampWin64, TimestampUnix32, TimestampUnix64, TimestampMac32, TimestampUUID60, TimestampWin64,
DateTimeMSDOS32, TimeDateMSDOS32, TimedeltaWin64) DateTimeMSDOS32, TimeDateMSDOS32, TimedeltaWin64)
# Special Field classes # Special Field classes
from lib.hachoir_core.field.link import Link, Fragment from hachoir_core.field.link import Link, Fragment
available_types = ( available_types = (
Bit, Bits, RawBits, Bit, Bits, RawBits,

View file

@ -1,7 +1,7 @@
from lib.hachoir_core.field import Field, FieldError from hachoir_core.field import Field, FieldError
from lib.hachoir_core.stream import InputStream from hachoir_core.stream import InputStream
from lib.hachoir_core.endian import BIG_ENDIAN, LITTLE_ENDIAN from hachoir_core.endian import BIG_ENDIAN, LITTLE_ENDIAN, MIDDLE_ENDIAN
from lib.hachoir_core.event_handler import EventHandler from hachoir_core.event_handler import EventHandler
class ParserError(FieldError): class ParserError(FieldError):
""" """
@ -60,7 +60,7 @@ class BasicFieldSet(Field):
self._global_event_handler = None self._global_event_handler = None
# Sanity checks (post-conditions) # Sanity checks (post-conditions)
assert self.endian in (BIG_ENDIAN, LITTLE_ENDIAN) assert self.endian in (BIG_ENDIAN, LITTLE_ENDIAN, MIDDLE_ENDIAN)
if (self._size is not None) and (self._size <= 0): if (self._size is not None) and (self._size <= 0):
raise ParserError("Invalid parser '%s' size: %s" % (self.path, self._size)) raise ParserError("Invalid parser '%s' size: %s" % (self.path, self._size))

View file

@ -5,9 +5,9 @@ Bit sized classes:
- RawBits: unknown content with a size in bits. - RawBits: unknown content with a size in bits.
""" """
from lib.hachoir_core.field import Field from hachoir_core.field import Field
from lib.hachoir_core.i18n import _ from hachoir_core.i18n import _
from lib.hachoir_core import config from hachoir_core import config
class RawBits(Field): class RawBits(Field):
""" """

View file

@ -3,10 +3,10 @@ Very basic field: raw content with a size in byte. Use this class for
unknown content. unknown content.
""" """
from lib.hachoir_core.field import Field, FieldError from hachoir_core.field import Field, FieldError
from lib.hachoir_core.tools import makePrintable from hachoir_core.tools import makePrintable
from lib.hachoir_core.bits import str2hex from hachoir_core.bits import str2hex
from lib.hachoir_core import config from hachoir_core import config
MAX_LENGTH = (2**64) MAX_LENGTH = (2**64)

View file

@ -2,9 +2,9 @@
Character field class: a 8-bit character Character field class: a 8-bit character
""" """
from lib.hachoir_core.field import Bits from hachoir_core.field import Bits
from lib.hachoir_core.endian import BIG_ENDIAN from hachoir_core.endian import BIG_ENDIAN
from lib.hachoir_core.tools import makePrintable from hachoir_core.tools import makePrintable
class Character(Bits): class Character(Bits):
""" """
@ -24,4 +24,3 @@ class Character(Bits):
def createDisplay(self): def createDisplay(self):
return makePrintable(self.value, "ASCII", quote="'", to_unicode=True) return makePrintable(self.value, "ASCII", quote="'", to_unicode=True)

View file

@ -1,7 +1,7 @@
def Enum(field, enum, key_func=None): def Enum(field, enum, key_func=None):
""" """
Enum is an adapter to another field: it will just change its display Enum is an adapter to another field: it will just change its display
attribute. It uses a dictionnary to associate a value to another. attribute. It uses a dictionary to associate a value to another.
key_func is an optional function with prototype "def func(key)->key" key_func is an optional function with prototype "def func(key)->key"
which is called to transform key. which is called to transform key.
@ -23,4 +23,3 @@ def Enum(field, enum, key_func=None):
field.createDisplay = createDisplay field.createDisplay = createDisplay
field.getEnum = lambda: enum field.getEnum = lambda: enum
return field return field

View file

@ -1,5 +1,5 @@
import itertools import itertools
from lib.hachoir_core.field import MissingField from hachoir_core.field import MissingField
class FakeArray: class FakeArray:
""" """

View file

@ -2,12 +2,12 @@
Parent of all (field) classes in Hachoir: Field. Parent of all (field) classes in Hachoir: Field.
""" """
from lib.hachoir_core.compatibility import reversed from hachoir_core.compatibility import reversed
from lib.hachoir_core.stream import InputFieldStream from hachoir_core.stream import InputFieldStream
from lib.hachoir_core.error import HachoirError, HACHOIR_ERRORS from hachoir_core.error import HachoirError, HACHOIR_ERRORS
from lib.hachoir_core.log import Logger from hachoir_core.log import Logger
from lib.hachoir_core.i18n import _ from hachoir_core.i18n import _
from lib.hachoir_core.tools import makePrintable from hachoir_core.tools import makePrintable
from weakref import ref as weakref_ref from weakref import ref as weakref_ref
class FieldError(HachoirError): class FieldError(HachoirError):
@ -70,6 +70,8 @@ class Field(Logger):
assert issubclass(parent.__class__, Field) assert issubclass(parent.__class__, Field)
assert (size is None) or (0 <= size) assert (size is None) or (0 <= size)
self._parent = parent self._parent = parent
if not name:
raise ValueError("empty field name")
self._name = name self._name = name
self._address = parent.nextFieldAddress() self._address = parent.nextFieldAddress()
self._size = size self._size = size
@ -166,7 +168,7 @@ class Field(Logger):
return '/' return '/'
names = [] names = []
field = self field = self
while field: while field is not None:
names.append(field._name) names.append(field._name)
field = field._parent field = field._parent
names[-1] = '' names[-1] = ''

View file

@ -1,4 +1,4 @@
from lib.hachoir_core.field import BasicFieldSet, GenericFieldSet from hachoir_core.field import BasicFieldSet, GenericFieldSet
class FieldSet(GenericFieldSet): class FieldSet(GenericFieldSet):
def __init__(self, parent, name, *args, **kw): def __init__(self, parent, name, *args, **kw):

View file

@ -1,5 +1,5 @@
from lib.hachoir_core.field import Bit, Bits, FieldSet from hachoir_core.field import Bit, Bits, FieldSet
from lib.hachoir_core.endian import BIG_ENDIAN, LITTLE_ENDIAN from hachoir_core.endian import BIG_ENDIAN, LITTLE_ENDIAN
import struct import struct
# Make sure that we use right struct types # Make sure that we use right struct types
@ -85,15 +85,15 @@ def floatFactory(name, format, mantissa_bits, exponent_bits, doc):
cls.__name__ = name cls.__name__ = name
return cls return cls
# 32-bit float (standart: IEEE 754/854) # 32-bit float (standard: IEEE 754/854)
Float32 = floatFactory("Float32", "f", 23, 8, Float32 = floatFactory("Float32", "f", 23, 8,
"Floating point number: format IEEE 754 int 32 bit") "Floating point number: format IEEE 754 int 32 bit")
# 64-bit float (standart: IEEE 754/854) # 64-bit float (standard: IEEE 754/854)
Float64 = floatFactory("Float64", "d", 52, 11, Float64 = floatFactory("Float64", "d", 52, 11,
"Floating point number: format IEEE 754 in 64 bit") "Floating point number: format IEEE 754 in 64 bit")
# 80-bit float (standart: IEEE 754/854) # 80-bit float (standard: IEEE 754/854)
Float80 = floatFactory("Float80", None, 64, 15, Float80 = floatFactory("Float80", None, 64, 15,
"Floating point number: format IEEE 754 in 80 bit") "Floating point number: format IEEE 754 in 80 bit")

View file

@ -1,9 +1,9 @@
from lib.hachoir_core.field import (MissingField, BasicFieldSet, Field, ParserError, from hachoir_core.field import (MissingField, BasicFieldSet, Field, ParserError,
createRawField, createNullField, createPaddingField, FakeArray) createRawField, createNullField, createPaddingField, FakeArray)
from lib.hachoir_core.dict import Dict, UniqKeyError from hachoir_core.dict import Dict, UniqKeyError
from lib.hachoir_core.error import HACHOIR_ERRORS from hachoir_core.error import HACHOIR_ERRORS
from lib.hachoir_core.tools import lowerBound from hachoir_core.tools import lowerBound, makeUnicode
import lib.hachoir_core.config as config import hachoir_core.config as config
class GenericFieldSet(BasicFieldSet): class GenericFieldSet(BasicFieldSet):
""" """
@ -12,8 +12,8 @@ class GenericFieldSet(BasicFieldSet):
document). document).
Class attributes: Class attributes:
- endian: Bytes order (L{BIG_ENDIAN} or L{LITTLE_ENDIAN}). Optional if the - endian: Bytes order (L{BIG_ENDIAN}, L{LITTLE_ENDIAN} or L{MIDDLE_ENDIAN}).
field set has a parent ; Optional if the field set has a parent ;
- static_size: (optional) Size of FieldSet in bits. This attribute should - static_size: (optional) Size of FieldSet in bits. This attribute should
be used in parser of constant size. be used in parser of constant size.
@ -310,7 +310,7 @@ class GenericFieldSet(BasicFieldSet):
""" """
if self._size is None or not self.autofix: if self._size is None or not self.autofix:
return False return False
self.warning(unicode(exception)) self.warning(makeUnicode(exception))
return self._fixLastField() return self._fixLastField()
def _feedUntil(self, field_name): def _feedUntil(self, field_name):

View file

@ -1,9 +1,9 @@
from lib.hachoir_core.field import (FieldError, from hachoir_core.field import (FieldError,
RawBits, RawBytes, RawBits, RawBytes,
PaddingBits, PaddingBytes, PaddingBits, PaddingBytes,
NullBits, NullBytes, NullBits, NullBytes,
GenericString, GenericInteger) GenericString, GenericInteger)
from lib.hachoir_core.stream import FileOutputStream from hachoir_core.stream import FileOutputStream
def createRawField(parent, size, name="raw[]", description=None): def createRawField(parent, size, name="raw[]", description=None):
if size <= 0: if size <= 0:

View file

@ -4,15 +4,15 @@ Integer field classes:
- Int8, Int16, Int24, Int32, Int64: signed integer of 8, 16, 32, 64 bits. - Int8, Int16, Int24, Int32, Int64: signed integer of 8, 16, 32, 64 bits.
""" """
from lib.hachoir_core.field import Bits, FieldError from hachoir_core.field import Bits, FieldError
class GenericInteger(Bits): class GenericInteger(Bits):
""" """
Generic integer class used to generate other classes. Generic integer class used to generate other classes.
""" """
def __init__(self, parent, name, signed, size, description=None): def __init__(self, parent, name, signed, size, description=None):
if not (8 <= size <= 256): if not (8 <= size <= 16384):
raise FieldError("Invalid integer size (%s): have to be in 8..256" % size) raise FieldError("Invalid integer size (%s): have to be in 8..16384" % size)
Bits.__init__(self, parent, name, size, description) Bits.__init__(self, parent, name, size, description)
self.signed = signed self.signed = signed

View file

@ -1,5 +1,5 @@
from lib.hachoir_core.field import Field, FieldSet, ParserError, Bytes, MissingField from hachoir_core.field import Field, FieldSet, ParserError, Bytes, MissingField
from lib.hachoir_core.stream import FragmentedStream from hachoir_core.stream import FragmentedStream
class Link(Field): class Link(Field):

View file

@ -1,5 +1,5 @@
from lib.hachoir_core.field import BasicFieldSet, GenericFieldSet, ParserError, createRawField from hachoir_core.field import BasicFieldSet, GenericFieldSet, ParserError, createRawField
from lib.hachoir_core.error import HACHOIR_ERRORS from hachoir_core.error import HACHOIR_ERRORS
# getgaps(int, int, [listof (int, int)]) -> generator of (int, int) # getgaps(int, int, [listof (int, int)]) -> generator of (int, int)
# Gets all the gaps not covered by a block in `blocks` from `start` for `length` units. # Gets all the gaps not covered by a block in `blocks` from `start` for `length` units.

View file

@ -1,6 +1,6 @@
from lib.hachoir_core.field import Bits, Bytes from hachoir_core.field import Bits, Bytes
from lib.hachoir_core.tools import makePrintable, humanFilesize from hachoir_core.tools import makePrintable, humanFilesize
from lib.hachoir_core import config from hachoir_core import config
class PaddingBits(Bits): class PaddingBits(Bits):
""" """

View file

@ -1,13 +1,13 @@
from lib.hachoir_core.endian import BIG_ENDIAN, LITTLE_ENDIAN from hachoir_core.endian import BIG_ENDIAN, LITTLE_ENDIAN, MIDDLE_ENDIAN
from lib.hachoir_core.field import GenericFieldSet from hachoir_core.field import GenericFieldSet
from lib.hachoir_core.log import Logger from hachoir_core.log import Logger
import lib.hachoir_core.config as config import hachoir_core.config as config
class Parser(GenericFieldSet): class Parser(GenericFieldSet):
""" """
A parser is the root of all other fields. It create first level of fields A parser is the root of all other fields. It create first level of fields
and have special attributes and methods: and have special attributes and methods:
- endian: Byte order (L{BIG_ENDIAN} or L{LITTLE_ENDIAN}) of input data ; - endian: Byte order (L{BIG_ENDIAN}, L{LITTLE_ENDIAN} or L{MIDDLE_ENDIAN}) of input data ;
- stream: Data input stream (set in L{__init__()}) ; - stream: Data input stream (set in L{__init__()}) ;
- size: Field set size will be size of input stream. - size: Field set size will be size of input stream.
""" """
@ -21,7 +21,7 @@ class Parser(GenericFieldSet):
""" """
# Check arguments # Check arguments
assert hasattr(self, "endian") \ assert hasattr(self, "endian") \
and self.endian in (BIG_ENDIAN, LITTLE_ENDIAN) and self.endian in (BIG_ENDIAN, LITTLE_ENDIAN, MIDDLE_ENDIAN)
# Call parent constructor # Call parent constructor
GenericFieldSet.__init__(self, None, "root", stream, description, stream.askSize(self)) GenericFieldSet.__init__(self, None, "root", stream, description, stream.askSize(self))

View file

@ -1,182 +1,82 @@
from lib.hachoir_core.field import Field, BasicFieldSet, FakeArray, MissingField, ParserError from hachoir_core.field import BasicFieldSet, GenericFieldSet, ParserError, createRawField
from lib.hachoir_core.tools import makeUnicode from hachoir_core.error import HACHOIR_ERRORS
from lib.hachoir_core.error import HACHOIR_ERRORS
from itertools import repeat
import lib.hachoir_core.config as config
class RootSeekableFieldSet(BasicFieldSet): # getgaps(int, int, [listof (int, int)]) -> generator of (int, int)
def __init__(self, parent, name, stream, description, size): # Gets all the gaps not covered by a block in `blocks` from `start` for `length` units.
BasicFieldSet.__init__(self, parent, name, stream, description, size) def getgaps(start, length, blocks):
self._generator = self.createFields() '''
self._offset = 0 Example:
self._current_size = 0 >>> list(getgaps(0, 20, [(15,3), (6,2), (6,2), (1,2), (2,3), (11,2), (9,5)]))
if size: [(0, 1), (5, 1), (8, 1), (14, 1), (18, 2)]
self._current_max_size = size '''
else: # done this way to avoid mutating the original
self._current_max_size = 0 blocks = sorted(blocks, key=lambda b: b[0])
self._field_dict = {} end = start+length
self._field_array = [] for s, l in blocks:
if s > start:
def _feedOne(self): yield (start, s-start)
assert self._generator start = s
field = self._generator.next() if s+l > start:
self._addField(field) start = s+l
return field if start < end:
yield (start, end-start)
def array(self, key):
return FakeArray(self, key)
def getFieldByAddress(self, address, feed=True):
for field in self._field_array:
if field.address <= address < field.address + field.size:
return field
for field in self._readFields():
if field.address <= address < field.address + field.size:
return field
return None
def _stopFeed(self):
self._size = self._current_max_size
self._generator = None
done = property(lambda self: not bool(self._generator))
def _getSize(self):
if self._size is None:
self._feedAll()
return self._size
size = property(_getSize)
def _getField(self, key, const):
field = Field._getField(self, key, const)
if field is not None:
return field
if key in self._field_dict:
return self._field_dict[key]
if self._generator and not const:
try:
while True:
field = self._feedOne()
if field.name == key:
return field
except StopIteration:
self._stopFeed()
except HACHOIR_ERRORS, err:
self.error("Error: %s" % makeUnicode(err))
self._stopFeed()
return None
def getField(self, key, const=True):
if isinstance(key, (int, long)):
if key < 0:
raise KeyError("Key must be positive!")
if not const:
self.readFirstFields(key+1)
if len(self._field_array) <= key:
raise MissingField(self, key)
return self._field_array[key]
return Field.getField(self, key, const)
def _addField(self, field):
if field._name.endswith("[]"):
self.setUniqueFieldName(field)
if config.debug:
self.info("[+] DBG: _addField(%s)" % field.name)
if field._address != self._offset:
self.warning("Set field %s address to %s (was %s)" % (
field.path, self._offset//8, field._address//8))
field._address = self._offset
assert field.name not in self._field_dict
self._checkFieldSize(field)
self._field_dict[field.name] = field
self._field_array.append(field)
self._current_size += field.size
self._offset += field.size
self._current_max_size = max(self._current_max_size, field.address + field.size)
def _checkAddress(self, address):
if self._size is not None:
max_addr = self._size
else:
# FIXME: Use parent size
max_addr = self.stream.size
return address < max_addr
def _checkFieldSize(self, field):
size = field.size
addr = field.address
if not self._checkAddress(addr+size-1):
raise ParserError("Unable to add %s: field is too large" % field.name)
class RootSeekableFieldSet(GenericFieldSet):
def seekBit(self, address, relative=True): def seekBit(self, address, relative=True):
if not relative: if not relative:
address -= self.absolute_address address -= self.absolute_address
if address < 0: if address < 0:
raise ParserError("Seek below field set start (%s.%s)" % divmod(address, 8)) raise ParserError("Seek below field set start (%s.%s)" % divmod(address, 8))
if not self._checkAddress(address): self._current_size = address
raise ParserError("Seek above field set end (%s.%s)" % divmod(address, 8))
self._offset = address
return None return None
def seekByte(self, address, relative=True): def seekByte(self, address, relative=True):
return self.seekBit(address*8, relative) return self.seekBit(address*8, relative)
def readMoreFields(self, number): def _fixLastField(self):
return self._readMoreFields(xrange(number)) """
Try to fix last field when we know current field set size.
Returns new added field if any, or None.
"""
assert self._size is not None
def _feedAll(self): # Stop parser
return self._readMoreFields(repeat(1)) message = ["stop parser"]
self._field_generator = None
def _readFields(self): # If last field is too big, delete it
while True: while self._size < self._current_size:
added = self._readMoreFields(xrange(1)) field = self._deleteField(len(self._fields)-1)
if not added: message.append("delete field %s" % field.path)
break assert self._current_size <= self._size
yield self._field_array[-1]
def _readMoreFields(self, index_generator): blocks = [(x.absolute_address, x.size) for x in self._fields]
added = 0 fields = []
if self._generator: self._size = max(self._size, max(a+b for a,b in blocks) - self.absolute_address)
try: for start, length in getgaps(self.absolute_address, self._size, blocks):
for index in index_generator: self.seekBit(start, relative=False)
self._feedOne() field = createRawField(self, length, "unparsed[]")
added += 1 self.setUniqueFieldName(field)
except StopIteration: self._fields.append(field.name, field)
self._stopFeed() fields.append(field)
except HACHOIR_ERRORS, err: message.append("found unparsed segment: start %s, length %s" % (start, length))
self.error("Error: %s" % makeUnicode(err)) self.seekBit(self._size + self.absolute_address, relative=False)
self._stopFeed() message = ", ".join(message)
return added if fields:
self.warning("[Autofix] Fix parser error: " + message)
return fields
current_length = property(lambda self: len(self._field_array)) def _stopFeeding(self):
current_size = property(lambda self: self._offset) new_field = None
if self._size is None:
if self._parent:
self._size = self._current_size
def __iter__(self): new_field = self._fixLastField()
for field in self._field_array: self._field_generator = None
yield field return new_field
if self._generator:
try:
while True:
yield self._feedOne()
except StopIteration:
self._stopFeed()
raise StopIteration
def __len__(self):
if self._generator:
self._feedAll()
return len(self._field_array)
def nextFieldAddress(self):
return self._offset
def getFieldIndex(self, field):
return self._field_array.index(field)
class SeekableFieldSet(RootSeekableFieldSet): class SeekableFieldSet(RootSeekableFieldSet):
def __init__(self, parent, name, description=None, size=None): def __init__(self, parent, name, description=None, size=None):
assert issubclass(parent.__class__, BasicFieldSet) assert issubclass(parent.__class__, BasicFieldSet)
RootSeekableFieldSet.__init__(self, parent, name, parent.stream, description, size) RootSeekableFieldSet.__init__(self, parent, name, parent.stream, description, size)

View file

@ -1,4 +1,4 @@
from lib.hachoir_core.field import FieldSet, ParserError from hachoir_core.field import FieldSet, ParserError
class StaticFieldSet(FieldSet): class StaticFieldSet(FieldSet):
""" """
@ -20,7 +20,7 @@ class StaticFieldSet(FieldSet):
if cls._class is not cls.__name__: if cls._class is not cls.__name__:
cls._class = cls.__name__ cls._class = cls.__name__
cls.static_size = cls._computeStaticSize() cls.static_size = cls._computeStaticSize()
return object.__new__(cls) return object.__new__(cls, *args, **kw)
@staticmethod @staticmethod
def _computeItemSize(item): def _computeItemSize(item):

View file

@ -15,11 +15,11 @@ Note: For PascalStringXX, prefixed value is the number of bytes and not
of characters! of characters!
""" """
from lib.hachoir_core.field import FieldError, Bytes from hachoir_core.field import FieldError, Bytes
from lib.hachoir_core.endian import LITTLE_ENDIAN, BIG_ENDIAN from hachoir_core.endian import LITTLE_ENDIAN, BIG_ENDIAN
from lib.hachoir_core.tools import alignValue, makePrintable from hachoir_core.tools import alignValue, makePrintable
from lib.hachoir_core.i18n import guessBytesCharset, _ from hachoir_core.i18n import guessBytesCharset, _
from lib.hachoir_core import config from hachoir_core import config
from codecs import BOM_UTF16_LE, BOM_UTF16_BE, BOM_UTF32_LE, BOM_UTF32_BE from codecs import BOM_UTF16_LE, BOM_UTF16_BE, BOM_UTF32_LE, BOM_UTF32_BE
# Default charset used to convert byte string to Unicode # Default charset used to convert byte string to Unicode

View file

@ -1,6 +1,6 @@
from lib.hachoir_core.field import Bytes from hachoir_core.field import Bytes
from lib.hachoir_core.tools import makePrintable, humanFilesize from hachoir_core.tools import makePrintable, humanFilesize
from lib.hachoir_core.stream import InputIOStream from hachoir_core.stream import InputIOStream
class SubFile(Bytes): class SubFile(Bytes):
""" """

View file

@ -1,7 +1,7 @@
from lib.hachoir_core.tools import (humanDatetime, humanDuration, from hachoir_core.tools import (humanDatetime, humanDuration,
timestampUNIX, timestampMac32, timestampUUID60, timestampUNIX, timestampMac32, timestampUUID60,
timestampWin64, durationWin64) timestampWin64, durationWin64)
from lib.hachoir_core.field import Bits, FieldSet from hachoir_core.field import Bits, FieldSet
from datetime import datetime from datetime import datetime
class GenericTimestamp(Bits): class GenericTimestamp(Bits):
@ -32,7 +32,7 @@ def timestampFactory(cls_name, handler, size):
TimestampUnix32 = timestampFactory("TimestampUnix32", timestampUNIX, 32) TimestampUnix32 = timestampFactory("TimestampUnix32", timestampUNIX, 32)
TimestampUnix64 = timestampFactory("TimestampUnix64", timestampUNIX, 64) TimestampUnix64 = timestampFactory("TimestampUnix64", timestampUNIX, 64)
TimestampMac32 = timestampFactory("TimestampUnix32", timestampMac32, 32) TimestampMac32 = timestampFactory("TimestampMac32", timestampMac32, 32)
TimestampUUID60 = timestampFactory("TimestampUUID60", timestampUUID60, 60) TimestampUUID60 = timestampFactory("TimestampUUID60", timestampUUID60, 60)
TimestampWin64 = timestampFactory("TimestampWin64", timestampWin64, 64) TimestampWin64 = timestampFactory("TimestampWin64", timestampWin64, 64)

View file

@ -1,4 +1,4 @@
from lib.hachoir_core.field import Field, FieldSet, ParserError from hachoir_core.field import Field, FieldSet, ParserError
class GenericVector(FieldSet): class GenericVector(FieldSet):
def __init__(self, parent, name, nb_items, item_class, item_name="item", description=None): def __init__(self, parent, name, nb_items, item_class, item_name="item", description=None):

View file

@ -14,8 +14,8 @@ WARNING: Loading this module indirectly calls initLocale() which sets
settings. settings.
""" """
import lib.hachoir_core.config as config import hachoir_core.config as config
import lib.hachoir_core import hachoir_core
import locale import locale
from os import path from os import path
import sys import sys
@ -133,7 +133,7 @@ def _initGettext():
return (_dummy_gettext, _dummy_ngettext) return (_dummy_gettext, _dummy_ngettext)
# Gettext variables # Gettext variables
package = lib.hachoir_core.PACKAGE package = hachoir_core.PACKAGE
locale_dir = path.join(path.dirname(__file__), "..", "locale") locale_dir = path.join(path.dirname(__file__), "..", "locale")
# Initialize gettext module # Initialize gettext module

View file

@ -328,7 +328,6 @@ _ISO639 = (
(u"Micmac", "mic", None), (u"Micmac", "mic", None),
(u"Minangkabau", "min", None), (u"Minangkabau", "min", None),
(u"Mirandese", "mwl", None), (u"Mirandese", "mwl", None),
(u"Miscellaneous languages", "mis", None),
(u"Mohawk", "moh", None), (u"Mohawk", "moh", None),
(u"Moksha", "mdf", None), (u"Moksha", "mdf", None),
(u"Moldavian", "mol", "mo"), (u"Moldavian", "mol", "mo"),
@ -513,6 +512,7 @@ _ISO639 = (
(u"Uighur", "uig", "ug"), (u"Uighur", "uig", "ug"),
(u"Ukrainian", "ukr", "uk"), (u"Ukrainian", "ukr", "uk"),
(u"Umbundu", "umb", None), (u"Umbundu", "umb", None),
(u"Uncoded languages", "mis", None),
(u"Undetermined", "und", None), (u"Undetermined", "und", None),
(u"Upper Sorbian", "hsb", None), (u"Upper Sorbian", "hsb", None),
(u"Urdu", "urd", "ur"), (u"Urdu", "urd", "ur"),

View file

@ -1,4 +1,4 @@
from lib.hachoir_core.iso639 import ISO639_2 from hachoir_core.iso639 import ISO639_2
class Language: class Language:
def __init__(self, code): def __init__(self, code):

View file

@ -1,6 +1,6 @@
import os, sys, time import os, sys, time
import lib.hachoir_core.config as config import hachoir_core.config as config
from lib.hachoir_core.i18n import _ from hachoir_core.i18n import _
class Log: class Log:
LOG_INFO = 0 LOG_INFO = 0
@ -75,7 +75,7 @@ class Log:
level <= self.LOG_INFO and not config.verbose: level <= self.LOG_INFO and not config.verbose:
return return
if config.debug: if config.debug:
from lib.hachoir_core.error import getBacktrace from hachoir_core.error import getBacktrace
backtrace = getBacktrace(None) backtrace = getBacktrace(None)
if backtrace: if backtrace:
text += "\n\n" + backtrace text += "\n\n" + backtrace

View file

@ -1,11 +1,11 @@
from lib.hachoir_core.endian import BIG_ENDIAN, LITTLE_ENDIAN from hachoir_core.endian import BIG_ENDIAN, LITTLE_ENDIAN
from lib.hachoir_core.stream.stream import StreamError from hachoir_core.stream.stream import StreamError
from lib.hachoir_core.stream.input import ( from hachoir_core.stream.input import (
InputStreamError, InputStreamError,
InputStream, InputIOStream, StringInputStream, InputStream, InputIOStream, StringInputStream,
InputSubStream, InputFieldStream, InputSubStream, InputFieldStream,
FragmentedStream, ConcatStream) FragmentedStream, ConcatStream)
from lib.hachoir_core.stream.input_helper import FileInputStream, guessStreamCharset from hachoir_core.stream.input_helper import FileInputStream, guessStreamCharset
from lib.hachoir_core.stream.output import (OutputStreamError, from hachoir_core.stream.output import (OutputStreamError,
FileOutputStream, StringOutputStream, OutputStream) FileOutputStream, StringOutputStream, OutputStream)

View file

@ -1,14 +1,14 @@
from lib.hachoir_core.endian import BIG_ENDIAN, LITTLE_ENDIAN from hachoir_core.endian import BIG_ENDIAN, LITTLE_ENDIAN, MIDDLE_ENDIAN
from lib.hachoir_core.error import info from hachoir_core.error import info
from lib.hachoir_core.log import Logger from hachoir_core.log import Logger
from lib.hachoir_core.bits import str2long from hachoir_core.bits import str2long
from lib.hachoir_core.i18n import getTerminalCharset from hachoir_core.i18n import getTerminalCharset
from lib.hachoir_core.tools import lowerBound from hachoir_core.tools import lowerBound
from lib.hachoir_core.i18n import _ from hachoir_core.i18n import _
from os import dup, fdopen from hachoir_core.tools import alignValue
from errno import ESPIPE from errno import ESPIPE
from weakref import ref as weakref_ref from weakref import ref as weakref_ref
from lib.hachoir_core.stream import StreamError from hachoir_core.stream import StreamError
class InputStreamError(StreamError): class InputStreamError(StreamError):
pass pass
@ -168,13 +168,20 @@ class InputStream(Logger):
raise NotImplementedError raise NotImplementedError
def readBits(self, address, nbits, endian): def readBits(self, address, nbits, endian):
assert endian in (BIG_ENDIAN, LITTLE_ENDIAN) assert endian in (BIG_ENDIAN, LITTLE_ENDIAN, MIDDLE_ENDIAN)
shift, data, missing = self.read(address, nbits) if endian is MIDDLE_ENDIAN:
# read an aligned chunk of words
wordaddr, remainder = divmod(address, 16)
wordnbits = alignValue(remainder+nbits, 16)
_, data, missing = self.read(wordaddr*16, wordnbits)
shift = remainder
else:
shift, data, missing = self.read(address, nbits)
if missing: if missing:
raise ReadStreamError(nbits, address) raise ReadStreamError(nbits, address)
value = str2long(data, endian) value = str2long(data, endian)
if endian is BIG_ENDIAN: if endian in (BIG_ENDIAN, MIDDLE_ENDIAN):
value >>= len(data) * 8 - shift - nbits value >>= len(data) * 8 - shift - nbits
else: else:
value >>= shift value >>= shift
@ -404,6 +411,7 @@ class InputIOStream(InputStream):
def file(self): def file(self):
if hasattr(self._input, "fileno"): if hasattr(self._input, "fileno"):
from os import dup, fdopen
new_fd = dup(self._input.fileno()) new_fd = dup(self._input.fileno())
new_file = fdopen(new_fd, "r") new_file = fdopen(new_fd, "r")
new_file.seek(0) new_file.seek(0)

View file

@ -1,5 +1,5 @@
from lib.hachoir_core.i18n import getTerminalCharset, guessBytesCharset, _ from hachoir_core.i18n import getTerminalCharset, guessBytesCharset, _
from lib.hachoir_core.stream import InputIOStream, InputSubStream, InputStreamError from hachoir_core.stream import InputIOStream, InputSubStream, InputStreamError
def FileInputStream(filename, real_filename=None, **args): def FileInputStream(filename, real_filename=None, **args):
""" """

View file

@ -1,7 +1,7 @@
from cStringIO import StringIO from cStringIO import StringIO
from lib.hachoir_core.endian import BIG_ENDIAN from hachoir_core.endian import BIG_ENDIAN, LITTLE_ENDIAN
from lib.hachoir_core.bits import long2raw from hachoir_core.bits import long2raw
from lib.hachoir_core.stream import StreamError from hachoir_core.stream import StreamError
from errno import EBADF from errno import EBADF
MAX_READ_NBYTES = 2 ** 16 MAX_READ_NBYTES = 2 ** 16
@ -21,6 +21,7 @@ class OutputStream(object):
filename = property(_getFilename) filename = property(_getFilename)
def writeBit(self, state, endian): def writeBit(self, state, endian):
assert endian in (BIG_ENDIAN, LITTLE_ENDIAN) # middle endian not yet supported
if self._bit_pos == 7: if self._bit_pos == 7:
self._bit_pos = 0 self._bit_pos = 0
if state: if state:
@ -39,6 +40,7 @@ class OutputStream(object):
self._bit_pos += 1 self._bit_pos += 1
def writeBits(self, count, value, endian): def writeBits(self, count, value, endian):
assert endian in (BIG_ENDIAN, LITTLE_ENDIAN) # middle endian not yet supported
assert 0 <= value < 2**count assert 0 <= value < 2**count
# Feed bits to align to byte address # Feed bits to align to byte address

View file

@ -1,4 +1,4 @@
from lib.hachoir_core.error import HachoirError from hachoir_core.error import HachoirError
class StreamError(HachoirError): class StreamError(HachoirError):
pass pass

View file

@ -2,12 +2,12 @@
Utilities used to convert a field to human classic reprentation of data. Utilities used to convert a field to human classic reprentation of data.
""" """
from lib.hachoir_core.tools import ( from hachoir_core.tools import (
humanDuration, humanFilesize, alignValue, humanDuration, humanFilesize, alignValue,
durationWin64 as doDurationWin64, durationWin64 as doDurationWin64,
deprecated) deprecated)
from types import FunctionType, MethodType from types import FunctionType, MethodType
from lib.hachoir_core.field import Field from hachoir_core.field import Field
def textHandler(field, handler): def textHandler(field, handler):
assert isinstance(handler, (FunctionType, MethodType)) assert isinstance(handler, (FunctionType, MethodType))

View file

@ -4,7 +4,7 @@
Various utilities. Various utilities.
""" """
from lib.hachoir_core.i18n import _, ngettext from hachoir_core.i18n import _, ngettext
import re import re
import stat import stat
from datetime import datetime, timedelta, MAXYEAR from datetime import datetime, timedelta, MAXYEAR
@ -330,7 +330,14 @@ def makeUnicode(text):
if isinstance(text, str): if isinstance(text, str):
text = unicode(text, "ISO-8859-1") text = unicode(text, "ISO-8859-1")
elif not isinstance(text, unicode): elif not isinstance(text, unicode):
text = unicode(text) try:
text = unicode(text)
except UnicodeError:
try:
text = str(text)
except Exception:
text = repr(text)
return makeUnicode(text)
text = regex_control_code.sub( text = regex_control_code.sub(
lambda regs: controlchars[ord(regs.group(1))], text) lambda regs: controlchars[ord(regs.group(1))], text)
text = re.sub(r"\\x0([0-7])(?=[^0-7]|$)", r"\\\1", text) text = re.sub(r"\\x0([0-7])(?=[^0-7]|$)", r"\\\1", text)

View file

@ -1,5 +1,5 @@
PACKAGE = "hachoir-core" PACKAGE = "hachoir-core"
VERSION = "1.3.3" VERSION = "1.3.4"
WEBSITE = 'http://bitbucket.org/haypo/hachoir/wiki/hachoir-core' WEBSITE = 'http://bitbucket.org/haypo/hachoir/wiki/hachoir-core'
LICENSE = 'GNU GPL v2' LICENSE = 'GNU GPL v2'

View file

@ -1,15 +1,15 @@
from lib.hachoir_metadata.version import VERSION as __version__ from hachoir_metadata.version import VERSION as __version__
from lib.hachoir_metadata.metadata import extractMetadata from hachoir_metadata.metadata import extractMetadata
# Just import the module, # Just import the module,
# each module use registerExtractor() method # each module use registerExtractor() method
import lib.hachoir_metadata.archive import hachoir_metadata.archive
import lib.hachoir_metadata.audio import hachoir_metadata.audio
import lib.hachoir_metadata.file_system import hachoir_metadata.file_system
import lib.hachoir_metadata.image import hachoir_metadata.image
import lib.hachoir_metadata.jpeg import hachoir_metadata.jpeg
import lib.hachoir_metadata.misc import hachoir_metadata.misc
import lib.hachoir_metadata.program import hachoir_metadata.program
import lib.hachoir_metadata.riff import hachoir_metadata.riff
import lib.hachoir_metadata.video import hachoir_metadata.video

View file

@ -1,11 +1,11 @@
from lib.hachoir_metadata.metadata_item import QUALITY_BEST, QUALITY_FASTEST from hachoir_metadata.metadata_item import QUALITY_BEST, QUALITY_FASTEST
from lib.hachoir_metadata.safe import fault_tolerant, getValue from hachoir_metadata.safe import fault_tolerant, getValue
from lib.hachoir_metadata.metadata import ( from hachoir_metadata.metadata import (
RootMetadata, Metadata, MultipleMetadata, registerExtractor) RootMetadata, Metadata, MultipleMetadata, registerExtractor)
from lib.hachoir_parser.archive import (Bzip2Parser, CabFile, GzipParser, from hachoir_parser.archive import (Bzip2Parser, CabFile, GzipParser,
TarFile, ZipFile, MarFile) TarFile, ZipFile, MarFile)
from lib.hachoir_core.tools import humanUnixAttributes from hachoir_core.tools import humanUnixAttributes
from lib.hachoir_core.i18n import _ from hachoir_core.i18n import _
def maxNbFile(meta): def maxNbFile(meta):
if meta.quality <= QUALITY_FASTEST: if meta.quality <= QUALITY_FASTEST:
@ -110,7 +110,7 @@ class CabMetadata(MultipleMetadata):
def extract(self, cab): def extract(self, cab):
if "folder[0]" in cab: if "folder[0]" in cab:
self.useFolder(cab["folder[0]"]) self.useFolder(cab["folder[0]"])
self.format_version = "Microsoft Cabinet version %s" % cab["cab_version"].display self.format_version = "Microsoft Cabinet version %s.%s" % (cab["major_version"].display, cab["minor_version"].display)
self.comment = "%s folders, %s files" % ( self.comment = "%s folders, %s files" % (
cab["nb_folder"].value, cab["nb_files"].value) cab["nb_folder"].value, cab["nb_files"].value)
max_nb = maxNbFile(self) max_nb = maxNbFile(self)

View file

@ -1,12 +1,12 @@
from lib.hachoir_metadata.metadata import (registerExtractor, from hachoir_metadata.metadata import (registerExtractor,
Metadata, RootMetadata, MultipleMetadata) Metadata, RootMetadata, MultipleMetadata)
from lib.hachoir_parser.audio import AuFile, MpegAudioFile, RealAudioFile, AiffFile, FlacParser from hachoir_parser.audio import AuFile, MpegAudioFile, RealAudioFile, AiffFile, FlacParser
from lib.hachoir_parser.container import OggFile, RealMediaFile from hachoir_parser.container import OggFile, RealMediaFile
from lib.hachoir_core.i18n import _ from hachoir_core.i18n import _
from lib.hachoir_core.tools import makePrintable, timedelta2seconds, humanBitRate from hachoir_core.tools import makePrintable, timedelta2seconds, humanBitRate
from datetime import timedelta from datetime import timedelta
from lib.hachoir_metadata.metadata_item import QUALITY_FAST, QUALITY_NORMAL, QUALITY_BEST from hachoir_metadata.metadata_item import QUALITY_FAST, QUALITY_NORMAL, QUALITY_BEST
from lib.hachoir_metadata.safe import fault_tolerant, getValue from hachoir_metadata.safe import fault_tolerant, getValue
def computeComprRate(meta, size): def computeComprRate(meta, size):
if not meta.has("duration") \ if not meta.has("duration") \

View file

@ -1,6 +1,6 @@
from lib.hachoir_metadata.metadata import RootMetadata, registerExtractor from hachoir_metadata.metadata import RootMetadata, registerExtractor
from lib.hachoir_metadata.safe import fault_tolerant from hachoir_metadata.safe import fault_tolerant
from lib.hachoir_parser.file_system import ISO9660 from hachoir_parser.file_system import ISO9660
from datetime import datetime from datetime import datetime
class ISO9660_Metadata(RootMetadata): class ISO9660_Metadata(RootMetadata):

View file

@ -1,4 +1,4 @@
from lib.hachoir_metadata.timezone import UTC from hachoir_metadata.timezone import UTC
from datetime import date, datetime from datetime import date, datetime
# Year in 1850..2030 # Year in 1850..2030

View file

@ -1,4 +1,4 @@
from lib.hachoir_core.i18n import _, ngettext from hachoir_core.i18n import _, ngettext
NB_CHANNEL_NAME = {1: _("mono"), 2: _("stereo")} NB_CHANNEL_NAME = {1: _("mono"), 2: _("stereo")}

View file

@ -1,12 +1,12 @@
from lib.hachoir_metadata.metadata import (registerExtractor, from hachoir_metadata.metadata import (registerExtractor,
Metadata, RootMetadata, MultipleMetadata) Metadata, RootMetadata, MultipleMetadata)
from lib.hachoir_parser.image import ( from hachoir_parser.image import (
BmpFile, IcoFile, PcxFile, GifFile, PngFile, TiffFile, BmpFile, IcoFile, PcxFile, GifFile, PngFile, TiffFile,
XcfFile, TargaFile, WMF_File, PsdFile) XcfFile, TargaFile, WMF_File, PsdFile)
from lib.hachoir_parser.image.png import getBitsPerPixel as pngBitsPerPixel from hachoir_parser.image.png import getBitsPerPixel as pngBitsPerPixel
from lib.hachoir_parser.image.xcf import XcfProperty from hachoir_parser.image.xcf import XcfProperty
from lib.hachoir_core.i18n import _ from hachoir_core.i18n import _
from lib.hachoir_metadata.safe import fault_tolerant from hachoir_metadata.safe import fault_tolerant
def computeComprRate(meta, compr_size): def computeComprRate(meta, compr_size):
""" """
@ -240,7 +240,7 @@ class GifMetadata(RootMetadata):
def useScreen(self, screen): def useScreen(self, screen):
self.width = screen["width"].value self.width = screen["width"].value
self.height = screen["height"].value self.height = screen["height"].value
self.bits_per_pixel = (1 + screen["bpp"].value) self.bits_per_pixel = (1 + screen["size_global_map"].value)
class TargaMetadata(RootMetadata): class TargaMetadata(RootMetadata):
def extract(self, tga): def extract(self, tga):

View file

@ -1,14 +1,14 @@
from lib.hachoir_metadata.metadata import RootMetadata, registerExtractor from hachoir_metadata.metadata import RootMetadata, registerExtractor
from lib.hachoir_metadata.image import computeComprRate from hachoir_metadata.image import computeComprRate
from lib.hachoir_parser.image.exif import ExifEntry from hachoir_parser.image.exif import IFD, BasicIFDEntry
from lib.hachoir_parser.image.jpeg import ( from hachoir_parser.image.jpeg import (
JpegFile, JpegChunk, JpegFile, JpegChunk,
QUALITY_HASH_COLOR, QUALITY_SUM_COLOR, QUALITY_HASH_COLOR, QUALITY_SUM_COLOR,
QUALITY_HASH_GRAY, QUALITY_SUM_GRAY) QUALITY_HASH_GRAY, QUALITY_SUM_GRAY)
from lib.hachoir_core.field import MissingField from hachoir_core.field import MissingField
from lib.hachoir_core.i18n import _ from hachoir_core.i18n import _
from lib.hachoir_core.tools import makeUnicode from hachoir_core.tools import makeUnicode
from lib.hachoir_metadata.safe import fault_tolerant from hachoir_metadata.safe import fault_tolerant
from datetime import datetime from datetime import datetime
def deg2float(degree, minute, second): def deg2float(degree, minute, second):
@ -17,21 +17,21 @@ def deg2float(degree, minute, second):
class JpegMetadata(RootMetadata): class JpegMetadata(RootMetadata):
EXIF_KEY = { EXIF_KEY = {
# Exif metadatas # Exif metadatas
ExifEntry.TAG_CAMERA_MANUFACTURER: "camera_manufacturer", "Make": "camera_manufacturer",
ExifEntry.TAG_CAMERA_MODEL: "camera_model", "Model": "camera_model",
ExifEntry.TAG_ORIENTATION: "image_orientation", "Orientation": "image_orientation",
ExifEntry.TAG_EXPOSURE: "camera_exposure", "ExposureTime": "camera_exposure",
ExifEntry.TAG_FOCAL: "camera_focal", "FNumber": "camera_focal",
ExifEntry.TAG_BRIGHTNESS: "camera_brightness", "BrightnessValue": "camera_brightness",
ExifEntry.TAG_APERTURE: "camera_aperture", "MaxApertureValue": "camera_aperture",
# Generic metadatas # Generic metadatas
ExifEntry.TAG_IMG_TITLE: "title", "ImageDescription": "title",
ExifEntry.TAG_SOFTWARE: "producer", "Software": "producer",
ExifEntry.TAG_FILE_TIMESTAMP: "creation_date", "DateTime": "creation_date",
ExifEntry.TAG_WIDTH: "width", "PixelXDimension": "width",
ExifEntry.TAG_HEIGHT: "height", "PixelYDimension": "height",
ExifEntry.TAG_USER_COMMENT: "comment", "UserComment": "comment",
} }
IPTC_KEY = { IPTC_KEY = {
@ -63,7 +63,8 @@ class JpegMetadata(RootMetadata):
self.extractAPP0(jpeg["app0/content"]) self.extractAPP0(jpeg["app0/content"])
if "exif/content" in jpeg: if "exif/content" in jpeg:
for ifd in jpeg.array("exif/content/ifd"): for ifd in jpeg['exif/content']:
if not isinstance(ifd, IFD): continue
for entry in ifd.array("entry"): for entry in ifd.array("entry"):
self.processIfdEntry(ifd, entry) self.processIfdEntry(ifd, entry)
self.readGPS(ifd) self.readGPS(ifd)
@ -156,7 +157,7 @@ class JpegMetadata(RootMetadata):
@fault_tolerant @fault_tolerant
def processIfdEntry(self, ifd, entry): def processIfdEntry(self, ifd, entry):
# Skip unknown tags # Skip unknown tags
tag = entry["tag"].value tag = entry["tag"].display
if tag not in self.EXIF_KEY: if tag not in self.EXIF_KEY:
return return
key = self.EXIF_KEY[tag] key = self.EXIF_KEY[tag]
@ -166,20 +167,17 @@ class JpegMetadata(RootMetadata):
return return
# Read value # Read value
if "value" in entry: value = ifd.getEntryValues(entry)[0].value
value = entry["value"].value
else:
value = ifd["value_%s" % entry.name].value
# Convert value to string # Convert value to string
if tag == ExifEntry.TAG_ORIENTATION: if tag == "Orientation":
value = self.orientation_name.get(value, value) value = self.orientation_name.get(value, value)
elif tag == ExifEntry.TAG_EXPOSURE: elif tag == "ExposureTime":
if not value: if not value:
return return
if isinstance(value, float): if isinstance(value, float):
value = (value, u"1/%g" % (1/value)) value = (value, u"1/%g" % (1/value))
elif entry["type"].value in (ExifEntry.TYPE_RATIONAL, ExifEntry.TYPE_SIGNED_RATIONAL): elif entry["type"].value in (BasicIFDEntry.TYPE_RATIONAL, BasicIFDEntry.TYPE_SIGNED_RATIONAL):
value = (value, u"%.3g" % value) value = (value, u"%.3g" % value)
# Store information # Store information
@ -197,35 +195,33 @@ class JpegMetadata(RootMetadata):
timestamp = None timestamp = None
datestamp = None datestamp = None
for entry in ifd.array("entry"): for entry in ifd.array("entry"):
tag = entry["tag"].value tag = entry["tag"].display
if tag == ExifEntry.TAG_GPS_LATITUDE_REF: values = [v.value for v in ifd.getEntryValues(entry)]
if entry["value"].value == "N": if tag == "GPSLatitudeRef":
if values[0] == "N":
latitude_ref = 1 latitude_ref = 1
else: else:
latitude_ref = -1 latitude_ref = -1
elif tag == ExifEntry.TAG_GPS_LONGITUDE_REF: elif tag == "GPSLongitudeRef":
if entry["value"].value == "E": if values[0] == "E":
longitude_ref = 1 longitude_ref = 1
else: else:
longitude_ref = -1 longitude_ref = -1
elif tag == ExifEntry.TAG_GPS_ALTITUDE_REF: elif tag == "GPSAltitudeRef":
if entry["value"].value == 1: if values[0] == 1:
altitude_ref = -1 altitude_ref = -1
else: else:
altitude_ref = 1 altitude_ref = 1
elif tag == ExifEntry.TAG_GPS_LATITUDE: elif tag == "GPSLatitude":
latitude = [ifd["value_%s[%u]" % (entry.name, index)].value for index in xrange(3)] latitude = values
elif tag == ExifEntry.TAG_GPS_LONGITUDE: elif tag == "GPSLongitude":
longitude = [ifd["value_%s[%u]" % (entry.name, index)].value for index in xrange(3)] longitude = values
elif tag == ExifEntry.TAG_GPS_ALTITUDE: elif tag == "GPSAltitude":
altitude = ifd["value_%s" % entry.name].value altitude = values[0]
elif tag == ExifEntry.TAG_GPS_DATESTAMP: elif tag == "GPSDateStamp":
datestamp = ifd["value_%s" % entry.name].value datestamp = values[0]
elif tag == ExifEntry.TAG_GPS_TIMESTAMP: elif tag == "GPSTimeStamp":
items = [ifd["value_%s[%u]" % (entry.name, index)].value for index in xrange(3)] timestamp = ':'.join(str(int(x)) for x in values)
items = map(int, items)
items = map(str, items)
timestamp = ":".join(items)
if latitude_ref and latitude: if latitude_ref and latitude:
value = deg2float(*latitude) value = deg2float(*latitude)
if latitude_ref < 0: if latitude_ref < 0:

View file

@ -1,14 +1,14 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from lib.hachoir_core.compatibility import any, sorted from hachoir_core.compatibility import any, sorted
from lib.hachoir_core.endian import endian_name from hachoir_core.endian import endian_name
from lib.hachoir_core.tools import makePrintable, makeUnicode from hachoir_core.tools import makePrintable, makeUnicode
from lib.hachoir_core.dict import Dict from hachoir_core.dict import Dict
from lib.hachoir_core.error import error, HACHOIR_ERRORS from hachoir_core.error import error, HACHOIR_ERRORS
from lib.hachoir_core.i18n import _ from hachoir_core.i18n import _
from lib.hachoir_core.log import Logger from hachoir_core.log import Logger
from lib.hachoir_metadata.metadata_item import ( from hachoir_metadata.metadata_item import (
MIN_PRIORITY, MAX_PRIORITY, QUALITY_NORMAL) MIN_PRIORITY, MAX_PRIORITY, QUALITY_NORMAL)
from lib.hachoir_metadata.register import registerAllItems from hachoir_metadata.register import registerAllItems
extractors = {} extractors = {}

View file

@ -1,7 +1,7 @@
from lib.hachoir_core.tools import makeUnicode, normalizeNewline from hachoir_core.tools import makeUnicode, normalizeNewline
from lib.hachoir_core.error import HACHOIR_ERRORS from hachoir_core.error import HACHOIR_ERRORS
from lib.hachoir_metadata import config from hachoir_metadata import config
from lib.hachoir_metadata.setter import normalizeString from hachoir_metadata.setter import normalizeString
MIN_PRIORITY = 100 MIN_PRIORITY = 100
MAX_PRIORITY = 999 MAX_PRIORITY = 999

View file

@ -1,11 +1,11 @@
from lib.hachoir_metadata.metadata import RootMetadata, registerExtractor from hachoir_metadata.metadata import RootMetadata, registerExtractor
from lib.hachoir_metadata.safe import fault_tolerant from hachoir_metadata.safe import fault_tolerant
from lib.hachoir_parser.container import SwfFile from hachoir_parser.container import SwfFile
from lib.hachoir_parser.misc import TorrentFile, TrueTypeFontFile, OLE2_File, PcfFile from hachoir_parser.misc import TorrentFile, TrueTypeFontFile, OLE2_File, PcfFile
from lib.hachoir_core.field import isString from hachoir_core.field import isString
from lib.hachoir_core.error import warning from hachoir_core.error import warning
from lib.hachoir_parser import guessParser from hachoir_parser import guessParser
from lib.hachoir_metadata.setter import normalizeString from hachoir_metadata.setter import normalizeString
class TorrentMetadata(RootMetadata): class TorrentMetadata(RootMetadata):
KEY_TO_ATTR = { KEY_TO_ATTR = {
@ -109,45 +109,42 @@ class OLE2_Metadata(RootMetadata):
def extract(self, ole2): def extract(self, ole2):
self._extract(ole2) self._extract(ole2)
def _extract(self, fieldset, main_document=True): def _extract(self, fieldset):
if main_document: try:
# _feedAll() is needed to make sure that we get all root[*] fragments
fieldset._feedAll() fieldset._feedAll()
if "root[0]" in fieldset: except StopIteration:
self.useRoot(fieldset["root[0]"]) pass
doc_summary = self.getField(fieldset, main_document, "doc_summary[0]") if "root[0]" in fieldset:
self._extract(self.getFragment(fieldset["root[0]"]))
doc_summary = self.getField(fieldset, "doc_summary[0]")
if doc_summary: if doc_summary:
self.useSummary(doc_summary, True) self.useSummary(doc_summary, True)
word_doc = self.getField(fieldset, main_document, "word_doc[0]") word_doc = self.getField(fieldset, "word_doc[0]")
if word_doc: if word_doc:
self.useWordDocument(word_doc) self.useWordDocument(word_doc)
summary = self.getField(fieldset, main_document, "summary[0]") summary = self.getField(fieldset, "summary[0]")
if summary: if summary:
self.useSummary(summary, False) self.useSummary(summary, False)
@fault_tolerant def getFragment(self, frag):
def useRoot(self, root): stream = frag.getSubIStream()
stream = root.getSubIStream()
ministream = guessParser(stream) ministream = guessParser(stream)
if not ministream: if not ministream:
warning("Unable to create the OLE2 mini stream parser!") warning("Unable to create the OLE2 mini stream parser!")
return return frag
self._extract(ministream, main_document=False) return ministream
def getField(self, fieldset, main_document, name): def getField(self, fieldset, name):
if name not in fieldset:
return None
# _feedAll() is needed to make sure that we get all fragments # _feedAll() is needed to make sure that we get all fragments
# eg. summary[0], summary[1], ..., summary[n] # eg. summary[0], summary[1], ..., summary[n]
fieldset._feedAll() try:
fieldset._feedAll()
except StopIteration:
pass
if name not in fieldset:
return None
field = fieldset[name] field = fieldset[name]
if main_document: return self.getFragment(field)
stream = field.getSubIStream()
field = guessParser(stream)
if not field:
warning("Unable to create the OLE2 parser for %s!" % name)
return None
return field
@fault_tolerant @fault_tolerant
def useSummary(self, summary, is_doc_summary): def useSummary(self, summary, is_doc_summary):
@ -161,7 +158,7 @@ class OLE2_Metadata(RootMetadata):
@fault_tolerant @fault_tolerant
def useWordDocument(self, doc): def useWordDocument(self, doc):
self.comment = "Encrypted: %s" % doc["fEncrypted"].value self.comment = "Encrypted: %s" % doc["FIB/fEncrypted"].value
@fault_tolerant @fault_tolerant
def useProperty(self, summary, property, is_doc_summary): def useProperty(self, summary, property, is_doc_summary):

View file

@ -1,6 +1,6 @@
from lib.hachoir_metadata.metadata import RootMetadata, registerExtractor from hachoir_metadata.metadata import RootMetadata, registerExtractor
from lib.hachoir_parser.program import ExeFile from hachoir_parser.program import ExeFile
from lib.hachoir_metadata.safe import fault_tolerant, getValue from hachoir_metadata.safe import fault_tolerant, getValue
class ExeMetadata(RootMetadata): class ExeMetadata(RootMetadata):
KEY_TO_ATTR = { KEY_TO_ATTR = {

View file

@ -1,64 +0,0 @@
<ui version="4.0" >
<class>Form</class>
<widget class="QWidget" name="Form" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>441</width>
<height>412</height>
</rect>
</property>
<property name="windowTitle" >
<string>hachoir-metadata</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout" >
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2" >
<item>
<widget class="QPushButton" name="open_button" >
<property name="text" >
<string>Open</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="files_combo" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Fixed" hsizetype="Expanding" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QTableWidget" name="metadata_table" >
<property name="alternatingRowColors" >
<bool>true</bool>
</property>
<property name="showGrid" >
<bool>false</bool>
</property>
<property name="rowCount" >
<number>0</number>
</property>
<property name="columnCount" >
<number>0</number>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="quit_button" >
<property name="text" >
<string>Quit</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View file

@ -1,52 +0,0 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'hachoir_metadata/qt/dialog.ui'
#
# Created: Mon Jul 26 03:10:06 2010
# by: PyQt4 UI code generator 4.7.3
#
# WARNING! All changes made in this file will be lost!
from PyQt4 import QtCore, QtGui
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(441, 412)
self.verticalLayout = QtGui.QVBoxLayout(Form)
self.verticalLayout.setObjectName("verticalLayout")
self.horizontalLayout_2 = QtGui.QHBoxLayout()
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
self.open_button = QtGui.QPushButton(Form)
self.open_button.setObjectName("open_button")
self.horizontalLayout_2.addWidget(self.open_button)
self.files_combo = QtGui.QComboBox(Form)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.files_combo.sizePolicy().hasHeightForWidth())
self.files_combo.setSizePolicy(sizePolicy)
self.files_combo.setObjectName("files_combo")
self.horizontalLayout_2.addWidget(self.files_combo)
self.verticalLayout.addLayout(self.horizontalLayout_2)
self.metadata_table = QtGui.QTableWidget(Form)
self.metadata_table.setAlternatingRowColors(True)
self.metadata_table.setShowGrid(False)
self.metadata_table.setRowCount(0)
self.metadata_table.setColumnCount(0)
self.metadata_table.setObjectName("metadata_table")
self.metadata_table.setColumnCount(0)
self.metadata_table.setRowCount(0)
self.verticalLayout.addWidget(self.metadata_table)
self.quit_button = QtGui.QPushButton(Form)
self.quit_button.setObjectName("quit_button")
self.verticalLayout.addWidget(self.quit_button)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
Form.setWindowTitle(QtGui.QApplication.translate("Form", "hachoir-metadata", None, QtGui.QApplication.UnicodeUTF8))
self.open_button.setText(QtGui.QApplication.translate("Form", "Open", None, QtGui.QApplication.UnicodeUTF8))
self.quit_button.setText(QtGui.QApplication.translate("Form", "Quit", None, QtGui.QApplication.UnicodeUTF8))

View file

@ -1,17 +1,17 @@
from lib.hachoir_core.i18n import _ from hachoir_core.i18n import _
from lib.hachoir_core.tools import ( from hachoir_core.tools import (
humanDuration, humanBitRate, humanDuration, humanBitRate,
humanFrequency, humanBitSize, humanFilesize, humanFrequency, humanBitSize, humanFilesize,
humanDatetime) humanDatetime)
from lib.hachoir_core.language import Language from hachoir_core.language import Language
from lib.hachoir_metadata.filter import Filter, NumberFilter, DATETIME_FILTER from hachoir_metadata.filter import Filter, NumberFilter, DATETIME_FILTER
from datetime import date, datetime, timedelta from datetime import date, datetime, timedelta
from lib.hachoir_metadata.formatter import ( from hachoir_metadata.formatter import (
humanAudioChannel, humanFrameRate, humanComprRate, humanAltitude, humanAudioChannel, humanFrameRate, humanComprRate, humanAltitude,
humanPixelSize, humanDPI) humanPixelSize, humanDPI)
from lib.hachoir_metadata.setter import ( from hachoir_metadata.setter import (
setDatetime, setTrackNumber, setTrackTotal, setLanguage) setDatetime, setTrackNumber, setTrackTotal, setLanguage)
from lib.hachoir_metadata.metadata_item import Data from hachoir_metadata.metadata_item import Data
MIN_SAMPLE_RATE = 1000 # 1 kHz MIN_SAMPLE_RATE = 1000 # 1 kHz
MAX_SAMPLE_RATE = 192000 # 192 kHz MAX_SAMPLE_RATE = 192000 # 192 kHz

View file

@ -2,13 +2,13 @@
Extract metadata from RIFF file format: AVI video and WAV sound. Extract metadata from RIFF file format: AVI video and WAV sound.
""" """
from lib.hachoir_metadata.metadata import Metadata, MultipleMetadata, registerExtractor from hachoir_metadata.metadata import Metadata, MultipleMetadata, registerExtractor
from lib.hachoir_metadata.safe import fault_tolerant, getValue from hachoir_metadata.safe import fault_tolerant, getValue
from lib.hachoir_parser.container.riff import RiffFile from hachoir_parser.container.riff import RiffFile
from lib.hachoir_parser.video.fourcc import UNCOMPRESSED_AUDIO from hachoir_parser.video.fourcc import UNCOMPRESSED_AUDIO
from lib.hachoir_core.tools import humanFilesize, makeUnicode, timedelta2seconds from hachoir_core.tools import humanFilesize, makeUnicode, timedelta2seconds
from lib.hachoir_core.i18n import _ from hachoir_core.i18n import _
from lib.hachoir_metadata.audio import computeComprRate as computeAudioComprRate from hachoir_metadata.audio import computeComprRate as computeAudioComprRate
from datetime import timedelta from datetime import timedelta
class RiffMetadata(MultipleMetadata): class RiffMetadata(MultipleMetadata):

View file

@ -1,4 +1,4 @@
from lib.hachoir_core.error import HACHOIR_ERRORS, warning from hachoir_core.error import HACHOIR_ERRORS, warning
def fault_tolerant(func, *args): def fault_tolerant(func, *args):
def safe_func(*args, **kw): def safe_func(*args, **kw):

View file

@ -1,10 +1,10 @@
from datetime import date, datetime from datetime import date, datetime
import re import re
from lib.hachoir_core.language import Language from hachoir_core.language import Language
from locale import setlocale, LC_ALL from locale import setlocale, LC_ALL
from time import strptime from time import strptime
from lib.hachoir_metadata.timezone import createTimezone from hachoir_metadata.timezone import createTimezone
from lib.hachoir_metadata import config from hachoir_metadata import config
NORMALIZE_REGEX = re.compile("[-/.: ]+") NORMALIZE_REGEX = re.compile("[-/.: ]+")
YEAR_REGEX1 = re.compile("^([0-9]{4})$") YEAR_REGEX1 = re.compile("^([0-9]{4})$")

View file

@ -1,14 +1,14 @@
from lib.hachoir_core.field import MissingField from hachoir_core.field import MissingField
from lib.hachoir_metadata.metadata import (registerExtractor, from hachoir_metadata.metadata import (registerExtractor,
Metadata, RootMetadata, MultipleMetadata) Metadata, RootMetadata, MultipleMetadata)
from lib.hachoir_metadata.metadata_item import QUALITY_GOOD from hachoir_metadata.metadata_item import QUALITY_GOOD
from lib.hachoir_metadata.safe import fault_tolerant from hachoir_metadata.safe import fault_tolerant
from lib.hachoir_parser.video import MovFile, AsfFile, FlvFile from hachoir_parser.video import MovFile, AsfFile, FlvFile
from lib.hachoir_parser.video.asf import Descriptor as ASF_Descriptor from hachoir_parser.video.asf import Descriptor as ASF_Descriptor
from lib.hachoir_parser.container import MkvFile from hachoir_parser.container import MkvFile
from lib.hachoir_parser.container.mkv import dateToDatetime from hachoir_parser.container.mkv import dateToDatetime
from lib.hachoir_core.i18n import _ from hachoir_core.i18n import _
from lib.hachoir_core.tools import makeUnicode, makePrintable, timedelta2seconds from hachoir_core.tools import makeUnicode, makePrintable, timedelta2seconds
from datetime import timedelta from datetime import timedelta
class MkvMetadata(MultipleMetadata): class MkvMetadata(MultipleMetadata):
@ -59,9 +59,10 @@ class MkvMetadata(MultipleMetadata):
def trackCommon(self, track, meta): def trackCommon(self, track, meta):
if "Name/unicode" in track: if "Name/unicode" in track:
meta.title = track["Name/unicode"].value meta.title = track["Name/unicode"].value
if "Language/string" in track \ if "Language/string" in track:
and track["Language/string"].value not in ("mis", "und"):
meta.language = track["Language/string"].value meta.language = track["Language/string"].value
else:
meta.language = "eng"
def processVideo(self, track): def processVideo(self, track):
video = Metadata(self) video = Metadata(self)
@ -222,7 +223,7 @@ class MovMetadata(RootMetadata):
self.last_modification = hdr["lastmod_date"].value self.last_modification = hdr["lastmod_date"].value
self.duration = timedelta(seconds=float(hdr["duration"].value) / hdr["time_scale"].value) self.duration = timedelta(seconds=float(hdr["duration"].value) / hdr["time_scale"].value)
self.comment = _("Play speed: %.1f%%") % (hdr["play_speed"].value*100) self.comment = _("Play speed: %.1f%%") % (hdr["play_speed"].value*100)
self.comment = _("User volume: %.1f%%") % (float(hdr["volume"].value)*100//255) self.comment = _("User volume: %.1f%%") % (float(hdr["volume"].value)*100)
@fault_tolerant @fault_tolerant
def processTrackHeader(self, hdr): def processTrackHeader(self, hdr):

View file

@ -1,7 +1,7 @@
from lib.hachoir_parser.version import __version__ from hachoir_parser.version import __version__
from lib.hachoir_parser.parser import ValidateError, HachoirParser, Parser from hachoir_parser.parser import ValidateError, HachoirParser, Parser
from lib.hachoir_parser.parser_list import ParserList, HachoirParserList from hachoir_parser.parser_list import ParserList, HachoirParserList
from lib.hachoir_parser.guess import (QueryParser, guessParser, createParser) from hachoir_parser.guess import (QueryParser, guessParser, createParser)
from lib.hachoir_parser import (archive, audio, container, from hachoir_parser import (archive, audio, container,
file_system, image, game, misc, network, program, video) file_system, image, game, misc, network, program, video)

View file

@ -1,12 +1,13 @@
from lib.hachoir_parser.archive.ace import AceFile from hachoir_parser.archive.ace import AceFile
from lib.hachoir_parser.archive.ar import ArchiveFile from hachoir_parser.archive.ar import ArchiveFile
from lib.hachoir_parser.archive.bzip2_parser import Bzip2Parser from hachoir_parser.archive.bzip2_parser import Bzip2Parser
from lib.hachoir_parser.archive.cab import CabFile from hachoir_parser.archive.cab import CabFile
from lib.hachoir_parser.archive.gzip_parser import GzipParser from hachoir_parser.archive.gzip_parser import GzipParser
from lib.hachoir_parser.archive.tar import TarFile from hachoir_parser.archive.tar import TarFile
from lib.hachoir_parser.archive.zip import ZipFile from hachoir_parser.archive.zip import ZipFile
from lib.hachoir_parser.archive.rar import RarFile from hachoir_parser.archive.rar import RarFile
from lib.hachoir_parser.archive.rpm import RpmFile from hachoir_parser.archive.rpm import RpmFile
from lib.hachoir_parser.archive.sevenzip import SevenZipParser from hachoir_parser.archive.sevenzip import SevenZipParser
from lib.hachoir_parser.archive.mar import MarFile from hachoir_parser.archive.mar import MarFile
from hachoir_parser.archive.mozilla_ar import MozillaArchive
from hachoir_parser.archive.zlib import ZlibData

View file

@ -11,15 +11,15 @@ Author: Christophe Gisquet <christophe.gisquet@free.fr>
Creation date: 19 january 2006 Creation date: 19 january 2006
""" """
from lib.hachoir_parser import Parser from hachoir_parser import Parser
from lib.hachoir_core.field import (StaticFieldSet, FieldSet, from hachoir_core.field import (StaticFieldSet, FieldSet,
Bit, Bits, NullBits, RawBytes, Enum, Bit, Bits, NullBits, RawBytes, Enum,
UInt8, UInt16, UInt32, UInt8, UInt16, UInt32,
PascalString8, PascalString16, String, PascalString8, PascalString16, String,
TimeDateMSDOS32) TimeDateMSDOS32)
from lib.hachoir_core.text_handler import textHandler, filesizeHandler, hexadecimal from hachoir_core.text_handler import textHandler, filesizeHandler, hexadecimal
from lib.hachoir_core.endian import LITTLE_ENDIAN from hachoir_core.endian import LITTLE_ENDIAN
from lib.hachoir_parser.common.msdos import MSDOSFileAttr32 from hachoir_parser.common.msdos import MSDOSFileAttr32
MAGIC = "**ACE**" MAGIC = "**ACE**"

View file

@ -2,10 +2,10 @@
GNU ar archive : archive file (.a) and Debian (.deb) archive. GNU ar archive : archive file (.a) and Debian (.deb) archive.
""" """
from lib.hachoir_parser import Parser from hachoir_parser import Parser
from lib.hachoir_core.field import (FieldSet, ParserError, from hachoir_core.field import (FieldSet, ParserError,
String, RawBytes, UnixLine) String, RawBytes, UnixLine)
from lib.hachoir_core.endian import BIG_ENDIAN from hachoir_core.endian import BIG_ENDIAN
class ArchiveFileEntry(FieldSet): class ArchiveFileEntry(FieldSet):
def createFields(self): def createFields(self):

View file

@ -1,14 +1,18 @@
""" """
BZIP2 archive file BZIP2 archive file
Author: Victor Stinner Author: Victor Stinner, Robert Xiao
""" """
from lib.hachoir_parser import Parser from hachoir_parser import Parser
from lib.hachoir_core.field import (ParserError, String, from hachoir_core.tools import paddingSize
Bytes, Character, UInt8, UInt32, CompressedField) from hachoir_core.field import (Field, FieldSet, GenericVector,
from lib.hachoir_core.endian import LITTLE_ENDIAN ParserError, String,
from lib.hachoir_core.text_handler import textHandler, hexadecimal PaddingBits, Bit, Bits, Character,
UInt32, Enum, CompressedField)
from hachoir_core.endian import BIG_ENDIAN
from hachoir_core.text_handler import textHandler, hexadecimal
from hachoir_parser.archive.zlib import build_tree, HuffmanCode
try: try:
from bz2 import BZ2Decompressor from bz2 import BZ2Decompressor
@ -27,6 +31,152 @@ try:
except ImportError: except ImportError:
has_deflate = False has_deflate = False
class ZeroTerminatedNumber(Field):
"""Zero (bit) terminated number: e.g. 11110 is 4."""
def __init__(self, parent, name, description=None):
Field.__init__(self, parent, name, 0, description)
endian = self.parent.endian
stream = self.parent.stream
addr = self.absolute_address
value = 0
while True:
bit = stream.readBits(addr, 1, endian)
addr += 1
self._size += 1
if not bit:
break
value += 1
self._value = value
def createValue(self):
return self._value
def move_to_front(l, c):
l[:] = l[c:c+1] + l[0:c] + l[c+1:]
class Bzip2Bitmap(FieldSet):
def __init__(self, parent, name, nb_items, start_index, *args, **kwargs):
FieldSet.__init__(self, parent, name, *args, **kwargs)
self.nb_items = nb_items
self.start_index = start_index
def createFields(self):
for i in xrange(self.start_index, self.start_index+self.nb_items):
yield Bit(self, "symbol_used[%i]"%i, "Is the symbol %i (%r) used?"%(i, chr(i)))
class Bzip2Lengths(FieldSet):
def __init__(self, parent, name, symbols, *args, **kwargs):
FieldSet.__init__(self, parent, name, *args, **kwargs)
self.symbols = symbols
def createFields(self):
yield Bits(self, "start_length", 5)
length = self["start_length"].value
lengths = []
for i in xrange(self.symbols):
while True:
bit = Bit(self, "change_length[%i][]"%i, "Should the length be changed for symbol %i?"%i)
yield bit
if not bit.value:
break
else:
bit = Enum(Bit(self, "length_decrement[%i][]"%i, "Decrement the value?"), {True: "Decrement", False: "Increment"})
yield bit
if bit.value:
length -= 1
else:
length += 1
lengths.append(length)
self.final_length = length
self.tree = build_tree(lengths)
class Bzip2Selectors(FieldSet):
def __init__(self, parent, name, ngroups, *args, **kwargs):
FieldSet.__init__(self, parent, name, *args, **kwargs)
self.groups = range(ngroups)
def createFields(self):
for i in xrange(self["../selectors_used"].value):
field = ZeroTerminatedNumber(self, "selector_list[]")
move_to_front(self.groups, field.value)
field.realvalue = self.groups[0]
field._description = "MTF'ed selector index: raw value %i, real value %i"%(field.value, field.realvalue)
yield field
class Bzip2Block(FieldSet):
def createFields(self):
yield textHandler(Bits(self, "blockheader", 48, "Block header"), hexadecimal)
if self["blockheader"].value != 0x314159265359: # pi
raise ParserError("Invalid block header!")
yield textHandler(UInt32(self, "crc32", "CRC32 for this block"), hexadecimal)
yield Bit(self, "randomized", "Is this block randomized?")
yield Bits(self, "orig_bwt_pointer", 24, "Starting pointer into BWT after untransform")
yield GenericVector(self, "huffman_used_map", 16, Bit, 'block_used', "Bitmap showing which blocks (representing 16 literals each) are in use")
symbols_used = []
for index, block_used in enumerate(self["huffman_used_map"].array('block_used')):
if block_used.value:
start_index = index*16
field = Bzip2Bitmap(self, "huffman_used_bitmap[%i]"%index, 16, start_index, "Bitmap for block %i (literals %i to %i) showing which symbols are in use"%(index, start_index, start_index + 15))
yield field
for i, used in enumerate(field):
if used.value:
symbols_used.append(start_index + i)
yield Bits(self, "huffman_groups", 3, "Number of different Huffman tables in use")
yield Bits(self, "selectors_used", 15, "Number of times the Huffman tables are switched")
yield Bzip2Selectors(self, "selectors_list", self["huffman_groups"].value)
trees = []
for group in xrange(self["huffman_groups"].value):
field = Bzip2Lengths(self, "huffman_lengths[]", len(symbols_used)+2)
yield field
trees.append(field.tree)
counter = 0
rle_run = 0
selector_tree = None
while True:
if counter%50 == 0:
select_id = self["selectors_list"].array("selector_list")[counter//50].realvalue
selector_tree = trees[select_id]
field = HuffmanCode(self, "huffman_code[]", selector_tree)
if field.realvalue in [0, 1]:
# RLE codes
if rle_run == 0:
rle_power = 1
rle_run += (field.realvalue + 1) * rle_power
rle_power <<= 1
field._description = "RLE Run Code %i (for %r); Total accumulated run %i (Huffman Code %i)" % (field.realvalue, chr(symbols_used[0]), rle_run, field.value)
elif field.realvalue == len(symbols_used)+1:
field._description = "Block Terminator (%i) (Huffman Code %i)"%(field.realvalue, field.value)
yield field
break
else:
rle_run = 0
move_to_front(symbols_used, field.realvalue-1)
field._description = "Literal %r (value %i) (Huffman Code %i)"%(chr(symbols_used[0]), field.realvalue, field.value)
yield field
if field.realvalue == len(symbols_used)+1:
break
counter += 1
class Bzip2Stream(FieldSet):
START_BLOCK = 0x314159265359 # pi
END_STREAM = 0x177245385090 # sqrt(pi)
def createFields(self):
end = False
while not end:
marker = self.stream.readBits(self.absolute_address + self.current_size, 48, self.endian)
if marker == self.START_BLOCK:
yield Bzip2Block(self, "block[]")
elif marker == self.END_STREAM:
yield textHandler(Bits(self, "stream_end", 48, "End-of-stream marker"), hexadecimal)
yield textHandler(UInt32(self, "crc32", "CRC32 for entire stream"), hexadecimal)
padding = paddingSize(self.current_size, 8)
if padding:
yield PaddingBits(self, "padding[]", padding)
end = True
else:
raise ParserError("Invalid marker 0x%02X!"%marker)
class Bzip2Parser(Parser): class Bzip2Parser(Parser):
PARSER_TAGS = { PARSER_TAGS = {
"id": "bzip2", "id": "bzip2",
@ -37,7 +187,7 @@ class Bzip2Parser(Parser):
"magic": (('BZh', 0),), "magic": (('BZh', 0),),
"description": "bzip2 archive" "description": "bzip2 archive"
} }
endian = LITTLE_ENDIAN endian = BIG_ENDIAN
def validate(self): def validate(self):
if self.stream.readBytes(0, 3) != 'BZh': if self.stream.readBytes(0, 3) != 'BZh':
@ -50,18 +200,6 @@ class Bzip2Parser(Parser):
yield String(self, "id", 3, "Identifier (BZh)", charset="ASCII") yield String(self, "id", 3, "Identifier (BZh)", charset="ASCII")
yield Character(self, "blocksize", "Block size (KB of memory needed to uncompress)") yield Character(self, "blocksize", "Block size (KB of memory needed to uncompress)")
yield UInt8(self, "blockheader", "Block header")
if self["blockheader"].value == 0x17:
yield String(self, "id2", 4, "Identifier2 (re8P)", charset="ASCII")
yield UInt8(self, "id3", "Identifier3 (0x90)")
elif self["blockheader"].value == 0x31:
yield String(self, "id2", 5, "Identifier 2 (AY&SY)", charset="ASCII")
if self["id2"].value != "AY&SY":
raise ParserError("Invalid identifier 2 (AY&SY)!")
else:
raise ParserError("Invalid block header!")
yield textHandler(UInt32(self, "crc32", "CRC32"), hexadecimal)
if self._size is None: # TODO: is it possible to handle piped input? if self._size is None: # TODO: is it possible to handle piped input?
raise NotImplementedError raise NotImplementedError
@ -73,7 +211,7 @@ class Bzip2Parser(Parser):
break break
else: else:
filename = None filename = None
data = Bytes(self, "file", size) data = Bzip2Stream(self, "file", size=size*8)
if has_deflate: if has_deflate:
CompressedField(self, Bunzip2) CompressedField(self, Bunzip2)
def createInputStream(**args): def createInputStream(**args):

View file

@ -1,18 +1,24 @@
""" """
Microsoft Cabinet (CAB) archive. Microsoft Cabinet (CAB) archive.
Author: Victor Stinner Author: Victor Stinner, Robert Xiao
Creation date: 31 january 2007 Creation date: 31 january 2007
"""
from lib.hachoir_parser import Parser - Microsoft Cabinet SDK
from lib.hachoir_core.field import (FieldSet, Enum, http://msdn2.microsoft.com/en-us/library/ms974336.aspx
"""
from __future__ import absolute_import
from hachoir_parser import Parser
from hachoir_core.field import (FieldSet, Enum,
CString, String, CString, String,
UInt16, UInt32, Bit, Bits, PaddingBits, NullBits, UInt8, UInt16, UInt32, Bit, Bits, PaddingBits, NullBits,
DateTimeMSDOS32, RawBytes) DateTimeMSDOS32, RawBytes)
from lib.hachoir_parser.common.msdos import MSDOSFileAttr16 from hachoir_core.text_handler import textHandler, hexadecimal, filesizeHandler
from lib.hachoir_core.text_handler import textHandler, hexadecimal, filesizeHandler from hachoir_core.endian import LITTLE_ENDIAN
from lib.hachoir_core.endian import LITTLE_ENDIAN from hachoir_core.tools import paddingSize
from hachoir_core.stream import StringInputStream
from hachoir_parser.archive.lzx import LZXStream, lzx_decompress
from hachoir_parser.archive.zlib import DeflateBlock
MAX_NB_FOLDER = 30 MAX_NB_FOLDER = 30
@ -26,38 +32,54 @@ COMPRESSION_NAME = {
class Folder(FieldSet): class Folder(FieldSet):
def createFields(self): def createFields(self):
yield UInt32(self, "off_data", "Offset of data") yield UInt32(self, "offset", "Offset to data (from file start)")
yield UInt16(self, "cf_data") yield UInt16(self, "data_blocks", "Number of data blocks which are in this cabinet")
yield Enum(Bits(self, "compr_method", 4, "Compression method"), COMPRESSION_NAME) yield Enum(Bits(self, "compr_method", 4, "Compression method"), COMPRESSION_NAME)
yield Bits(self, "compr_level", 5, "Compression level") if self["compr_method"].value in [2, 3]: # Quantum or LZX use compression level
yield PaddingBits(self, "padding", 7) yield PaddingBits(self, "padding[]", 4)
yield Bits(self, "compr_level", 5, "Compression level")
yield PaddingBits(self, "padding[]", 3)
else:
yield PaddingBits(self, "padding[]", 12)
if self["../flags/has_reserved"].value and self["../reserved_folder_size"].value:
yield RawBytes(self, "reserved_folder", self["../reserved_folder_size"].value, "Per-folder reserved area")
def createDescription(self): def createDescription(self):
text= "Folder: compression %s" % self["compr_method"].display text= "Folder: compression %s" % self["compr_method"].display
if self["compr_method"].value != COMPRESSION_NONE: if self["compr_method"].value in [2, 3]: # Quantum or LZX use compression level
text += " (level %u)" % self["compr_level"].value text += " (level %u: window size %u)" % (self["compr_level"].value, 2**self["compr_level"].value)
return text return text
class CabFileAttributes(FieldSet):
def createFields(self):
yield Bit(self, "readonly")
yield Bit(self, "hidden")
yield Bit(self, "system")
yield Bits(self, "reserved[]", 2)
yield Bit(self, "archive", "Has the file been modified since the last backup?")
yield Bit(self, "exec", "Run file after extraction?")
yield Bit(self, "name_is_utf", "Is the filename using UTF-8?")
yield Bits(self, "reserved[]", 8)
class File(FieldSet): class File(FieldSet):
def createFields(self): def createFields(self):
yield filesizeHandler(UInt32(self, "filesize", "Uncompressed file size")) yield filesizeHandler(UInt32(self, "filesize", "Uncompressed file size"))
yield UInt32(self, "offset", "File offset after decompression") yield UInt32(self, "folder_offset", "File offset in uncompressed folder")
yield UInt16(self, "iFolder", "file control id") yield Enum(UInt16(self, "folder_index", "Containing folder ID (index)"), {
0xFFFD:"Folder continued from previous cabinet (real folder ID = 0)",
0xFFFE:"Folder continued to next cabinet (real folder ID = %i)" % (self["../nb_folder"].value - 1),
0xFFFF:"Folder spanning previous, current and next cabinets (real folder ID = 0)"})
yield DateTimeMSDOS32(self, "timestamp") yield DateTimeMSDOS32(self, "timestamp")
yield MSDOSFileAttr16(self, "attributes") yield CabFileAttributes(self, "attributes")
yield CString(self, "filename", charset="ASCII") if self["attributes/name_is_utf"].value:
yield CString(self, "filename", charset="UTF-8")
else:
yield CString(self, "filename", charset="ASCII")
def createDescription(self): def createDescription(self):
return "File %s (%s)" % ( return "File %s (%s)" % (
self["filename"].display, self["filesize"].display) self["filename"].display, self["filesize"].display)
class Reserved(FieldSet):
def createFields(self):
yield UInt32(self, "size")
size = self["size"].value
if size:
yield RawBytes(self, "data", size)
class Flags(FieldSet): class Flags(FieldSet):
static_size = 16 static_size = 16
def createFields(self): def createFields(self):
@ -66,6 +88,111 @@ class Flags(FieldSet):
yield Bit(self, "has_reserved") yield Bit(self, "has_reserved")
yield NullBits(self, "padding", 13) yield NullBits(self, "padding", 13)
class FragmentGroup:
def __init__(self, parser):
self.items = []
self.parser = parser
self.args = {}
def add(self, item):
self.items.append(item)
def createInputStream(self):
# FIXME: Use lazy stream creation
data = []
for item in self.items:
data.append( item["rawdata"].value )
data = "".join(data)
# FIXME: Use smarter code to send arguments
self.args["compr_level"] = self.items[0].parent.parent.folder["compr_level"].value
tags = {"class": self.parser, "args": self.args}
tags = tags.iteritems()
return StringInputStream(data, "<fragment group>", tags=tags)
class CustomFragment(FieldSet):
def __init__(self, parent, name, size, parser, description=None, group=None):
FieldSet.__init__(self, parent, name, description, size=size)
if not group:
group = FragmentGroup(parser)
self.field_size = size
self.group = group
self.group.add(self)
def createFields(self):
yield RawBytes(self, "rawdata", self.field_size//8)
def _createInputStream(self, **args):
return self.group.createInputStream()
class DataBlock(FieldSet):
def __init__(self, *args, **kwargs):
FieldSet.__init__(self, *args, **kwargs)
size = (self["size"].value + 8) * 8 # +8 for header values
if self["/flags/has_reserved"].value:
size += self["/reserved_data_size"].value * 8
self._size = size
def createFields(self):
yield textHandler(UInt32(self, "crc32"), hexadecimal)
yield UInt16(self, "size")
yield UInt16(self, "uncompressed_size", "If this is 0, this block is continued in a subsequent cabinet")
if self["/flags/has_reserved"].value and self["/reserved_data_size"].value:
yield RawBytes(self, "reserved_data", self["/reserved_data_size"].value, "Per-datablock reserved area")
compr_method = self.parent.folder["compr_method"].value
if compr_method == 0: # Uncompressed
yield RawBytes(self, "data", self["size"].value, "Folder Data")
self.parent.uncompressed_data += self["data"].value
elif compr_method == 1: # MSZIP
yield String(self, "mszip_signature", 2, "MSZIP Signature (CK)")
yield DeflateBlock(self, "deflate_block", self.parent.uncompressed_data)
padding = paddingSize(self.current_size, 8)
if padding:
yield PaddingBits(self, "padding[]", padding)
self.parent.uncompressed_data = self["deflate_block"].uncomp_data
elif compr_method == 2: # Quantum
yield RawBytes(self, "compr_data", self["size"].value, "Compressed Folder Data")
elif compr_method == 3: # LZX
group = getattr(self.parent.folder, "lzx_group", None)
field = CustomFragment(self, "data", self["size"].value*8, LZXStream, "LZX data fragment", group)
self.parent.folder.lzx_group = field.group
yield field
class FolderParser(Parser):
endian = LITTLE_ENDIAN
def createFields(self):
for file in sorted(self.files, key=lambda x:x["folder_offset"].value):
padding = self.seekByte(file["folder_offset"].value)
if padding:
yield padding
yield RawBytes(self, "file[]", file["filesize"].value, file.description)
class FolderData(FieldSet):
def __init__(self, parent, name, folder, files, *args, **kwargs):
FieldSet.__init__(self, parent, name, *args, **kwargs)
def createInputStream(cis, source=None, **args):
stream = cis(source=source)
tags = args.setdefault("tags",[])
tags.extend(stream.tags)
tags.append(( "class", FolderParser ))
tags.append(( "args", {'files': files} ))
for unused in self:
pass
if folder["compr_method"].value == 3: # LZX
self.uncompressed_data = lzx_decompress(self["block[0]/data"].getSubIStream(), folder["compr_level"].value)
return StringInputStream(self.uncompressed_data, source=source, **args)
self.setSubIStream(createInputStream)
self.files = files
self.folder = folder # Folder fieldset
def createFields(self):
self.uncompressed_data = ""
for index in xrange(self.folder["data_blocks"].value):
block = DataBlock(self, "block[]")
for i in block:
pass
yield block
class CabFile(Parser): class CabFile(Parser):
endian = LITTLE_ENDIAN endian = LITTLE_ENDIAN
MAGIC = "MSCF" MAGIC = "MSCF"
@ -82,8 +209,8 @@ class CabFile(Parser):
def validate(self): def validate(self):
if self.stream.readBytes(0, 4) != self.MAGIC: if self.stream.readBytes(0, 4) != self.MAGIC:
return "Invalid magic" return "Invalid magic"
if self["cab_version"].value != 0x0103: if self["major_version"].value != 1 or self["minor_version"].value != 3:
return "Unknown version (%s)" % self["cab_version"].display return "Unknown version (%i.%i)" % (self["major_version"].value, self["minor_version"].value)
if not (1 <= self["nb_folder"].value <= MAX_NB_FOLDER): if not (1 <= self["nb_folder"].value <= MAX_NB_FOLDER):
return "Invalid number of folder (%s)" % self["nb_folder"].value return "Invalid number of folder (%s)" % self["nb_folder"].value
return True return True
@ -95,26 +222,54 @@ class CabFile(Parser):
yield textHandler(UInt32(self, "fld_checksum", "Folders checksum (0 if not used)"), hexadecimal) yield textHandler(UInt32(self, "fld_checksum", "Folders checksum (0 if not used)"), hexadecimal)
yield UInt32(self, "off_file", "Offset of first file") yield UInt32(self, "off_file", "Offset of first file")
yield textHandler(UInt32(self, "files_checksum", "Files checksum (0 if not used)"), hexadecimal) yield textHandler(UInt32(self, "files_checksum", "Files checksum (0 if not used)"), hexadecimal)
yield textHandler(UInt16(self, "cab_version", "Cabinet version"), hexadecimal) yield UInt8(self, "minor_version", "Minor version (should be 3)")
yield UInt8(self, "major_version", "Major version (should be 1)")
yield UInt16(self, "nb_folder", "Number of folders") yield UInt16(self, "nb_folder", "Number of folders")
yield UInt16(self, "nb_files", "Number of files") yield UInt16(self, "nb_files", "Number of files")
yield Flags(self, "flags") yield Flags(self, "flags")
yield UInt16(self, "setid") yield UInt16(self, "setid")
yield UInt16(self, "number", "Zero-based cabinet number") yield UInt16(self, "cabinet_serial", "Zero-based cabinet number")
# --- TODO: Support flags
if self["flags/has_reserved"].value: if self["flags/has_reserved"].value:
yield Reserved(self, "reserved") yield UInt16(self, "reserved_header_size", "Size of per-cabinet reserved area")
#(3) Previous cabinet name, if CAB_HEADER.flags & CAB_FLAG_HASPREV yield UInt8(self, "reserved_folder_size", "Size of per-folder reserved area")
#(4) Previous disk name, if CAB_HEADER.flags & CAB_FLAG_HASPREV yield UInt8(self, "reserved_data_size", "Size of per-datablock reserved area")
#(5) Next cabinet name, if CAB_HEADER.flags & CAB_FLAG_HASNEXT if self["reserved_header_size"].value:
#(6) Next disk name, if CAB_HEADER.flags & CAB_FLAG_HASNEXT yield RawBytes(self, "reserved_header", self["reserved_header_size"].value, "Per-cabinet reserved area")
# ---- if self["flags/has_previous"].value:
yield CString(self, "previous_cabinet", "File name of previous cabinet", charset="ASCII")
yield CString(self, "previous_disk", "Description of disk/media on which previous cabinet resides", charset="ASCII")
if self["flags/has_next"].value:
yield CString(self, "next_cabinet", "File name of next cabinet", charset="ASCII")
yield CString(self, "next_disk", "Description of disk/media on which next cabinet resides", charset="ASCII")
folders = []
files = []
for index in xrange(self["nb_folder"].value): for index in xrange(self["nb_folder"].value):
yield Folder(self, "folder[]") folder = Folder(self, "folder[]")
yield folder
folders.append(folder)
for index in xrange(self["nb_files"].value): for index in xrange(self["nb_files"].value):
yield File(self, "file[]") file = File(self, "file[]")
yield file
files.append(file)
folders = sorted(enumerate(folders), key=lambda x:x[1]["offset"].value)
for i in xrange(len(folders)):
index, folder = folders[i]
padding = self.seekByte(folder["offset"].value)
if padding:
yield padding
files = []
for file in files:
if file["folder_index"].value == index:
files.append(file)
if i+1 == len(folders):
size = (self.size // 8) - folder["offset"].value
else:
size = (folders[i+1][1]["offset"].value) - folder["offset"].value
yield FolderData(self, "folder_data[%i]" % index, folder, files, size=size*8)
end = self.seekBit(self.size, "endraw") end = self.seekBit(self.size, "endraw")
if end: if end:

View file

@ -4,14 +4,14 @@ GZIP archive parser.
Author: Victor Stinner Author: Victor Stinner
""" """
from lib.hachoir_parser import Parser from hachoir_parser import Parser
from lib.hachoir_core.field import ( from hachoir_core.field import (
UInt8, UInt16, UInt32, Enum, TimestampUnix32, UInt8, UInt16, UInt32, Enum, TimestampUnix32,
Bit, CString, SubFile, Bit, CString, SubFile,
NullBits, Bytes, RawBytes) NullBits, Bytes, RawBytes)
from lib.hachoir_core.text_handler import textHandler, hexadecimal, filesizeHandler from hachoir_core.text_handler import textHandler, hexadecimal, filesizeHandler
from lib.hachoir_core.endian import LITTLE_ENDIAN from hachoir_core.endian import LITTLE_ENDIAN
from lib.hachoir_parser.common.deflate import Deflate from hachoir_parser.common.deflate import Deflate
class GzipParser(Parser): class GzipParser(Parser):
endian = LITTLE_ENDIAN endian = LITTLE_ENDIAN

View file

@ -0,0 +1,267 @@
"""LZX data stream parser.
Also includes a decompression function (slow!!) which can decompress
LZX data stored in a Hachoir stream.
Author: Robert Xiao
Creation date: July 18, 2007
"""
from hachoir_parser import Parser
from hachoir_core.field import (FieldSet,
UInt32, Bit, Bits, PaddingBits,
RawBytes, ParserError)
from hachoir_core.endian import MIDDLE_ENDIAN, LITTLE_ENDIAN
from hachoir_core.tools import paddingSize, alignValue
from hachoir_parser.archive.zlib import build_tree, HuffmanCode, extend_data
from hachoir_core.bits import str2long
import new # for instancemethod
class LZXPreTreeEncodedTree(FieldSet):
def __init__(self, parent, name, num_elements, *args, **kwargs):
FieldSet.__init__(self, parent, name, *args, **kwargs)
self.num_elements = num_elements
def createFields(self):
for i in xrange(20):
yield Bits(self, "pretree_lengths[]", 4)
pre_tree = build_tree([self['pretree_lengths[%d]'%x].value for x in xrange(20)])
if not hasattr(self.root, "lzx_tree_lengths_"+self.name):
self.lengths = [0] * self.num_elements
setattr(self.root, "lzx_tree_lengths_"+self.name, self.lengths)
else:
self.lengths = getattr(self.root, "lzx_tree_lengths_"+self.name)
i = 0
while i < self.num_elements:
field = HuffmanCode(self, "tree_code[]", pre_tree)
if field.realvalue <= 16:
self.lengths[i] = (self.lengths[i] - field.realvalue) % 17
field._description = "Literal tree delta length %i (new length value %i for element %i)" % (
field.realvalue, self.lengths[i], i)
i += 1
yield field
elif field.realvalue == 17:
field._description = "Tree Code 17: Zeros for 4-19 elements"
yield field
extra = Bits(self, "extra[]", 4)
zeros = 4 + extra.value
extra._description = "Extra bits: zeros for %i elements (elements %i through %i)" % (zeros, i, i+zeros-1)
yield extra
self.lengths[i:i+zeros] = [0] * zeros
i += zeros
elif field.realvalue == 18:
field._description = "Tree Code 18: Zeros for 20-51 elements"
yield field
extra = Bits(self, "extra[]", 5)
zeros = 20 + extra.value
extra._description = "Extra bits: zeros for %i elements (elements %i through %i)" % (zeros, i, i+zeros-1)
yield extra
self.lengths[i:i+zeros] = [0] * zeros
i += zeros
elif field.realvalue == 19:
field._description = "Tree Code 19: Same code for 4-5 elements"
yield field
extra = Bits(self, "extra[]", 1)
run = 4 + extra.value
extra._description = "Extra bits: run for %i elements (elements %i through %i)" % (run, i, i+run-1)
yield extra
newfield = HuffmanCode(self, "tree_code[]", pre_tree)
assert newfield.realvalue <= 16
newfield._description = "Literal tree delta length %i (new length value %i for elements %i through %i)" % (
newfield.realvalue, self.lengths[i], i, i+run-1)
self.lengths[i:i+run] = [(self.lengths[i] - newfield.realvalue) % 17] * run
i += run
yield newfield
class LZXBlock(FieldSet):
WINDOW_SIZE = {15:30,
16:32,
17:34,
18:36,
19:38,
20:42,
21:50}
POSITION_SLOTS = {0:(0,0,0),
1:(1,1,0),
2:(2,2,0),
3:(3,3,0),
4:(4,5,1),
5:(6,7,1),
6:(8,11,2),
7:(12,15,2),
8:(16,23,3),
9:(24,31,3),
10:(32,47,4),
11:(48,63,4),
12:(64,95,5),
13:(96,127,5),
14:(128,191,6),
15:(192,255,6),
16:(256,383,7),
17:(384,511,7),
18:(512,767,8),
19:(768,1023,8),
20:(1024,1535,9),
21:(1536,2047,9),
22:(2048,3071,10),
23:(3072,4095,10),
24:(4096,6143,11),
25:(6144,8191,11),
26:(8192,12287,12),
27:(12288,16383,12),
28:(16384,24575,13),
29:(24576,32767,13),
30:(32768,49151,14),
31:(49152,65535,14),
32:(65536,98303,15),
33:(98304,131071,15),
34:(131072,196607,16),
35:(196608,262143,16),
36:(262144,393215,17),
37:(393216,524287,17),
38:(524288,655359,17),
39:(655360,786431,17),
40:(786432,917503,17),
41:(917504,1048575,17),
42:(1048576,1179647,17),
43:(1179648,1310719,17),
44:(1310720,1441791,17),
45:(1441792,1572863,17),
46:(1572864,1703935,17),
47:(1703936,1835007,17),
48:(1835008,1966079,17),
49:(1966080,2097151,17),
}
def createFields(self):
yield Bits(self, "block_type", 3)
yield Bits(self, "block_size", 24)
self.uncompressed_size = self["block_size"].value
self.compression_level = self.root.compr_level
self.window_size = self.WINDOW_SIZE[self.compression_level]
self.block_type = self["block_type"].value
curlen = len(self.parent.uncompressed_data)
if self.block_type in (1, 2): # Verbatim or aligned offset block
if self.block_type == 2:
for i in xrange(8):
yield Bits(self, "aligned_len[]", 3)
aligned_tree = build_tree([self['aligned_len[%d]'%i].value for i in xrange(8)])
yield LZXPreTreeEncodedTree(self, "main_tree_start", 256)
yield LZXPreTreeEncodedTree(self, "main_tree_rest", self.window_size * 8)
main_tree = build_tree(self["main_tree_start"].lengths + self["main_tree_rest"].lengths)
yield LZXPreTreeEncodedTree(self, "length_tree", 249)
length_tree = build_tree(self["length_tree"].lengths)
current_decoded_size = 0
while current_decoded_size < self.uncompressed_size:
if (curlen+current_decoded_size) % 32768 == 0 and (curlen+current_decoded_size) != 0:
padding = paddingSize(self.address + self.current_size, 16)
if padding:
yield PaddingBits(self, "padding[]", padding)
field = HuffmanCode(self, "main_code[]", main_tree)
if field.realvalue < 256:
field._description = "Literal value %r" % chr(field.realvalue)
current_decoded_size += 1
self.parent.uncompressed_data += chr(field.realvalue)
yield field
continue
position_header, length_header = divmod(field.realvalue - 256, 8)
info = self.POSITION_SLOTS[position_header]
if info[2] == 0:
if info[0] == 0:
position = self.parent.r0
field._description = "Position Slot %i, Position [R0] (%i)" % (position_header, position)
elif info[0] == 1:
position = self.parent.r1
self.parent.r1 = self.parent.r0
self.parent.r0 = position
field._description = "Position Slot %i, Position [R1] (%i)" % (position_header, position)
elif info[0] == 2:
position = self.parent.r2
self.parent.r2 = self.parent.r0
self.parent.r0 = position
field._description = "Position Slot %i, Position [R2] (%i)" % (position_header, position)
else:
position = info[0] - 2
self.parent.r2 = self.parent.r1
self.parent.r1 = self.parent.r0
self.parent.r0 = position
field._description = "Position Slot %i, Position %i" % (position_header, position)
else:
field._description = "Position Slot %i, Positions %i to %i" % (position_header, info[0] - 2, info[1] - 2)
if length_header == 7:
field._description += ", Length Values 9 and up"
yield field
length_field = HuffmanCode(self, "length_code[]", length_tree)
length = length_field.realvalue + 9
length_field._description = "Length Code %i, total length %i" % (length_field.realvalue, length)
yield length_field
else:
field._description += ", Length Value %i (Huffman Code %i)"%(length_header + 2, field.value)
yield field
length = length_header + 2
if info[2]:
if self.block_type == 1 or info[2] < 3: # verbatim
extrafield = Bits(self, "position_extra[%s" % field.name.split('[')[1], info[2])
position = extrafield.value + info[0] - 2
extrafield._description = "Position Extra Bits (%i), total position %i"%(extrafield.value, position)
yield extrafield
else: # aligned offset
position = info[0] - 2
if info[2] > 3:
extrafield = Bits(self, "position_verbatim[%s" % field.name.split('[')[1], info[2]-3)
position += extrafield.value*8
extrafield._description = "Position Verbatim Bits (%i), added position %i"%(extrafield.value, extrafield.value*8)
yield extrafield
if info[2] >= 3:
extrafield = HuffmanCode(self, "position_aligned[%s" % field.name.split('[')[1], aligned_tree)
position += extrafield.realvalue
extrafield._description = "Position Aligned Bits (%i), total position %i"%(extrafield.realvalue, position)
yield extrafield
self.parent.r2 = self.parent.r1
self.parent.r1 = self.parent.r0
self.parent.r0 = position
self.parent.uncompressed_data = extend_data(self.parent.uncompressed_data, length, position)
current_decoded_size += length
elif self.block_type == 3: # Uncompressed block
padding = paddingSize(self.address + self.current_size, 16)
if padding:
yield PaddingBits(self, "padding[]", padding)
else:
yield PaddingBits(self, "padding[]", 16)
self.endian = LITTLE_ENDIAN
yield UInt32(self, "r[]", "New value of R0")
yield UInt32(self, "r[]", "New value of R1")
yield UInt32(self, "r[]", "New value of R2")
self.parent.r0 = self["r[0]"].value
self.parent.r1 = self["r[1]"].value
self.parent.r2 = self["r[2]"].value
yield RawBytes(self, "data", self.uncompressed_size)
self.parent.uncompressed_data+=self["data"].value
if self["block_size"].value % 2:
yield PaddingBits(self, "padding", 8)
else:
raise ParserError("Unknown block type %d!"%self.block_type)
class LZXStream(Parser):
endian = MIDDLE_ENDIAN
def createFields(self):
self.uncompressed_data = ""
self.r0 = 1
self.r1 = 1
self.r2 = 1
yield Bit(self, "filesize_indicator")
if self["filesize_indicator"].value:
yield UInt32(self, "filesize")
while self.current_size < self.size:
block = LZXBlock(self, "block[]")
yield block
if self.size - self.current_size < 16:
padding = paddingSize(self.address + self.current_size, 16)
if padding:
yield PaddingBits(self, "padding[]", padding)
break
def lzx_decompress(stream, window_bits):
data = LZXStream(stream)
data.compr_level = window_bits
for unused in data:
pass
return data.uncompressed_data

View file

@ -7,10 +7,10 @@ Creation date: 2007-03-04
MAX_NB_FILE = 100000 MAX_NB_FILE = 100000
from lib.hachoir_parser import Parser from hachoir_parser import Parser
from lib.hachoir_core.field import FieldSet, String, UInt32, SubFile from hachoir_core.field import FieldSet, String, UInt32, SubFile
from lib.hachoir_core.endian import LITTLE_ENDIAN from hachoir_core.endian import LITTLE_ENDIAN
from lib.hachoir_core.text_handler import textHandler, filesizeHandler, hexadecimal from hachoir_core.text_handler import textHandler, filesizeHandler, hexadecimal
class FileIndex(FieldSet): class FileIndex(FieldSet):
static_size = 68*8 static_size = 68*8

View file

@ -0,0 +1,60 @@
"""MAR (Mozilla ARchive) parser
Author: Robert Xiao
Creation date: July 10, 2007
"""
from hachoir_core.endian import BIG_ENDIAN
from hachoir_core.field import (RootSeekableFieldSet, FieldSet,
String, CString, UInt32, RawBytes)
from hachoir_core.text_handler import displayHandler, filesizeHandler
from hachoir_core.tools import humanUnixAttributes
from hachoir_parser import HachoirParser
class IndexEntry(FieldSet):
def createFields(self):
yield UInt32(self, "offset", "Offset in bytes relative to start of archive")
yield filesizeHandler(UInt32(self, "length", "Length in bytes"))
yield displayHandler(UInt32(self, "flags"), humanUnixAttributes)
yield CString(self, "name", "Filename (byte array)")
def createDescription(self):
return 'File %s, Size %s, Mode %s'%(
self["name"].display, self["length"].display, self["flags"].display)
class MozillaArchive(HachoirParser, RootSeekableFieldSet):
MAGIC = "MAR1"
PARSER_TAGS = {
"id": "mozilla_ar",
"category": "archive",
"file_ext": ("mar",),
"min_size": (8+4+13)*8, # Header, Index Header, 1 Index Entry
"magic": ((MAGIC, 0),),
"description": "Mozilla Archive",
}
endian = BIG_ENDIAN
def __init__(self, stream, **args):
RootSeekableFieldSet.__init__(self, None, "root", stream, None, stream.askSize(self))
HachoirParser.__init__(self, stream, **args)
def validate(self):
if self.stream.readBytes(0, 4) != self.MAGIC:
return "Invalid magic"
return True
def createFields(self):
yield String(self, "magic", 4, "File signature (MAR1)", charset="ASCII")
yield UInt32(self, "index_offset", "Offset to index relative to file start")
self.seekByte(self["index_offset"].value, False)
yield UInt32(self, "index_size", "size of index in bytes")
current_index_size = 0 # bytes
while current_index_size < self["index_size"].value:
# plus 4 compensates for index_size
self.seekByte(self["index_offset"].value + current_index_size + 4, False)
entry = IndexEntry(self, "index_entry[]")
yield entry
current_index_size += entry.size // 8
self.seekByte(entry["offset"].value, False)
yield RawBytes(self, "file[]", entry["length"].value)

View file

@ -5,15 +5,15 @@ Status: can only read higher-level attructures
Author: Christophe Gisquet Author: Christophe Gisquet
""" """
from lib.hachoir_parser import Parser from hachoir_parser import Parser
from lib.hachoir_core.field import (StaticFieldSet, FieldSet, from hachoir_core.field import (StaticFieldSet, FieldSet,
Bit, Bits, Enum, Bit, Bits, Enum,
UInt8, UInt16, UInt32, UInt64, UInt8, UInt16, UInt32, UInt64,
String, TimeDateMSDOS32, String, TimeDateMSDOS32,
NullBytes, NullBits, RawBytes) NullBytes, NullBits, RawBytes)
from lib.hachoir_core.text_handler import textHandler, filesizeHandler, hexadecimal from hachoir_core.text_handler import textHandler, filesizeHandler, hexadecimal
from lib.hachoir_core.endian import LITTLE_ENDIAN from hachoir_core.endian import LITTLE_ENDIAN
from lib.hachoir_parser.common.msdos import MSDOSFileAttr32 from hachoir_parser.common.msdos import MSDOSFileAttr32
MAX_FILESIZE = 1000 * 1024 * 1024 MAX_FILESIZE = 1000 * 1024 * 1024

View file

@ -4,14 +4,14 @@ RPM archive parser.
Author: Victor Stinner, 1st December 2005. Author: Victor Stinner, 1st December 2005.
""" """
from lib.hachoir_parser import Parser from hachoir_parser import Parser
from lib.hachoir_core.field import (FieldSet, ParserError, from hachoir_core.field import (FieldSet, ParserError,
UInt8, UInt16, UInt32, UInt64, Enum, UInt8, UInt16, UInt32, UInt64, Enum,
NullBytes, Bytes, RawBytes, SubFile, NullBytes, Bytes, RawBytes, SubFile,
Character, CString, String) Character, CString, String)
from lib.hachoir_core.endian import BIG_ENDIAN from hachoir_core.endian import BIG_ENDIAN
from lib.hachoir_parser.archive.gzip_parser import GzipParser from hachoir_parser.archive.gzip_parser import GzipParser
from lib.hachoir_parser.archive.bzip2_parser import Bzip2Parser from hachoir_parser.archive.bzip2_parser import Bzip2Parser
class ItemContent(FieldSet): class ItemContent(FieldSet):
format_type = { format_type = {

View file

@ -9,13 +9,13 @@ Author: Olivier SCHWAB
Creation date: 6 december 2006 Creation date: 6 december 2006
""" """
from lib.hachoir_parser import Parser from hachoir_parser import Parser
from lib.hachoir_core.field import (Field, FieldSet, ParserError, from hachoir_core.field import (Field, FieldSet, ParserError,
GenericVector, GenericVector,
Enum, UInt8, UInt32, UInt64, Enum, UInt8, UInt32, UInt64,
Bytes, RawBytes) Bytes, RawBytes)
from lib.hachoir_core.endian import LITTLE_ENDIAN from hachoir_core.endian import LITTLE_ENDIAN
from lib.hachoir_core.text_handler import textHandler, hexadecimal, filesizeHandler from hachoir_core.text_handler import textHandler, hexadecimal, filesizeHandler
class SZUInt64(Field): class SZUInt64(Field):
""" """

View file

@ -4,11 +4,11 @@ Tar archive parser.
Author: Victor Stinner Author: Victor Stinner
""" """
from lib.hachoir_parser import Parser from hachoir_parser import Parser
from lib.hachoir_core.field import (FieldSet, from hachoir_core.field import (FieldSet,
Enum, UInt8, SubFile, String, NullBytes) Enum, UInt8, SubFile, String, NullBytes)
from lib.hachoir_core.tools import humanFilesize, paddingSize, timestampUNIX from hachoir_core.tools import humanFilesize, paddingSize, timestampUNIX
from lib.hachoir_core.endian import BIG_ENDIAN from hachoir_core.endian import BIG_ENDIAN
import re import re
class FileEntry(FieldSet): class FileEntry(FieldSet):

View file

@ -5,18 +5,18 @@ Status: can read most important headers
Authors: Christophe Gisquet and Victor Stinner Authors: Christophe Gisquet and Victor Stinner
""" """
from lib.hachoir_parser import Parser from hachoir_parser import Parser
from lib.hachoir_core.field import (FieldSet, ParserError, from hachoir_core.field import (FieldSet, ParserError,
Bit, Bits, Enum, Bit, Bits, Enum,
TimeDateMSDOS32, SubFile, TimeDateMSDOS32, SubFile,
UInt8, UInt16, UInt32, UInt64, UInt8, UInt16, UInt32, UInt64,
String, PascalString16, String, PascalString16,
RawBytes) RawBytes)
from lib.hachoir_core.text_handler import textHandler, filesizeHandler, hexadecimal from hachoir_core.text_handler import textHandler, filesizeHandler, hexadecimal
from lib.hachoir_core.error import HACHOIR_ERRORS from hachoir_core.error import HACHOIR_ERRORS
from lib.hachoir_core.tools import makeUnicode from hachoir_core.tools import makeUnicode
from lib.hachoir_core.endian import LITTLE_ENDIAN from hachoir_core.endian import LITTLE_ENDIAN
from lib.hachoir_parser.common.deflate import Deflate from hachoir_parser.common.deflate import Deflate
MAX_FILESIZE = 1000 * 1024 * 1024 MAX_FILESIZE = 1000 * 1024 * 1024
@ -80,16 +80,7 @@ class ZipGeneralFlags(FieldSet):
# Need the compression info from the parent, and that is the byte following # Need the compression info from the parent, and that is the byte following
method = self.stream.readBits(self.absolute_address+16, 16, LITTLE_ENDIAN) method = self.stream.readBits(self.absolute_address+16, 16, LITTLE_ENDIAN)
yield Bits(self, "unused[]", 2, "Unused") yield Bit(self, "is_encrypted", "File is encrypted?")
yield Bit(self, "encrypted_central_dir", "Selected data values in the Local Header are masked")
yield Bit(self, "incomplete", "Reserved by PKWARE for enhanced compression.")
yield Bit(self, "uses_unicode", "Filename and comments are in UTF-8")
yield Bits(self, "unused[]", 4, "Unused")
yield Bit(self, "strong_encrypt", "Strong encryption (version >= 50)")
yield Bit(self, "is_patched", "File is compressed with patched data?")
yield Bit(self, "enhanced_deflate", "Reserved for use with method 8")
yield Bit(self, "has_descriptor",
"Compressed data followed by descriptor?")
if method == 6: if method == 6:
yield Bit(self, "use_8k_sliding", "Use 8K sliding dictionary (instead of 4K)") yield Bit(self, "use_8k_sliding", "Use 8K sliding dictionary (instead of 4K)")
yield Bit(self, "use_3shannon", "Use a 3 Shannon-Fano tree (instead of 2 Shannon-Fano)") yield Bit(self, "use_3shannon", "Use a 3 Shannon-Fano tree (instead of 2 Shannon-Fano)")
@ -106,7 +97,16 @@ class ZipGeneralFlags(FieldSet):
yield Bit(self, "unused[]") yield Bit(self, "unused[]")
else: else:
yield Bits(self, "compression_info", 2) yield Bits(self, "compression_info", 2)
yield Bit(self, "is_encrypted", "File is encrypted?") yield Bit(self, "has_descriptor",
"Compressed data followed by descriptor?")
yield Bit(self, "enhanced_deflate", "Reserved for use with method 8")
yield Bit(self, "is_patched", "File is compressed with patched data?")
yield Bit(self, "strong_encrypt", "Strong encryption (version >= 50)")
yield Bits(self, "unused[]", 4, "Unused")
yield Bit(self, "uses_unicode", "Filename and comments are in UTF-8")
yield Bit(self, "incomplete", "Reserved by PKWARE for enhanced compression.")
yield Bit(self, "encrypted_central_dir", "Selected data values in the Local Header are masked")
yield Bits(self, "unused[]", 2, "Unused")
class ExtraField(FieldSet): class ExtraField(FieldSet):
EXTRA_FIELD_ID = { EXTRA_FIELD_ID = {
@ -141,7 +141,12 @@ class ExtraField(FieldSet):
size = UInt16(self, "field_data_size", "Extra field data size") size = UInt16(self, "field_data_size", "Extra field data size")
yield size yield size
if size.value > 0: if size.value > 0:
yield RawBytes(self, "field_data", size, "Unknown field data") yield RawBytes(self, "field_data", size.value, "Unknown field data")
class ExtraFields(FieldSet):
def createFields(self):
while self.current_size < self.size:
yield ExtraField(self, "extra[]")
def ZipStartCommonFields(self): def ZipStartCommonFields(self):
yield ZipVersion(self, "version_needed", "Version needed") yield ZipVersion(self, "version_needed", "Version needed")
@ -179,8 +184,8 @@ class ZipCentralDirectory(FieldSet):
yield String(self, "filename", self["filename_length"].value, yield String(self, "filename", self["filename_length"].value,
"Filename", charset=charset) "Filename", charset=charset)
if 0 < self["extra_length"].value: if 0 < self["extra_length"].value:
yield RawBytes(self, "extra", self["extra_length"].value, yield ExtraFields(self, "extra", size=self["extra_length"].value*8,
"Extra fields") description="Extra fields")
if 0 < self["comment_length"].value: if 0 < self["comment_length"].value:
yield String(self, "comment", self["comment_length"].value, yield String(self, "comment", self["comment_length"].value,
"Comment", charset=charset) "Comment", charset=charset)
@ -278,14 +283,15 @@ class FileEntry(FieldSet):
yield filename yield filename
self.filename = filename.value self.filename = filename.value
if self["extra_length"].value: if self["extra_length"].value:
yield RawBytes(self, "extra", self["extra_length"].value, "Extra") yield ExtraFields(self, "extra", size=self["extra_length"].value*8,
description="Extra fields")
size = self["compressed_size"].value size = self["compressed_size"].value
if size > 0: if size > 0:
yield self.data(size) yield self.data(size)
elif self["flags/incomplete"].value: elif self["flags/incomplete"].value:
for field in self.resync(): for field in self.resync():
yield field yield field
if self["flags/has_descriptor"].value: if self["flags/has_descriptor"].value and self['crc32'].value == 0:
yield ZipDataDescriptor(self, "data_desc", "Data descriptor") yield ZipDataDescriptor(self, "data_desc", "Data descriptor")
def createDescription(self): def createDescription(self):

View file

@ -0,0 +1,301 @@
"""Detailed ZLIB parser
Author: Robert Xiao
Creation date: July 9 2007
"""
from hachoir_parser import Parser
from hachoir_core.field import (Bit, Bits, Field, Int16, UInt32,
Enum, FieldSet, GenericFieldSet,
PaddingBits, ParserError, RawBytes)
from hachoir_core.endian import LITTLE_ENDIAN
from hachoir_core.text_handler import textHandler, hexadecimal
from hachoir_core.tools import paddingSize, alignValue
def extend_data(data, length, offset):
"""Extend data using a length and an offset."""
if length >= offset:
new_data = data[-offset:] * (alignValue(length, offset) // offset)
return data + new_data[:length]
else:
return data + data[-offset:-offset+length]
def build_tree(lengths):
"""Build a Huffman tree from a list of lengths.
The ith entry of the input list is the length of the Huffman code corresponding to
integer i, or 0 if the integer i is unused."""
max_length = max(lengths) + 1
bit_counts = [0]*max_length
next_code = [0]*max_length
tree = {}
for i in lengths:
if i:
bit_counts[i] += 1
code = 0
for i in xrange(1, len(bit_counts)):
next_code[i] = code = (code + bit_counts[i-1]) << 1
for i, ln in enumerate(lengths):
if ln:
tree[(ln, next_code[ln])] = i
next_code[ln] += 1
return tree
class HuffmanCode(Field):
"""Huffman code. Uses tree parameter as the Huffman tree."""
def __init__(self, parent, name, tree, description=None):
Field.__init__(self, parent, name, 0, description)
endian = self.parent.endian
stream = self.parent.stream
addr = self.absolute_address
value = 0
while (self.size, value) not in tree:
if self.size > 256:
raise ParserError("Huffman code too long!")
bit = stream.readBits(addr, 1, endian)
value <<= 1
value += bit
self._size += 1
addr += 1
self.huffvalue = value
self.realvalue = tree[(self.size, value)]
def createValue(self):
return self.huffvalue
class DeflateBlock(FieldSet):
# code: (min, max, extrabits)
LENGTH_SYMBOLS = {257:(3,3,0),
258:(4,4,0),
259:(5,5,0),
260:(6,6,0),
261:(7,7,0),
262:(8,8,0),
263:(9,9,0),
264:(10,10,0),
265:(11,12,1),
266:(13,14,1),
267:(15,16,1),
268:(17,18,1),
269:(19,22,2),
270:(23,26,2),
271:(27,30,2),
272:(31,34,2),
273:(35,42,3),
274:(43,50,3),
275:(51,58,3),
276:(59,66,3),
277:(67,82,4),
278:(83,98,4),
279:(99,114,4),
280:(115,130,4),
281:(131,162,5),
282:(163,194,5),
283:(195,226,5),
284:(227,257,5),
285:(258,258,0)
}
DISTANCE_SYMBOLS = {0:(1,1,0),
1:(2,2,0),
2:(3,3,0),
3:(4,4,0),
4:(5,6,1),
5:(7,8,1),
6:(9,12,2),
7:(13,16,2),
8:(17,24,3),
9:(25,32,3),
10:(33,48,4),
11:(49,64,4),
12:(65,96,5),
13:(97,128,5),
14:(129,192,6),
15:(193,256,6),
16:(257,384,7),
17:(385,512,7),
18:(513,768,8),
19:(769,1024,8),
20:(1025,1536,9),
21:(1537,2048,9),
22:(2049,3072,10),
23:(3073,4096,10),
24:(4097,6144,11),
25:(6145,8192,11),
26:(8193,12288,12),
27:(12289,16384,12),
28:(16385,24576,13),
29:(24577,32768,13),
}
CODE_LENGTH_ORDER = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]
def __init__(self, parent, name, uncomp_data="", *args, **kwargs):
FieldSet.__init__(self, parent, name, *args, **kwargs)
self.uncomp_data = uncomp_data
def createFields(self):
yield Bit(self, "final", "Is this the final block?") # BFINAL
yield Enum(Bits(self, "compression_type", 2), # BTYPE
{0:"None", 1:"Fixed Huffman", 2:"Dynamic Huffman", 3:"Reserved"})
if self["compression_type"].value == 0: # no compression
padding = paddingSize(self.current_size + self.absolute_address, 8) # align on byte boundary
if padding:
yield PaddingBits(self, "padding[]", padding)
yield Int16(self, "len")
yield Int16(self, "nlen", "One's complement of len")
if self["len"].value != ~self["nlen"].value:
raise ParserError("len must be equal to the one's complement of nlen!")
if self["len"].value: # null stored blocks produced by some encoders (e.g. PIL)
yield RawBytes(self, "data", self["len"].value, "Uncompressed data")
return
elif self["compression_type"].value == 1: # Fixed Huffman
length_tree = {} # (size, huffman code): value
distance_tree = {}
for i in xrange(144):
length_tree[(8, i+48)] = i
for i in xrange(144, 256):
length_tree[(9, i+256)] = i
for i in xrange(256, 280):
length_tree[(7, i-256)] = i
for i in xrange(280, 288):
length_tree[(8, i-88)] = i
for i in xrange(32):
distance_tree[(5, i)] = i
elif self["compression_type"].value == 2: # Dynamic Huffman
yield Bits(self, "huff_num_length_codes", 5, "Number of Literal/Length Codes, minus 257")
yield Bits(self, "huff_num_distance_codes", 5, "Number of Distance Codes, minus 1")
yield Bits(self, "huff_num_code_length_codes", 4, "Number of Code Length Codes, minus 4")
code_length_code_lengths = [0]*19 # confusing variable name...
for i in self.CODE_LENGTH_ORDER[:self["huff_num_code_length_codes"].value+4]:
field = Bits(self, "huff_code_length_code[%i]" % i, 3, "Code lengths for the code length alphabet")
yield field
code_length_code_lengths[i] = field.value
code_length_tree = build_tree(code_length_code_lengths)
length_code_lengths = []
distance_code_lengths = []
for numcodes, name, lengths in (
(self["huff_num_length_codes"].value + 257, "length", length_code_lengths),
(self["huff_num_distance_codes"].value + 1, "distance", distance_code_lengths)):
while len(lengths) < numcodes:
field = HuffmanCode(self, "huff_%s_code[]" % name, code_length_tree)
value = field.realvalue
if value < 16:
prev_value = value
field._description = "Literal Code Length %i (Huffman Code %i)" % (value, field.value)
yield field
lengths.append(value)
else:
info = {16: (3,6,2),
17: (3,10,3),
18: (11,138,7)}[value]
if value == 16:
repvalue = prev_value
else:
repvalue = 0
field._description = "Repeat Code %i, Repeating value (%i) %i to %i times (Huffman Code %i)" % (value, repvalue, info[0], info[1], field.value)
yield field
extrafield = Bits(self, "huff_%s_code_extra[%s" % (name, field.name.split('[')[1]), info[2])
num_repeats = extrafield.value+info[0]
extrafield._description = "Repeat Extra Bits (%i), total repeats %i"%(extrafield.value, num_repeats)
yield extrafield
lengths += [repvalue]*num_repeats
length_tree = build_tree(length_code_lengths)
distance_tree = build_tree(distance_code_lengths)
else:
raise ParserError("Unsupported compression type 3!")
while True:
field = HuffmanCode(self, "length_code[]", length_tree)
value = field.realvalue
if value < 256:
field._description = "Literal Code %r (Huffman Code %i)" % (chr(value), field.value)
yield field
self.uncomp_data += chr(value)
if value == 256:
field._description = "Block Terminator Code (256) (Huffman Code %i)" % field.value
yield field
break
elif value > 256:
info = self.LENGTH_SYMBOLS[value]
if info[2] == 0:
field._description = "Length Code %i, Value %i (Huffman Code %i)" % (value, info[0], field.value)
length = info[0]
yield field
else:
field._description = "Length Code %i, Values %i to %i (Huffman Code %i)" % (value, info[0], info[1], field.value)
yield field
extrafield = Bits(self, "length_extra[%s" % field.name.split('[')[1], info[2])
length = extrafield.value + info[0]
extrafield._description = "Length Extra Bits (%i), total length %i"%(extrafield.value, length)
yield extrafield
field = HuffmanCode(self, "distance_code[]", distance_tree)
value = field.realvalue
info = self.DISTANCE_SYMBOLS[value]
if info[2] == 0:
field._description = "Distance Code %i, Value %i (Huffman Code %i)" % (value, info[0], field.value)
distance = info[0]
yield field
else:
field._description = "Distance Code %i, Values %i to %i (Huffman Code %i)" % (value, info[0], info[1], field.value)
yield field
extrafield = Bits(self, "distance_extra[%s" % field.name.split('[')[1], info[2])
distance = extrafield.value + info[0]
extrafield._description = "Distance Extra Bits (%i), total length %i"%(extrafield.value, distance)
yield extrafield
self.uncomp_data = extend_data(self.uncomp_data, length, distance)
class DeflateData(GenericFieldSet):
endian = LITTLE_ENDIAN
def createFields(self):
uncomp_data = ""
blk=DeflateBlock(self, "compressed_block[]", uncomp_data)
yield blk
uncomp_data = blk.uncomp_data
while not blk["final"].value:
blk=DeflateBlock(self, "compressed_block[]", uncomp_data)
yield blk
uncomp_data = blk.uncomp_data
padding = paddingSize(self.current_size + self.absolute_address, 8) # align on byte boundary
if padding:
yield PaddingBits(self, "padding[]", padding)
self.uncompressed_data = uncomp_data
class ZlibData(Parser):
PARSER_TAGS = {
"id": "zlib",
"category": "archive",
"file_ext": ("zlib",),
"min_size": 8*8,
"description": "ZLIB Data",
}
endian = LITTLE_ENDIAN
def validate(self):
if self["compression_method"].value != 8:
return "Incorrect compression method"
if ((self["compression_info"].value << 12) +
(self["compression_method"].value << 8) +
(self["flag_compression_level"].value << 6) +
(self["flag_dictionary_present"].value << 5) +
(self["flag_check_bits"].value)) % 31 != 0:
return "Invalid flag check value"
return True
def createFields(self):
yield Enum(Bits(self, "compression_method", 4), {8:"deflate", 15:"reserved"}) # CM
yield Bits(self, "compression_info", 4, "base-2 log of the window size") # CINFO
yield Bits(self, "flag_check_bits", 5) # FCHECK
yield Bit(self, "flag_dictionary_present") # FDICT
yield Enum(Bits(self, "flag_compression_level", 2), # FLEVEL
{0:"Fastest", 1:"Fast", 2:"Default", 3:"Maximum, Slowest"})
if self["flag_dictionary_present"].value:
yield textHandler(UInt32(self, "dict_checksum", "ADLER32 checksum of dictionary information"), hexadecimal)
yield DeflateData(self, "data", self.stream, description = "Compressed Data")
yield textHandler(UInt32(self, "data_checksum", "ADLER32 checksum of compressed data"), hexadecimal)
def zlib_inflate(stream, wbits=None, prevdata=""):
if wbits is None or wbits >= 0:
return ZlibData(stream)["data"].uncompressed_data
else:
data = DeflateData(None, "root", stream, "", stream.askSize(None))
for unused in data:
pass
return data.uncompressed_data

View file

@ -1,126 +0,0 @@
"""
Audio Interchange File Format (AIFF) parser.
Author: Victor Stinner
Creation: 27 december 2006
"""
from lib.hachoir_parser import Parser
from lib.hachoir_core.field import (FieldSet,
UInt16, UInt32, Float80, TimestampMac32,
RawBytes, NullBytes,
String, Enum, PascalString32)
from lib.hachoir_core.endian import BIG_ENDIAN
from lib.hachoir_core.text_handler import filesizeHandler
from lib.hachoir_core.tools import alignValue
from lib.hachoir_parser.audio.id3 import ID3v2
CODEC_NAME = {
'ACE2': u"ACE 2-to-1",
'ACE8': u"ACE 8-to-3",
'MAC3': u"MAC 3-to-1",
'MAC6': u"MAC 6-to-1",
'NONE': u"None",
'sowt': u"Little-endian, no compression",
}
class Comment(FieldSet):
def createFields(self):
yield TimestampMac32(self, "timestamp")
yield PascalString32(self, "text")
def parseText(self):
yield String(self, "text", self["size"].value)
def parseID3(self):
yield ID3v2(self, "id3v2", size=self["size"].value*8)
def parseComment(self):
yield UInt16(self, "nb_comment")
for index in xrange(self["nb_comment"].value):
yield Comment(self, "comment[]")
def parseCommon(self):
yield UInt16(self, "nb_channel")
yield UInt32(self, "nb_sample")
yield UInt16(self, "sample_size")
yield Float80(self, "sample_rate")
yield Enum(String(self, "codec", 4, strip="\0", charset="ASCII"), CODEC_NAME)
def parseVersion(self):
yield TimestampMac32(self, "timestamp")
def parseSound(self):
yield UInt32(self, "offset")
yield UInt32(self, "block_size")
size = (self.size - self.current_size) // 8
if size:
yield RawBytes(self, "data", size)
class Chunk(FieldSet):
TAG_INFO = {
'COMM': ('common', "Common chunk", parseCommon),
'COMT': ('comment', "Comment", parseComment),
'NAME': ('name', "Name", parseText),
'AUTH': ('author', "Author", parseText),
'FVER': ('version', "Version", parseVersion),
'SSND': ('sound', "Sound data", parseSound),
'ID3 ': ('id3', "ID3", parseID3),
}
def __init__(self, *args):
FieldSet.__init__(self, *args)
self._size = (8 + alignValue(self["size"].value, 2)) * 8
tag = self["type"].value
if tag in self.TAG_INFO:
self._name, self._description, self._parser = self.TAG_INFO[tag]
else:
self._parser = None
def createFields(self):
yield String(self, "type", 4, "Signature (FORM)", charset="ASCII")
yield filesizeHandler(UInt32(self, "size"))
size = self["size"].value
if size:
if self._parser:
for field in self._parser(self):
yield field
if size % 2:
yield NullBytes(self, "padding", 1)
else:
yield RawBytes(self, "data", size)
class HeightSVX(Parser):
PARSER_TAGS = {
"id": "8svx",
"category": "audio",
"file_ext": ("8svx",),
"mime": (u"audio/x-aiff",),
"min_size": 12*8,
"description": "8SVX (audio) format"
}
endian = BIG_ENDIAN
def validate(self):
if self.stream.readBytes(0, 4) != "FORM":
return "Invalid signature"
if self.stream.readBytes(8*8, 4) != "8SVX":
return "Invalid type"
return True
def createFields(self):
yield String(self, "signature", 4, "Signature (FORM)", charset="ASCII")
yield filesizeHandler(UInt32(self, "filesize"))
yield String(self, "type", 4, "Form type (AIFF or AIFC)", charset="ASCII")
while not self.eof:
yield Chunk(self, "chunk[]")
def createDescription(self):
if self["type"].value == "AIFC":
return "Audio Interchange File Format Compressed (AIFC)"
else:
return "Audio Interchange File Format (AIFF)"
def createContentSize(self):
return self["filesize"].value * 8

View file

@ -1,12 +1,12 @@
from lib.hachoir_parser.audio.aiff import AiffFile from hachoir_parser.audio.aiff import AiffFile
from lib.hachoir_parser.audio.au import AuFile from hachoir_parser.audio.au import AuFile
from lib.hachoir_parser.audio.itunesdb import ITunesDBFile from hachoir_parser.audio.itunesdb import ITunesDBFile
from lib.hachoir_parser.audio.midi import MidiFile from hachoir_parser.audio.midi import MidiFile
from lib.hachoir_parser.audio.mpeg_audio import MpegAudioFile from hachoir_parser.audio.mpeg_audio import MpegAudioFile
from lib.hachoir_parser.audio.real_audio import RealAudioFile from hachoir_parser.audio.real_audio import RealAudioFile
from lib.hachoir_parser.audio.xm import XMModule from hachoir_parser.audio.xm import XMModule
from lib.hachoir_parser.audio.s3m import S3MModule from hachoir_parser.audio.s3m import S3MModule
from lib.hachoir_parser.audio.s3m import PTMModule from hachoir_parser.audio.s3m import PTMModule
from lib.hachoir_parser.audio.mod import AmigaModule from hachoir_parser.audio.mod import AmigaModule
from lib.hachoir_parser.audio.flac import FlacParser from hachoir_parser.audio.flac import FlacParser

View file

@ -5,15 +5,15 @@ Author: Victor Stinner
Creation: 27 december 2006 Creation: 27 december 2006
""" """
from lib.hachoir_parser import Parser from hachoir_parser import Parser
from lib.hachoir_core.field import (FieldSet, from hachoir_core.field import (FieldSet,
UInt16, UInt32, Float80, TimestampMac32, UInt16, UInt32, Float80, TimestampMac32,
RawBytes, NullBytes, RawBytes, NullBytes,
String, Enum, PascalString32) String, Enum, PascalString32)
from lib.hachoir_core.endian import BIG_ENDIAN from hachoir_core.endian import BIG_ENDIAN
from lib.hachoir_core.text_handler import filesizeHandler from hachoir_core.text_handler import filesizeHandler
from lib.hachoir_core.tools import alignValue from hachoir_core.tools import alignValue
from lib.hachoir_parser.audio.id3 import ID3v2 from hachoir_parser.audio.id3 import ID3v2
CODEC_NAME = { CODEC_NAME = {
'ACE2': u"ACE 2-to-1", 'ACE2': u"ACE 2-to-1",

View file

@ -5,11 +5,11 @@ Author: Victor Stinner
Creation: 12 july 2006 Creation: 12 july 2006
""" """
from lib.hachoir_parser import Parser from hachoir_parser import Parser
from lib.hachoir_core.field import UInt32, Enum, String, RawBytes from hachoir_core.field import UInt32, Enum, String, RawBytes
from lib.hachoir_core.endian import BIG_ENDIAN from hachoir_core.endian import BIG_ENDIAN
from lib.hachoir_core.text_handler import displayHandler, filesizeHandler from hachoir_core.text_handler import displayHandler, filesizeHandler
from lib.hachoir_core.tools import createDict, humanFrequency from hachoir_core.tools import createDict, humanFrequency
class AuFile(Parser): class AuFile(Parser):
PARSER_TAGS = { PARSER_TAGS = {

View file

@ -9,11 +9,11 @@ Author: Esteban Loiseau <baal AT tuxfamily.org>
Creation date: 2008-04-09 Creation date: 2008-04-09
""" """
from lib.hachoir_parser import Parser from hachoir_parser import Parser
from lib.hachoir_core.field import FieldSet, String, Bit, Bits, UInt16, UInt24, RawBytes, Enum, NullBytes from hachoir_core.field import FieldSet, String, Bit, Bits, UInt16, UInt24, RawBytes, Enum, NullBytes
from lib.hachoir_core.stream import BIG_ENDIAN, LITTLE_ENDIAN from hachoir_core.stream import BIG_ENDIAN, LITTLE_ENDIAN
from lib.hachoir_core.tools import createDict from hachoir_core.tools import createDict
from lib.hachoir_parser.container.ogg import parseVorbisComment from hachoir_parser.container.ogg import parseVorbisComment
class VorbisComment(FieldSet): class VorbisComment(FieldSet):
endian = LITTLE_ENDIAN endian = LITTLE_ENDIAN

View file

@ -6,13 +6,13 @@ Informations: http://www.id3.org/
Author: Victor Stinner Author: Victor Stinner
""" """
from lib.hachoir_core.field import (FieldSet, MatchError, ParserError, from hachoir_core.field import (FieldSet, MatchError, ParserError,
Enum, UInt8, UInt24, UInt32, Enum, UInt8, UInt24, UInt32,
CString, String, RawBytes, CString, String, RawBytes,
Bit, Bits, NullBytes, NullBits) Bit, Bits, NullBytes, NullBits)
from lib.hachoir_core.text_handler import textHandler from hachoir_core.text_handler import textHandler
from lib.hachoir_core.tools import humanDuration from hachoir_core.tools import humanDuration
from lib.hachoir_core.endian import NETWORK_ENDIAN from hachoir_core.endian import NETWORK_ENDIAN
class ID3v1(FieldSet): class ID3v1(FieldSet):
static_size = 128 * 8 static_size = 128 * 8

View file

@ -8,13 +8,13 @@ Author: Romain HERAULT
Creation date: 19 august 2006 Creation date: 19 august 2006
""" """
from lib.hachoir_parser import Parser from hachoir_parser import Parser
from lib.hachoir_core.field import (FieldSet, from hachoir_core.field import (FieldSet,
UInt8, UInt16, UInt32, UInt64, TimestampMac32, UInt8, UInt16, UInt32, Int32, UInt64, TimestampMac32,
String, Float32, NullBytes, Enum) String, Float32, NullBytes, Enum, RawBytes)
from lib.hachoir_core.endian import LITTLE_ENDIAN from hachoir_core.endian import LITTLE_ENDIAN
from lib.hachoir_core.tools import humanDuration from hachoir_core.tools import humanDuration
from lib.hachoir_core.text_handler import displayHandler, filesizeHandler from hachoir_core.text_handler import displayHandler, filesizeHandler
list_order={ list_order={
1 : "playlist order (manual sort order)", 1 : "playlist order (manual sort order)",
@ -75,6 +75,9 @@ class DataObject(FieldSet):
51:"Smart Playlist Rules", 51:"Smart Playlist Rules",
52:"Library Playlist Index", 52:"Library Playlist Index",
100:"Column info", 100:"Column info",
200:"Album name (for album descriptions)",
201:"Album artist (for album descriptions)",
202:"Album sort artist (for album descriptions)"
} }
mhod52_sort_index_type_name={ mhod52_sort_index_type_name={
@ -94,7 +97,7 @@ class DataObject(FieldSet):
yield UInt32(self, "header_length", "Header Length") yield UInt32(self, "header_length", "Header Length")
yield UInt32(self, "entry_length", "Entry Length") yield UInt32(self, "entry_length", "Entry Length")
yield Enum(UInt32(self, "type", "type"),self.type_name) yield Enum(UInt32(self, "type", "type"),self.type_name)
if(self["type"].value<15): if(self["type"].value<15) or (self["type"].value >= 200):
yield UInt32(self, "unknown[]") yield UInt32(self, "unknown[]")
yield UInt32(self, "unknown[]") yield UInt32(self, "unknown[]")
yield UInt32(self, "position", "Position") yield UInt32(self, "position", "Position")
@ -162,7 +165,7 @@ class TrackItem(FieldSet):
yield Enum(UInt8(self, "x2_type", "Extended type 2"),self.x2_type_name) yield Enum(UInt8(self, "x2_type", "Extended type 2"),self.x2_type_name)
yield UInt8(self, "compilation_flag", "Compilation Flag") yield UInt8(self, "compilation_flag", "Compilation Flag")
yield UInt8(self, "rating", "Rating") yield UInt8(self, "rating", "Rating")
yield TimestampMac32(self, "added_date", "Date when the item was added") yield TimestampMac32(self, "last_modified", "Time of the last modification of the track")
yield filesizeHandler(UInt32(self, "size", "Track size in bytes")) yield filesizeHandler(UInt32(self, "size", "Track size in bytes"))
yield displayHandler(UInt32(self, "length", "Track length in milliseconds"), humanDuration) yield displayHandler(UInt32(self, "length", "Track length in milliseconds"), humanDuration)
yield UInt32(self, "track_number", "Number of this track") yield UInt32(self, "track_number", "Number of this track")
@ -180,23 +183,24 @@ class TrackItem(FieldSet):
yield UInt32(self, "disc_number", "disc number in multi disc sets") yield UInt32(self, "disc_number", "disc number in multi disc sets")
yield UInt32(self, "total_discs", "Total number of discs in the disc set") yield UInt32(self, "total_discs", "Total number of discs in the disc set")
yield UInt32(self, "userid", "User ID in the DRM scheme") yield UInt32(self, "userid", "User ID in the DRM scheme")
yield TimestampMac32(self, "last_modified", "Time of the last modification of the track") yield TimestampMac32(self, "added_date", "Date when the item was added")
yield UInt32(self, "bookmark_time", "Bookmark time for AudioBook") yield UInt32(self, "bookmark_time", "Bookmark time for AudioBook")
yield UInt64(self, "dbid", "Unique DataBase ID for the song (identical in mhit and in mhii)") yield UInt64(self, "dbid", "Unique DataBase ID for the song (identical in mhit and in mhii)")
yield UInt8(self, "checked", "song is checked") yield UInt8(self, "checked", "song is checked")
yield UInt8(self, "application_rating", "Last Rating before change") yield UInt8(self, "application_rating", "Last Rating before change")
yield UInt16(self, "BPM", "BPM of the track") yield UInt16(self, "BPM", "BPM of the track")
yield UInt16(self, "artwork_count", "number of artworks fo this item") yield UInt16(self, "artwork_count", "number of artworks for this item")
yield UInt16(self, "unknown[]") yield UInt16(self, "unknown[]")
yield UInt32(self, "artwork_size", "Total size of artworks in bytes") yield UInt32(self, "artwork_size", "Total size of artworks in bytes")
yield UInt32(self, "unknown[]") yield UInt32(self, "unknown[]")
yield Float32(self, "sample_rate_2", "Sample Rate express in float") yield Float32(self, "sample_rate_2", "Sample Rate express in float")
yield UInt32(self, "released_date", "Date of release in Music Store or in Podcast") yield UInt32(self, "released_date", "Date of release in Music Store or in Podcast")
yield UInt16(self, "unknown[]")
yield UInt16(self, "explicit_flag[]", "Explicit flag")
yield UInt32(self, "unknown[]") yield UInt32(self, "unknown[]")
yield UInt32(self, "unknown[]") yield UInt32(self, "unknown[]")
yield UInt32(self, "unknown[]") yield UInt32(self, "skip_count[]", "Skip Count")
yield UInt32(self, "unknown[]") yield TimestampMac32(self, "last_skipped", "Date when the item was last skipped")
yield UInt32(self, "unknown[]")
yield UInt8(self, "has_artwork", "0x01 for track with artwork, 0x02 otherwise") yield UInt8(self, "has_artwork", "0x01 for track with artwork, 0x02 otherwise")
yield UInt8(self, "skip_wen_shuffling", "Skip that track when shuffling") yield UInt8(self, "skip_wen_shuffling", "Skip that track when shuffling")
yield UInt8(self, "remember_playback_position", "Remember playback position") yield UInt8(self, "remember_playback_position", "Remember playback position")
@ -207,11 +211,10 @@ class TrackItem(FieldSet):
yield UInt8(self, "played_mark", "Track has been played") yield UInt8(self, "played_mark", "Track has been played")
yield UInt8(self, "unknown[]") yield UInt8(self, "unknown[]")
yield UInt32(self, "unknown[]") yield UInt32(self, "unknown[]")
yield UInt32(self, "pregap[]", "Number of samples of silence before the song starts")
yield UInt64(self, "sample_count", "Number of samples in the song (only for WAV and AAC files)")
yield UInt32(self, "unknown[]") yield UInt32(self, "unknown[]")
yield UInt32(self, "sample_count", "Number of samples in the song (only for WAV and AAC files)") yield UInt32(self, "postgap[]", "Number of samples of silence at the end of the song")
yield UInt32(self, "unknown[]")
yield UInt32(self, "unknown[]")
yield UInt32(self, "unknown[]")
yield UInt32(self, "unknown[]") yield UInt32(self, "unknown[]")
yield Enum(UInt32(self, "media_type", "Media Type for video iPod"),self.media_type_name) yield Enum(UInt32(self, "media_type", "Media Type for video iPod"),self.media_type_name)
yield UInt32(self, "season_number", "Season Number") yield UInt32(self, "season_number", "Season Number")
@ -222,6 +225,20 @@ class TrackItem(FieldSet):
yield UInt32(self, "unknown[]") yield UInt32(self, "unknown[]")
yield UInt32(self, "unknown[]") yield UInt32(self, "unknown[]")
yield UInt32(self, "unknown[]") yield UInt32(self, "unknown[]")
yield UInt32(self, "unknown[]")
yield UInt32(self, "gapless_data[]","The size in bytes from first Sync Frame until the 8th before the last frame." )
yield UInt32(self, "unknown[]")
yield UInt16(self, "gaplessTrackFlag[]", "1 if track has gapless data")
yield UInt16(self, "gaplessAlbumFlag[]", "1 if track uses crossfading in iTunes")
yield RawBytes(self, "unknown[]", 20)
yield UInt32(self, "unknown[]")
yield UInt32(self, "unknown[]")
yield UInt32(self, "unknown[]")
yield UInt32(self, "unknown[]")
yield UInt16(self, "unknown[]")
yield UInt16(self, "album_id[]", "Album ID (used to link tracks with MHIAs)")
yield RawBytes(self, "unknown[]", 52)
yield UInt32(self, "mhii_link[]", "Artwork ID (used to link tracks with MHIIs)")
padding = self.seekByte(self["header_length"].value, "header padding") padding = self.seekByte(self["header_length"].value, "header padding")
if padding: if padding:
yield padding yield padding
@ -319,7 +336,7 @@ class Playlist(FieldSet):
self._size = self["entry_length"].value *8 self._size = self["entry_length"].value *8
def createFields(self): def createFields(self):
yield String(self, "header_id", 4, "Playlist List Header Markup (\"mhyp\")", charset="ISO-8859-1") yield String(self, "header_id", 4, "Playlist Header Markup (\"mhyp\")", charset="ISO-8859-1")
yield UInt32(self, "header_length", "Header Length") yield UInt32(self, "header_length", "Header Length")
yield UInt32(self, "entry_length", "Entry Length") yield UInt32(self, "entry_length", "Entry Length")
yield UInt32(self, "data_object_child_count", "Number of Child Data Objects") yield UInt32(self, "data_object_child_count", "Number of Child Data Objects")
@ -360,11 +377,48 @@ class PlaylistList(FieldSet):
for i in xrange(self["playlist_number"].value): for i in xrange(self["playlist_number"].value):
yield Playlist(self, "playlist[]") yield Playlist(self, "playlist[]")
class Album(FieldSet):
def __init__(self, *args, **kw):
FieldSet.__init__(self, *args, **kw)
self._size = self["entry_length"].value *8
def createFields(self):
yield String(self, "header_id", 4, "Album Item Header Markup (\"mhia\")", charset="ISO-8859-1")
yield UInt32(self, "header_length", "Header Length")
yield UInt32(self, "entry_length", "Entry Length")
yield UInt32(self, "data_object_child_count", "Number of Child Data Objects")
yield UInt16(self, "unknow[]")
yield UInt16(self, "album_id[]", "Album ID")
yield UInt32(self, "unknow[]")
yield UInt32(self, "unknow[]")
yield UInt32(self, "unknow[]")
padding = self.seekByte(self["header_length"].value, "entry padding")
if padding:
yield padding
for i in xrange(self["data_object_child_count"].value):
yield DataObject(self, "mhod[]")
class AlbumList(FieldSet):
def createFields(self):
yield String(self, "header_id", 4, "Album List Header Markup (\"mhla\")", charset="ISO-8859-1")
yield UInt32(self, "header_length", "Header Length")
yield UInt32(self, "album_number", "Number of Albums")
padding = self.seekByte(self["header_length"].value, "header padding")
if padding:
yield padding
for i in xrange(self["album_number"].value):
yield Album(self, "album[]")
class DataSet(FieldSet): class DataSet(FieldSet):
type_name={ type_name={
1:"Track List", 1:"Track List",
2:"Play List", 2:"Play List",
3:"Podcast List" 3:"Podcast List",
4:"Album List"
} }
def __init__(self, *args, **kw): def __init__(self, *args, **kw):
FieldSet.__init__(self, *args, **kw) FieldSet.__init__(self, *args, **kw)
@ -384,6 +438,8 @@ class DataSet(FieldSet):
yield PlaylistList(self, "playlist_list[]"); yield PlaylistList(self, "playlist_list[]");
if self["type"].value == 3: if self["type"].value == 3:
yield PlaylistList(self, "podcast_list[]"); yield PlaylistList(self, "podcast_list[]");
if self["type"].value == 4:
yield AlbumList(self, "album_list[]");
padding = self.seekBit(self._size, "entry padding") padding = self.seekBit(self._size, "entry padding")
if padding: if padding:
yield padding yield padding
@ -417,8 +473,20 @@ class ITunesDBFile(Parser):
yield UInt32(self, "version_number", "Version Number") yield UInt32(self, "version_number", "Version Number")
yield UInt32(self, "child_number", "Number of Children") yield UInt32(self, "child_number", "Number of Children")
yield UInt64(self, "id", "ID for this database") yield UInt64(self, "id", "ID for this database")
yield UInt16(self, "unknown[]")
yield UInt32(self, "unknown[]") yield UInt32(self, "unknown[]")
yield UInt64(self, "initial_dbid", "Initial DBID") yield UInt64(self, "unknown[]")
yield UInt16(self, "unknown[]")
yield UInt16(self, "hashing_scheme[]", "Algorithm used to calculate the database hash")
yield NullBytes(self, "unknown[]", 20)
yield String(self, "language_id", 2, "Language ID")
yield UInt64(self, "persistent_id", "Library Persistent ID")
yield UInt32(self, "unknown[]")
yield UInt32(self, "unknown[]")
yield RawBytes(self, "hash[]", 20)
yield Int32(self, "timezone_offset[]", "Timezone offset in seconds")
yield UInt16(self, "unknown[]")
yield RawBytes(self, "iphone_hash[]", 45)
size = self["header_length"].value-self.current_size/ 8 size = self["header_length"].value-self.current_size/ 8
if size>0: if size>0:
yield NullBytes(self, "padding", size) yield NullBytes(self, "padding", size)

View file

@ -8,13 +8,13 @@ Author: Victor Stinner
Creation: 27 december 2006 Creation: 27 december 2006
""" """
from lib.hachoir_parser import Parser from hachoir_parser import Parser
from lib.hachoir_core.field import (FieldSet, Bits, ParserError, from hachoir_core.field import (FieldSet, Bits, ParserError,
String, UInt32, UInt24, UInt16, UInt8, Enum, RawBytes) String, UInt32, UInt24, UInt16, UInt8, Enum, RawBits, RawBytes)
from lib.hachoir_core.endian import BIG_ENDIAN from hachoir_core.endian import BIG_ENDIAN
from lib.hachoir_core.text_handler import textHandler, hexadecimal from hachoir_core.text_handler import textHandler, hexadecimal
from lib.hachoir_core.tools import createDict, humanDurationNanosec from hachoir_core.tools import createDict, humanDurationNanosec
from lib.hachoir_parser.common.tracker import NOTE_NAME from hachoir_parser.common.tracker import NOTE_NAME
MAX_FILESIZE = 10 * 1024 * 1024 MAX_FILESIZE = 10 * 1024 * 1024
@ -46,7 +46,7 @@ def parseControl(parser):
def parsePatch(parser): def parsePatch(parser):
yield UInt8(parser, "program", "New program number") yield UInt8(parser, "program", "New program number")
def parseChannel(parser): def parseChannel(parser, size=1):
yield UInt8(parser, "channel", "Channel number") yield UInt8(parser, "channel", "Channel number")
def parsePitch(parser): def parsePitch(parser):
@ -56,6 +56,16 @@ def parsePitch(parser):
def parseText(parser, size): def parseText(parser, size):
yield String(parser, "text", size) yield String(parser, "text", size)
def parseSMPTEOffset(parser, size):
yield RawBits(parser, "padding", 1)
yield Enum(Bits(parser, "frame_rate", 2),
{0:"24 fps", 1:"25 fps", 2:"30 fps (drop frame)", 3:"30 fps"})
yield Bits(parser, "hour", 5)
yield UInt8(parser, "minute")
yield UInt8(parser, "second")
yield UInt8(parser, "frame")
yield UInt8(parser, "subframe", "100 subframes per frame")
def formatTempo(field): def formatTempo(field):
return humanDurationNanosec(field.value*1000) return humanDurationNanosec(field.value*1000)
@ -92,8 +102,10 @@ class Command(FieldSet):
0x05: ("Lyric", parseText), 0x05: ("Lyric", parseText),
0x06: ("Marker", parseText), 0x06: ("Marker", parseText),
0x07: ("Cue point", parseText), 0x07: ("Cue point", parseText),
0x20: ("MIDI Channel Prefix", parseChannel),
0x2F: ("End of the track", None), 0x2F: ("End of the track", None),
0x51: ("Set tempo", parseTempo), 0x51: ("Set tempo", parseTempo),
0x54: ("SMPTE offset", parseSMPTEOffset),
0x58: ("Time Signature", parseTimeSignature), 0x58: ("Time Signature", parseTimeSignature),
0x59: ("Key signature", None), 0x59: ("Key signature", None),
0x7F: ("Sequencer specific information", None), 0x7F: ("Sequencer specific information", None),
@ -101,11 +113,27 @@ class Command(FieldSet):
META_COMMAND_DESC = createDict(META_COMMAND, 0) META_COMMAND_DESC = createDict(META_COMMAND, 0)
META_COMMAND_PARSER = createDict(META_COMMAND, 1) META_COMMAND_PARSER = createDict(META_COMMAND, 1)
def __init__(self, *args, **kwargs):
if 'prev_command' in kwargs:
self.prev_command = kwargs['prev_command']
del kwargs['prev_command']
else:
self.prev_command = None
self.command = None
FieldSet.__init__(self, *args, **kwargs)
def createFields(self): def createFields(self):
yield Integer(self, "time", "Delta time in ticks") yield Integer(self, "time", "Delta time in ticks")
yield Enum(textHandler(UInt8(self, "command"), hexadecimal), self.COMMAND_DESC) next = self.stream.readBits(self.absolute_address+self.current_size, 8, self.root.endian)
command = self["command"].value if next & 0x80 == 0:
if command == 0xFF: # "Running Status" command
if self.prev_command is None:
raise ParserError("Running Status command not preceded by another command.")
self.command = self.prev_command.command
else:
yield Enum(textHandler(UInt8(self, "command"), hexadecimal), self.COMMAND_DESC)
self.command = self["command"].value
if self.command == 0xFF:
yield Enum(textHandler(UInt8(self, "meta_command"), hexadecimal), self.META_COMMAND_DESC) yield Enum(textHandler(UInt8(self, "meta_command"), hexadecimal), self.META_COMMAND_DESC)
yield UInt8(self, "data_len") yield UInt8(self, "data_len")
size = self["data_len"].value size = self["data_len"].value
@ -121,9 +149,9 @@ class Command(FieldSet):
else: else:
yield RawBytes(self, "data", size) yield RawBytes(self, "data", size)
else: else:
if command not in self.COMMAND_PARSER: if self.command not in self.COMMAND_PARSER:
raise ParserError("Unknown command: %s" % self["command"].display) raise ParserError("Unknown command: %s" % self["command"].display)
parser = self.COMMAND_PARSER[command] parser = self.COMMAND_PARSER[self.command]
for field in parser(self): for field in parser(self):
yield field yield field
@ -131,7 +159,7 @@ class Command(FieldSet):
if "meta_command" in self: if "meta_command" in self:
return self["meta_command"].display return self["meta_command"].display
else: else:
return self["command"].display return self.COMMAND_DESC[self.command]
class Track(FieldSet): class Track(FieldSet):
def __init__(self, *args): def __init__(self, *args):
@ -141,9 +169,11 @@ class Track(FieldSet):
def createFields(self): def createFields(self):
yield String(self, "marker", 4, "Track marker (MTrk)", charset="ASCII") yield String(self, "marker", 4, "Track marker (MTrk)", charset="ASCII")
yield UInt32(self, "size") yield UInt32(self, "size")
cur = None
if True: if True:
while not self.eof: while not self.eof:
yield Command(self, "command[]") cur = Command(self, "command[]", prev_command=cur)
yield cur
else: else:
size = self["size"].value size = self["size"].value
if size: if size:

View file

@ -18,12 +18,12 @@ Creation: 18th February 2007
""" """
from math import log10 from math import log10
from lib.hachoir_parser import Parser from hachoir_parser import Parser
from lib.hachoir_core.field import (FieldSet, from hachoir_core.field import (FieldSet,
Bits, UInt16, UInt8, Bits, UInt16, UInt8,
RawBytes, String, GenericVector) RawBytes, String, GenericVector)
from lib.hachoir_core.endian import BIG_ENDIAN from hachoir_core.endian import BIG_ENDIAN
from lib.hachoir_core.text_handler import textHandler from hachoir_core.text_handler import textHandler
# Old NoiseTracker 15-samples modules can have anything here. # Old NoiseTracker 15-samples modules can have anything here.
MODULE_TYPE = { MODULE_TYPE = {

View file

@ -8,11 +8,11 @@ Author: Christophe GISQUET <christophe.gisquet@free.fr>
Creation: 10th February 2007 Creation: 10th February 2007
""" """
from lib.hachoir_core.field import (FieldSet, from hachoir_core.field import (FieldSet,
UInt32, UInt16, UInt8, Int8, Float32, UInt32, UInt16, UInt8, Int8, Float32,
RawBytes, String, GenericVector, ParserError) RawBytes, String, GenericVector, ParserError)
from lib.hachoir_core.endian import LITTLE_ENDIAN from hachoir_core.endian import LITTLE_ENDIAN
from lib.hachoir_core.text_handler import textHandler, hexadecimal from hachoir_core.text_handler import textHandler, hexadecimal
MAX_ENVPOINTS = 32 MAX_ENVPOINTS = 32

View file

@ -5,18 +5,18 @@ Creation: 12 decembre 2005
Author: Victor Stinner Author: Victor Stinner
""" """
from lib.hachoir_parser import Parser from hachoir_parser import Parser
from lib.hachoir_core.field import (FieldSet, from hachoir_core.field import (FieldSet,
MissingField, ParserError, createOrphanField, MissingField, ParserError, createOrphanField,
Bit, Bits, Enum, Bit, Bits, Enum,
PaddingBits, PaddingBytes, PaddingBits, PaddingBytes,
RawBytes) RawBytes)
from lib.hachoir_parser.audio.id3 import ID3v1, ID3v2 from hachoir_parser.audio.id3 import ID3v1, ID3v2
from lib.hachoir_core.endian import BIG_ENDIAN from hachoir_core.endian import BIG_ENDIAN
from lib.hachoir_core.tools import humanFrequency, humanBitSize from hachoir_core.tools import humanFrequency, humanBitSize
from lib.hachoir_core.bits import long2raw from hachoir_core.bits import long2raw
from lib.hachoir_core.error import HACHOIR_ERRORS from hachoir_core.error import HACHOIR_ERRORS
from lib.hachoir_core.stream import InputStreamError from hachoir_core.stream import InputStreamError
# Max MP3 filesize: 200 MB # Max MP3 filesize: 200 MB
MAX_FILESIZE = 200*1024*1024*8 MAX_FILESIZE = 200*1024*1024*8

View file

@ -8,14 +8,14 @@ Samples:
http://samples.mplayerhq.hu/real/RA/ http://samples.mplayerhq.hu/real/RA/
""" """
from lib.hachoir_parser import Parser from hachoir_parser import Parser
from lib.hachoir_core.field import (FieldSet, from hachoir_core.field import (FieldSet,
UInt8, UInt16, UInt32, UInt8, UInt16, UInt32,
Bytes, RawBytes, String, Bytes, RawBytes, String,
PascalString8) PascalString8)
from lib.hachoir_core.tools import humanFrequency from hachoir_core.tools import humanFrequency
from lib.hachoir_core.text_handler import displayHandler from hachoir_core.text_handler import displayHandler
from lib.hachoir_core.endian import BIG_ENDIAN from hachoir_core.endian import BIG_ENDIAN
class Metadata(FieldSet): class Metadata(FieldSet):
def createFields(self): def createFields(self):

View file

@ -9,15 +9,15 @@ Author: Christophe GISQUET <christophe.gisquet@free.fr>
Creation: 11th February 2007 Creation: 11th February 2007
""" """
from lib.hachoir_parser import Parser from hachoir_parser import Parser
from lib.hachoir_core.field import (StaticFieldSet, FieldSet, Field, from hachoir_core.field import (StaticFieldSet, FieldSet, Field,
Bit, Bits, Bit, Bits,
UInt32, UInt16, UInt8, Enum, UInt32, UInt16, UInt8, Enum,
PaddingBytes, RawBytes, NullBytes, PaddingBytes, RawBytes, NullBytes,
String, GenericVector, ParserError) String, GenericVector, ParserError)
from lib.hachoir_core.endian import LITTLE_ENDIAN from hachoir_core.endian import LITTLE_ENDIAN
from lib.hachoir_core.text_handler import textHandler, hexadecimal from hachoir_core.text_handler import textHandler, hexadecimal
from lib.hachoir_core.tools import alignValue from hachoir_core.tools import alignValue
class Chunk: class Chunk:
def __init__(self, cls, name, offset, size, *args): def __init__(self, cls, name, offset, size, *args):
@ -326,7 +326,7 @@ class PTMHeader(Header):
# static_size should prime over _size, right? # static_size should prime over _size, right?
static_size = 8*608 static_size = 8*608
def getTrackerVersion(val): def getTrackerVersion(self, val):
val = val.value val = val.value
return "ProTracker x%04X" % val return "ProTracker x%04X" % val

View file

@ -13,15 +13,15 @@ Author: Christophe GISQUET <christophe.gisquet@free.fr>
Creation: 8th February 2007 Creation: 8th February 2007
""" """
from lib.hachoir_parser import Parser from hachoir_parser import Parser
from lib.hachoir_core.field import (StaticFieldSet, FieldSet, from hachoir_core.field import (StaticFieldSet, FieldSet,
Bit, RawBits, Bits, Bit, RawBits, Bits,
UInt32, UInt16, UInt8, Int8, Enum, UInt32, UInt16, UInt8, Int8, Enum,
RawBytes, String, GenericVector) RawBytes, String, GenericVector)
from lib.hachoir_core.endian import LITTLE_ENDIAN, BIG_ENDIAN from hachoir_core.endian import LITTLE_ENDIAN, BIG_ENDIAN
from lib.hachoir_core.text_handler import textHandler, filesizeHandler, hexadecimal from hachoir_core.text_handler import textHandler, filesizeHandler, hexadecimal
from lib.hachoir_parser.audio.modplug import ParseModplugMetadata from hachoir_parser.audio.modplug import ParseModplugMetadata
from lib.hachoir_parser.common.tracker import NOTE_NAME from hachoir_parser.common.tracker import NOTE_NAME
def parseSigned(val): def parseSigned(val):
return "%i" % (val.value-128) return "%i" % (val.value-128)

View file

@ -1,4 +1,4 @@
from lib.hachoir_core.field import CompressedField from hachoir_core.field import CompressedField
try: try:
from zlib import decompressobj, MAX_WBITS from zlib import decompressobj, MAX_WBITS
@ -12,8 +12,8 @@ try:
def __call__(self, size, data=None): def __call__(self, size, data=None):
if data is None: if data is None:
data = self.gzip.unconsumed_tail data = ''
return self.gzip.decompress(data, size) return self.gzip.decompress(self.gzip.unconsumed_tail+data, size)
class DeflateStreamWbits(DeflateStream): class DeflateStreamWbits(DeflateStream):
def __init__(self, stream): def __init__(self, stream):

View file

@ -6,8 +6,8 @@ Documentation:
http://www.cs.colorado.edu/~main/cs1300/include/ddk/winddk.h http://www.cs.colorado.edu/~main/cs1300/include/ddk/winddk.h
""" """
from lib.hachoir_core.field import StaticFieldSet from hachoir_core.field import StaticFieldSet
from lib.hachoir_core.field import Bit, NullBits from hachoir_core.field import Bit, NullBits
_FIELDS = ( _FIELDS = (
(Bit, "read_only"), (Bit, "read_only"),

View file

@ -1,9 +1,9 @@
from lib.hachoir_core.field import (FieldSet, from hachoir_core.field import (FieldSet,
UInt16, UInt32, Enum, String, Bytes, Bits, TimestampUUID60) UInt16, UInt32, Enum, String, Bytes, Bits, TimestampUUID60)
from lib.hachoir_parser.video.fourcc import video_fourcc_name from hachoir_parser.video.fourcc import video_fourcc_name
from lib.hachoir_core.bits import str2hex from hachoir_core.bits import str2hex
from lib.hachoir_core.text_handler import textHandler, hexadecimal from hachoir_core.text_handler import textHandler, hexadecimal
from lib.hachoir_parser.network.common import MAC48_Address from hachoir_parser.network.common import MAC48_Address
# Dictionary: Windows codepage => Python charset name # Dictionary: Windows codepage => Python charset name
CODEPAGE_CHARSET = { CODEPAGE_CHARSET = {
@ -24,6 +24,26 @@ CODEPAGE_CHARSET = {
65001: "UTF-8", 65001: "UTF-8",
} }
class PascalStringWin16(FieldSet):
def __init__(self, parent, name, description=None, strip=None, charset="UTF-16-LE"):
FieldSet.__init__(self, parent, name, description)
length = self["length"].value
self._size = 16 + length * 16
self.strip = strip
self.charset = charset
def createFields(self):
yield UInt16(self, "length", "Length in widechar characters")
size = self["length"].value
if size:
yield String(self, "text", size*2, charset=self.charset, strip=self.strip)
def createValue(self):
if "text" in self:
return self["text"].value
else:
return None
class PascalStringWin32(FieldSet): class PascalStringWin32(FieldSet):
def __init__(self, parent, name, description=None, strip=None, charset="UTF-16-LE"): def __init__(self, parent, name, description=None, strip=None, charset="UTF-16-LE"):
FieldSet.__init__(self, parent, name, description) FieldSet.__init__(self, parent, name, description)

View file

@ -1,7 +1,7 @@
from lib.hachoir_parser.container.asn1 import ASN1File from hachoir_parser.container.asn1 import ASN1File
from lib.hachoir_parser.container.mkv import MkvFile from hachoir_parser.container.mkv import MkvFile
from lib.hachoir_parser.container.ogg import OggFile, OggStream from hachoir_parser.container.ogg import OggFile, OggStream
from lib.hachoir_parser.container.riff import RiffFile from hachoir_parser.container.riff import RiffFile
from lib.hachoir_parser.container.swf import SwfFile from hachoir_parser.container.swf import SwfFile
from lib.hachoir_parser.container.realmedia import RealMediaFile from hachoir_parser.container.realmedia import RealMediaFile

View file

@ -5,29 +5,64 @@ Documentation:
- Alexis' SWF Reference: - Alexis' SWF Reference:
http://www.m2osw.com/swf_alexref.html http://www.m2osw.com/swf_alexref.html
- Tamarin ABC format:
http://www.m2osw.com/abc_format.html
Author: Sebastien Ponce Authors: Sebastien Ponce, Robert Xiao
Creation date: 26 April 2008 Creation date: 26 April 2008
""" """
from lib.hachoir_core.field import (FieldSet, ParserError, from hachoir_parser import Parser
Bit, Bits, UInt8, UInt32, Int16, UInt16, Float32, CString, from hachoir_core.field import (FieldSet, ParserError,
RawBytes) Bit, Bits, UInt8, UInt32, Int16, UInt16, Float32, Float64, CString, Enum,
#from lib.hachoir_core.field import Field Bytes, RawBytes, NullBits, String, SubFile, Field)
from lib.hachoir_core.field.float import FloatExponent from hachoir_core.endian import LITTLE_ENDIAN, BIG_ENDIAN
from hachoir_core.field.float import FloatExponent
from struct import unpack from struct import unpack
class FlashPackedInteger(Bits):
def __init__(self, parent, name, signed=False, nbits=30, description=None):
Bits.__init__(self, parent, name, 8, description)
stream = self._parent.stream
addr = self.absolute_address
size = 0
value = 0
mult = 1
while True:
byte = stream.readBits(addr+size, 8, LITTLE_ENDIAN)
value += mult * (byte & 0x7f)
size += 8
mult <<= 7
if byte < 128:
break
self._size = size
if signed and (1 << (nbits-1)) <= value:
value -= (1 << nbits)
self.createValue = lambda: value
class FlashU30(FlashPackedInteger):
def __init__(self, parent, name, description=None):
FlashPackedInteger.__init__(self, parent, name, signed=False, nbits=30, description=description)
class FlashS32(FlashPackedInteger):
def __init__(self, parent, name, description=None):
FlashPackedInteger.__init__(self, parent, name, signed=True, nbits=32, description=description)
class FlashU32(FlashPackedInteger):
def __init__(self, parent, name, description=None):
FlashPackedInteger.__init__(self, parent, name, signed=False, nbits=32, description=description)
class FlashFloat64(FieldSet): class FlashFloat64(FieldSet):
def createFields(self): def createFields(self):
yield Bits(self, "mantisa_high", 20) yield Bits(self, "mantissa_high", 20)
yield FloatExponent(self, "exponent", 11) yield FloatExponent(self, "exponent", 11)
yield Bit(self, "negative") yield Bit(self, "negative")
yield Bits(self, "mantisa_low", 32) yield Bits(self, "mantissa_low", 32)
def createValue(self): def createValue(self):
# Manual computation: # Manual computation:
# mantisa = mantisa_high * 2^32 + mantisa_low # mantissa = mantissa_high * 2^32 + mantissa_low
# float = 2^exponent + (1 + mantisa / 2^52) # float = 2^exponent + (1 + mantissa / 2^52)
# (and float is negative if negative=True) # (and float is negative if negative=True)
bytes = self.parent.stream.readBytes( bytes = self.parent.stream.readBytes(
self.absolute_address, self.size//8) self.absolute_address, self.size//8)
@ -44,8 +79,8 @@ TYPE_INFO = {
0x05: (UInt8, "Boolean[]"), 0x05: (UInt8, "Boolean[]"),
0x06: (FlashFloat64, "Double[]"), 0x06: (FlashFloat64, "Double[]"),
0x07: (UInt32, "Integer[]"), 0x07: (UInt32, "Integer[]"),
0x08: (UInt8, "Dictionnary_Lookup_Index[]"), 0x08: (UInt8, "Dictionary_Lookup_Index[]"),
0x09: (UInt16, "Large_Dictionnary_Lookup_Index[]"), 0x09: (UInt16, "Large_Dictionary_Lookup_Index[]"),
} }
def parseBranch(parent, size): def parseBranch(parent, size):
@ -135,7 +170,7 @@ def parseWaitForFrame(parent, size):
def parseWaitForFrameDyn(parent, size): def parseWaitForFrameDyn(parent, size):
yield UInt8(parent, "skip") yield UInt8(parent, "skip")
def parseDeclareDictionnary(parent, size): def parseDeclareDictionary(parent, size):
count = UInt16(parent, "count") count = UInt16(parent, "count")
yield count yield count
for i in range(count.value): for i in range(count.value):
@ -231,7 +266,7 @@ class Instruction(FieldSet):
# Objects # Objects
0x2B: ("Cast_Object[]", "Cast Object", None), 0x2B: ("Cast_Object[]", "Cast Object", None),
0x42: ("Declare_Array[]", "Declare Array", None), 0x42: ("Declare_Array[]", "Declare Array", None),
0x88: ("Declare_Dictionary[]", "Declare Dictionary", parseDeclareDictionnary), 0x88: ("Declare_Dictionary[]", "Declare Dictionary", parseDeclareDictionary),
0x43: ("Declare_Object[]", "Declare Object", None), 0x43: ("Declare_Object[]", "Declare Object", None),
0x3A: ("Delete[]", "Delete", None), 0x3A: ("Delete[]", "Delete", None),
0x3B: ("Delete_All[]", "Delete All", None), 0x3B: ("Delete_All[]", "Delete All", None),
@ -314,3 +349,313 @@ class ActionScript(FieldSet):
def parseActionScript(parent, size): def parseActionScript(parent, size):
yield ActionScript(parent, "action", size=size*8) yield ActionScript(parent, "action", size=size*8)
def FindABC(field):
while not getattr(field, "isABC", False):
field = field.parent
if field is None:
return None
return field
def GetConstant(field, pool, index):
if index == 0:
return None
return FindABC(field)["constant_%s_pool/constant[%i]"%(pool, index)]
def GetMultiname(field, index):
fld = GetConstant(field, "multiname", index)
if fld is None:
return "*"
if "name_index" not in fld:
return "?"
fld2 = GetConstant(fld, "string", fld["name_index"].value)
if fld2 is None:
return "*"
return fld2.value
class ABCStringIndex(FlashU30):
def createDisplay(self):
fld = GetConstant(self, "string", self.value)
if fld is None:
return "*"
return fld.value
class ABCNSIndex(FlashU30):
def createDisplay(self):
fld = GetConstant(self, "namespace", self.value)
if fld is None:
return "*"
return fld.display
class ABCMethodIndex(FlashU30):
def createDisplay(self):
fld = FindABC(self)["method_array/method[%i]"%self.value]
if fld is None:
return "*"
return fld.description
class ABCMultinameIndex(FlashU30):
def createDisplay(self):
return GetMultiname(self, self.value)
class ABCConstantPool(FieldSet):
def __init__(self, parent, name, klass):
FieldSet.__init__(self, parent, 'constant_%s_pool'%name)
self.klass = klass
def createFields(self):
ctr = FlashU30(self, "count")
yield ctr
for i in xrange(ctr.value-1):
yield self.klass(self, "constant[%i]"%(i+1))
class ABCObjectArray(FieldSet):
def __init__(self, parent, name, klass):
self.arrname = name
FieldSet.__init__(self, parent, name+'_array')
self.klass = klass
def createFields(self):
ctr = FlashU30(self, "count")
yield ctr
for i in xrange(ctr.value):
yield self.klass(self, self.arrname+"[]")
class ABCClassArray(FieldSet):
def __init__(self, parent, name):
FieldSet.__init__(self, parent, name+'_array')
def createFields(self):
ctr = FlashU30(self, "count")
yield ctr
for i in xrange(ctr.value):
yield ABCInstanceInfo(self, "instance[]")
for i in xrange(ctr.value):
yield ABCClassInfo(self, "class[]")
class ABCConstantString(FieldSet):
def createFields(self):
yield FlashU30(self, "length")
size = self["length"].value
if size:
yield String(self, "data", size, charset="UTF-8")
def createDisplay(self):
if "data" in self:
return self["data"].display
else:
return "<empty>"
def createValue(self):
if "data" in self:
return self["data"].value
else:
return ""
class ABCConstantNamespace(FieldSet):
NAMESPACE_KIND = {8: "Namespace",
5: "PrivateNamespace",
22: "PackageNamespace",
23: "PacakgeInternalNamespace",
24: "ProtectedNamespace",
25: "ExplicitNamespace",
26: "MultinameL"}
def createFields(self):
yield Enum(UInt8(self, "kind"), self.NAMESPACE_KIND)
yield ABCStringIndex(self, "name_index")
def createDisplay(self):
return "%s %s"%(self["kind"].display, self["name_index"].display)
def createValue(self):
return self["name_index"].value
class ABCConstantNamespaceSet(FieldSet):
def createFields(self):
ctr = FlashU30(self, "namespace_count")
yield ctr
for i in xrange(ctr.value):
yield ABCNSIndex(self, "namespace_index[]")
def createDescription(self):
ret = [fld.display for fld in self.array("namespace_index")]
return ', '.join(ret)
class ABCConstantMultiname(FieldSet):
MULTINAME_KIND = {7: "Qname",
13: "QnameA",
9: "Multiname",
14: "MultinameA",
15: "RTQname",
16: "RTQnameA",
27: "MultinameL",
17: "RTQnameL",
18: "RTQnameLA"}
def createFields(self):
yield Enum(UInt8(self, "kind"), self.MULTINAME_KIND)
kind = self["kind"].value
if kind in (7,13): # Qname
yield FlashU30(self, "namespace_index")
yield ABCStringIndex(self, "name_index")
elif kind in (9,14): # Multiname
yield ABCStringIndex(self, "name_index")
yield FlashU30(self, "namespace_set_index")
elif kind in (15,16): # RTQname
yield ABCStringIndex(self, "name_index")
elif kind == 27: # MultinameL
yield FlashU30(self, "namespace_set_index")
elif kind in (17,18): # RTQnameL
pass
def createDisplay(self):
kind = self["kind"].display
if "name_index" in self:
return kind + " " + self["name_index"].display
return kind
def createValue(self):
return self["kind"].value
class ABCTrait(FieldSet):
TRAIT_KIND = {0: "slot",
1: "method",
2: "getter",
3: "setter",
4: "class",
5: "function",
6: "const",}
def createFields(self):
yield ABCMultinameIndex(self, "name_index")
yield Enum(Bits(self, "kind", 4), self.TRAIT_KIND)
yield Enum(Bit(self, "is_final"), {True:'final',False:'virtual'})
yield Enum(Bit(self, "is_override"), {True:'override',False:'new'})
yield Bit(self, "has_metadata")
yield Bits(self, "unused", 1)
kind = self["kind"].value
if kind in (0,6): # slot, const
yield FlashU30(self, "slot_id")
yield ABCMultinameIndex(self, "type_index")
### TODO reference appropriate constant pool using value_kind
yield FlashU30(self, "value_index")
if self['value_index'].value != 0:
yield UInt8(self, "value_kind")
elif kind in (1,2,3): # method, getter, setter
yield FlashU30(self, "disp_id")
yield ABCMethodIndex(self, "method_info")
elif kind == 4: # class
yield FlashU30(self, "disp_id")
yield FlashU30(self, "class_info")
elif kind == 5: # function
yield FlashU30(self, "disp_id")
yield ABCMethodIndex(self, "method_info")
if self['has_metadata'].value:
yield ABCObjectArray(self, "metadata", FlashU30)
class ABCValueKind(FieldSet):
def createFields(self):
yield FlashU30(self, "value_index")
yield UInt8(self, "value_kind")
class ABCMethodInfo(FieldSet):
def createFields(self):
yield FlashU30(self, "param_count")
yield ABCMultinameIndex(self, "ret_type")
for i in xrange(self["param_count"].value):
yield ABCMultinameIndex(self, "param_type[]")
yield ABCStringIndex(self, "name_index")
yield Bit(self, "need_arguments")
yield Bit(self, "need_activation")
yield Bit(self, "need_rest")
yield Bit(self, "has_optional")
yield Bit(self, "ignore_rest")
yield Bit(self, "explicit")
yield Bit(self, "setsdxns")
yield Bit(self, "has_paramnames")
if self["has_optional"].value:
yield ABCObjectArray(self, "optional", ABCValueKind)
if self["has_paramnames"].value:
for i in xrange(self["param_count"].value):
yield FlashU30(self, "param_name[]")
def createDescription(self):
ret = GetMultiname(self, self["ret_type"].value)
ret += " " + self["name_index"].display
ret += "(" + ", ".join(GetMultiname(self, fld.value) for fld in self.array("param_type")) + ")"
return ret
class ABCMetadataInfo(FieldSet):
def createFields(self):
yield ABCStringIndex(self, "name_index")
yield FlashU30(self, "values_count")
count = self["values_count"].value
for i in xrange(count):
yield FlashU30(self, "key[]")
for i in xrange(count):
yield FlashU30(self, "value[]")
class ABCInstanceInfo(FieldSet):
def createFields(self):
yield ABCMultinameIndex(self, "name_index")
yield ABCMultinameIndex(self, "super_index")
yield Bit(self, "is_sealed")
yield Bit(self, "is_final")
yield Bit(self, "is_interface")
yield Bit(self, "is_protected")
yield Bits(self, "unused", 4)
if self['is_protected'].value:
yield ABCNSIndex(self, "protectedNS")
yield FlashU30(self, "interfaces_count")
for i in xrange(self["interfaces_count"].value):
yield ABCMultinameIndex(self, "interface[]")
yield ABCMethodIndex(self, "iinit_index")
yield ABCObjectArray(self, "trait", ABCTrait)
class ABCClassInfo(FieldSet):
def createFields(self):
yield ABCMethodIndex(self, "cinit_index")
yield ABCObjectArray(self, "trait", ABCTrait)
class ABCScriptInfo(FieldSet):
def createFields(self):
yield ABCMethodIndex(self, "init_index")
yield ABCObjectArray(self, "trait", ABCTrait)
class ABCException(FieldSet):
def createFields(self):
yield FlashU30(self, "start")
yield FlashU30(self, "end")
yield FlashU30(self, "target")
yield FlashU30(self, "type_index")
yield FlashU30(self, "name_index")
class ABCMethodBody(FieldSet):
def createFields(self):
yield ABCMethodIndex(self, "method_info")
yield FlashU30(self, "max_stack")
yield FlashU30(self, "max_regs")
yield FlashU30(self, "scope_depth")
yield FlashU30(self, "max_scope")
yield FlashU30(self, "code_length")
yield RawBytes(self, "code", self['code_length'].value)
yield ABCObjectArray(self, "exception", ABCException)
yield ABCObjectArray(self, "trait", ABCTrait)
def parseABC(parent, size):
code = parent["code"].value
if code == parent.TAG_DO_ABC_DEFINE:
yield UInt32(parent, "action_flags")
yield CString(parent, "action_name")
yield UInt16(parent, "minor_version")
yield UInt16(parent, "major_version")
parent.isABC = True
yield ABCConstantPool(parent, "int", FlashS32)
yield ABCConstantPool(parent, "uint", FlashU32)
yield ABCConstantPool(parent, "double", Float64)
yield ABCConstantPool(parent, "string", ABCConstantString)
yield ABCConstantPool(parent, "namespace", ABCConstantNamespace)
yield ABCConstantPool(parent, "namespace_set", ABCConstantNamespaceSet)
yield ABCConstantPool(parent, "multiname", ABCConstantMultiname)
yield ABCObjectArray(parent, "method", ABCMethodInfo)
yield ABCObjectArray(parent, "metadata", ABCMetadataInfo)
yield ABCClassArray(parent, "class")
yield ABCObjectArray(parent, "script", ABCScriptInfo)
yield ABCObjectArray(parent, "body", ABCMethodBody)

View file

@ -39,15 +39,15 @@ Author: Victor Stinner
Creation date: 24 september 2006 Creation date: 24 september 2006
""" """
from lib.hachoir_parser import Parser from hachoir_parser import Parser
from lib.hachoir_core.field import (FieldSet, from hachoir_core.field import (FieldSet,
FieldError, ParserError, FieldError, ParserError,
Bit, Bits, Bytes, UInt8, GenericInteger, String, Bit, Bits, Bytes, UInt8, GenericInteger, String,
Field, Enum, RawBytes) Field, Enum, RawBytes)
from lib.hachoir_core.endian import BIG_ENDIAN from hachoir_core.endian import BIG_ENDIAN
from lib.hachoir_core.tools import createDict, humanDatetime from hachoir_core.tools import createDict, humanDatetime
from lib.hachoir_core.stream import InputStreamError from hachoir_core.stream import InputStreamError
from lib.hachoir_core.text_handler import textHandler from hachoir_core.text_handler import textHandler
# --- Field parser --- # --- Field parser ---

View file

@ -4,18 +4,18 @@
# Created: 8 june 2006 # Created: 8 june 2006
# #
from lib.hachoir_parser import Parser from hachoir_parser import Parser
from lib.hachoir_core.field import (FieldSet, Link, from hachoir_core.field import (FieldSet, Link,
MissingField, ParserError, MissingField, ParserError,
Enum as _Enum, String as _String, Enum as _Enum, String as _String,
Float32, Float64, Float32, Float64,
NullBits, Bits, Bit, RawBytes, Bytes, NullBits, Bits, Bit, RawBytes, Bytes,
Int16, GenericInteger) Int16, GenericInteger)
from lib.hachoir_core.endian import BIG_ENDIAN from hachoir_core.endian import BIG_ENDIAN
from lib.hachoir_core.iso639 import ISO639_2 from hachoir_core.iso639 import ISO639_2
from lib.hachoir_core.tools import humanDatetime from hachoir_core.tools import humanDatetime
from lib.hachoir_core.text_handler import textHandler, hexadecimal from hachoir_core.text_handler import textHandler, hexadecimal
from lib.hachoir_parser.container.ogg import XiphInt from hachoir_parser.container.ogg import XiphInt
from datetime import datetime, timedelta from datetime import datetime, timedelta
class RawInt(GenericInteger): class RawInt(GenericInteger):
@ -66,7 +66,7 @@ def SInt(parent):
return GenericInteger(parent, 'signed', True, parent['size'].value*8) return GenericInteger(parent, 'signed', True, parent['size'].value*8)
def String(parent): def String(parent):
return _String(parent, 'string', parent['size'].value, charset="ASCII") return _String(parent, 'string', parent['size'].value, charset="ASCII", strip="\0")
def EnumString(parent, enum): def EnumString(parent, enum):
return _Enum(String(parent), enum) return _Enum(String(parent), enum)
@ -206,7 +206,7 @@ class Block(FieldSet):
yield Bit(self, 'invisible') yield Bit(self, 'invisible')
yield self.lacing() yield self.lacing()
yield NullBits(self, 'reserved[]', 1) yield NullBits(self, 'reserved[]', 1)
elif self.parent._name == 'SimpleBlock[]': elif self.parent._name.startswith('SimpleBlock'):
yield Bit(self, 'keyframe') yield Bit(self, 'keyframe')
yield NullBits(self, 'reserved', 3) yield NullBits(self, 'reserved', 3)
yield Bit(self, 'invisible') yield Bit(self, 'invisible')

View file

@ -4,15 +4,15 @@
# Created: 10 june 2006 # Created: 10 june 2006
# #
from lib.hachoir_parser import Parser from hachoir_parser import Parser
from lib.hachoir_core.field import (Field, FieldSet, createOrphanField, from hachoir_core.field import (Field, FieldSet, createOrphanField,
NullBits, Bit, Bits, Enum, Fragment, MissingField, ParserError, NullBits, Bit, Bits, Enum, Fragment, MissingField, ParserError,
UInt8, UInt16, UInt24, UInt32, UInt64, UInt8, UInt16, UInt24, UInt32, UInt64,
RawBytes, String, PascalString32, NullBytes) RawBytes, String, PascalString32, NullBytes)
from lib.hachoir_core.stream import FragmentedStream, InputStreamError from hachoir_core.stream import FragmentedStream, InputStreamError
from lib.hachoir_core.endian import LITTLE_ENDIAN, BIG_ENDIAN from hachoir_core.endian import LITTLE_ENDIAN, BIG_ENDIAN
from lib.hachoir_core.tools import humanDurationNanosec from hachoir_core.tools import humanDurationNanosec
from lib.hachoir_core.text_handler import textHandler, hexadecimal from hachoir_core.text_handler import textHandler, hexadecimal
MAX_FILESIZE = 1000 * 1024 * 1024 MAX_FILESIZE = 1000 * 1024 * 1024

Some files were not shown because too many files have changed in this diff Show more