180 changed files with 7085 additions and 2472 deletions
@ -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 |
|||
|
|||
|
@ -1,11 +1,11 @@ |
|||
from lib.hachoir_core.endian import BIG_ENDIAN, LITTLE_ENDIAN |
|||
from lib.hachoir_core.stream.stream import StreamError |
|||
from lib.hachoir_core.stream.input import ( |
|||
from hachoir_core.endian import BIG_ENDIAN, LITTLE_ENDIAN |
|||
from hachoir_core.stream.stream import StreamError |
|||
from hachoir_core.stream.input import ( |
|||
InputStreamError, |
|||
InputStream, InputIOStream, StringInputStream, |
|||
InputSubStream, InputFieldStream, |
|||
FragmentedStream, ConcatStream) |
|||
from lib.hachoir_core.stream.input_helper import FileInputStream, guessStreamCharset |
|||
from lib.hachoir_core.stream.output import (OutputStreamError, |
|||
from hachoir_core.stream.input_helper import FileInputStream, guessStreamCharset |
|||
from hachoir_core.stream.output import (OutputStreamError, |
|||
FileOutputStream, StringOutputStream, OutputStream) |
|||
|
|||
|
@ -1,5 +1,5 @@ |
|||
PACKAGE = "hachoir-core" |
|||
VERSION = "1.3.3" |
|||
VERSION = "1.3.4" |
|||
WEBSITE = 'http://bitbucket.org/haypo/hachoir/wiki/hachoir-core' |
|||
LICENSE = 'GNU GPL v2' |
|||
|
|||
|
@ -1,15 +1,15 @@ |
|||
from lib.hachoir_metadata.version import VERSION as __version__ |
|||
from lib.hachoir_metadata.metadata import extractMetadata |
|||
from hachoir_metadata.version import VERSION as __version__ |
|||
from hachoir_metadata.metadata import extractMetadata |
|||
|
|||
# Just import the module, |
|||
# each module use registerExtractor() method |
|||
import lib.hachoir_metadata.archive |
|||
import lib.hachoir_metadata.audio |
|||
import lib.hachoir_metadata.file_system |
|||
import lib.hachoir_metadata.image |
|||
import lib.hachoir_metadata.jpeg |
|||
import lib.hachoir_metadata.misc |
|||
import lib.hachoir_metadata.program |
|||
import lib.hachoir_metadata.riff |
|||
import lib.hachoir_metadata.video |
|||
import hachoir_metadata.archive |
|||
import hachoir_metadata.audio |
|||
import hachoir_metadata.file_system |
|||
import hachoir_metadata.image |
|||
import hachoir_metadata.jpeg |
|||
import hachoir_metadata.misc |
|||
import hachoir_metadata.program |
|||
import hachoir_metadata.riff |
|||
import hachoir_metadata.video |
|||
|
|||
|
@ -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> |
@ -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)) |
|||
|
@ -1,7 +1,7 @@ |
|||
from lib.hachoir_parser.version import __version__ |
|||
from lib.hachoir_parser.parser import ValidateError, HachoirParser, Parser |
|||
from lib.hachoir_parser.parser_list import ParserList, HachoirParserList |
|||
from lib.hachoir_parser.guess import (QueryParser, guessParser, createParser) |
|||
from lib.hachoir_parser import (archive, audio, container, |
|||
from hachoir_parser.version import __version__ |
|||
from hachoir_parser.parser import ValidateError, HachoirParser, Parser |
|||
from hachoir_parser.parser_list import ParserList, HachoirParserList |
|||
from hachoir_parser.guess import (QueryParser, guessParser, createParser) |
|||
from hachoir_parser import (archive, audio, container, |
|||
file_system, image, game, misc, network, program, video) |
|||
|
|||
|
@ -1,12 +1,13 @@ |
|||
from lib.hachoir_parser.archive.ace import AceFile |
|||
from lib.hachoir_parser.archive.ar import ArchiveFile |
|||
from lib.hachoir_parser.archive.bzip2_parser import Bzip2Parser |
|||
from lib.hachoir_parser.archive.cab import CabFile |
|||
from lib.hachoir_parser.archive.gzip_parser import GzipParser |
|||
from lib.hachoir_parser.archive.tar import TarFile |
|||
from lib.hachoir_parser.archive.zip import ZipFile |
|||
from lib.hachoir_parser.archive.rar import RarFile |
|||
from lib.hachoir_parser.archive.rpm import RpmFile |
|||
from lib.hachoir_parser.archive.sevenzip import SevenZipParser |
|||
from lib.hachoir_parser.archive.mar import MarFile |
|||
|
|||
from hachoir_parser.archive.ace import AceFile |
|||
from hachoir_parser.archive.ar import ArchiveFile |
|||
from hachoir_parser.archive.bzip2_parser import Bzip2Parser |
|||
from hachoir_parser.archive.cab import CabFile |
|||
from hachoir_parser.archive.gzip_parser import GzipParser |
|||
from hachoir_parser.archive.tar import TarFile |
|||
from hachoir_parser.archive.zip import ZipFile |
|||
from hachoir_parser.archive.rar import RarFile |
|||
from hachoir_parser.archive.rpm import RpmFile |
|||
from hachoir_parser.archive.sevenzip import SevenZipParser |
|||
from hachoir_parser.archive.mar import MarFile |
|||
from hachoir_parser.archive.mozilla_ar import MozillaArchive |
|||
from hachoir_parser.archive.zlib import ZlibData |
|||
|
@ -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 |
@ -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) |
@ -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 |
@ -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 |
|||
|
@ -1,12 +1,12 @@ |
|||
from lib.hachoir_parser.audio.aiff import AiffFile |
|||
from lib.hachoir_parser.audio.au import AuFile |
|||
from lib.hachoir_parser.audio.itunesdb import ITunesDBFile |
|||
from lib.hachoir_parser.audio.midi import MidiFile |
|||
from lib.hachoir_parser.audio.mpeg_audio import MpegAudioFile |
|||
from lib.hachoir_parser.audio.real_audio import RealAudioFile |
|||
from lib.hachoir_parser.audio.xm import XMModule |
|||
from lib.hachoir_parser.audio.s3m import S3MModule |
|||
from lib.hachoir_parser.audio.s3m import PTMModule |
|||
from lib.hachoir_parser.audio.mod import AmigaModule |
|||
from lib.hachoir_parser.audio.flac import FlacParser |
|||
from hachoir_parser.audio.aiff import AiffFile |
|||
from hachoir_parser.audio.au import AuFile |
|||
from hachoir_parser.audio.itunesdb import ITunesDBFile |
|||
from hachoir_parser.audio.midi import MidiFile |
|||
from hachoir_parser.audio.mpeg_audio import MpegAudioFile |
|||
from hachoir_parser.audio.real_audio import RealAudioFile |
|||
from hachoir_parser.audio.xm import XMModule |
|||
from hachoir_parser.audio.s3m import S3MModule |
|||
from hachoir_parser.audio.s3m import PTMModule |
|||
from hachoir_parser.audio.mod import AmigaModule |
|||
from hachoir_parser.audio.flac import FlacParser |
|||
|
|||
|
@ -1,7 +1,7 @@ |
|||
from lib.hachoir_parser.container.asn1 import ASN1File |
|||
from lib.hachoir_parser.container.mkv import MkvFile |
|||
from lib.hachoir_parser.container.ogg import OggFile, OggStream |
|||
from lib.hachoir_parser.container.riff import RiffFile |
|||
from lib.hachoir_parser.container.swf import SwfFile |
|||
from lib.hachoir_parser.container.realmedia import RealMediaFile |
|||
from hachoir_parser.container.asn1 import ASN1File |
|||
from hachoir_parser.container.mkv import MkvFile |
|||
from hachoir_parser.container.ogg import OggFile, OggStream |
|||
from hachoir_parser.container.riff import RiffFile |
|||
from hachoir_parser.container.swf import SwfFile |
|||
from hachoir_parser.container.realmedia import RealMediaFile |
|||
|
|||
|
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue