예제 #1
0
 def read_object(self,
                 expected_type_reader=None,
                 type_params=None,
                 expected_type=None):
     type_id = self.read_7bit_encoded_int()
     if type_id == 0:
         # null object
         return None
     try:
         type_reader = self.type_readers[type_id - 1]
     except IndexError:
         raise ReaderError("type id out of range: {} > {}".format(
             type_id, len(self.type_readers)))
     if expected_type_reader is not None:
         try:
             if expected_type_reader.is_generic_type and expected_type_reader.target_type is None:
                 expected_type = generic_reader_type(
                     expected_type_reader, type_params)
             elif expected_type_reader.is_enum_type:
                 expected_type = generic_reader_type(
                     EnumReader, [expected_type_reader.target_type])
             else:
                 expected_type = expected_type_reader.target_type
         except AttributeError:
             raise ReaderError("bad expected_type_reader: '{}'".format(
                 expected_type_reader))
     if expected_type is not None:
         if type_reader.target_type != expected_type:
             raise ReaderError("Unexpected type: '{}' != '{}'".format(
                 type_reader.target_type, expected_type))
     return type_reader.read()
예제 #2
0
    def __init__(self, width, height, surface_format, data, needs_swap=False):
        if surface_format not in self._FORMATS:
            raise ReaderError(
                "Unknown DXT format: '{}'".format(surface_format))
        if (width | height) & 3:
            raise ReaderError("Bad dimensions for DXT: {}x{}".format(
                width, height))
        self.width = width
        self.height = height
        self.surface_format = surface_format
        self.data = data
        self.block_size = self._FORMATS[self.surface_format]
        stride = (self.width >> 2) * self.block_size
        expected_len = stride * (self.height >> 2)
        if len(self.data) != expected_len:
            raise ReaderError("Invalid data size for DXT: {} != {}".format(
                len(data), expected_len))
        self.out_rows = [
            bytearray([0] * self.width * 4),
            bytearray([0] * self.width * 4),
            bytearray([0] * self.width * 4),
            bytearray([0] * self.width * 4)
        ]
        if needs_swap:
            self.swap_struct = Struct('>HHHH')
        else:
            self.swap_struct = Struct('<HHHH')

        self.explicit_alphas = []
        for cur_a in range(16):
            self.explicit_alphas.append(cur_a * 17)
예제 #3
0
 def __init__(self):
     self.type_readers = {}
     self.type_readers_type = {}
     self.generic_type_readers = {}
     self.generic_type_readers_type = {}
     for class_ in TypeReaderPlugin.__subclasses__():
         if issubclass(class_, GenericTypeReader):
             if class_.generic_reader_name in self.generic_type_readers:
                 raise ReaderError(
                     "Duplicate generic type reader name: '{}'".format(
                         class_.generic_reader_name))
             self.generic_type_readers[class_.generic_reader_name] = class_
             if class_.generic_target_type in self.generic_type_readers_type:
                 raise ReaderError(
                     "Duplicate generic type reader type: '{}'".format(
                         class_.generic_target_type))
             self.generic_type_readers_type[
                 class_.generic_target_type] = class_
         elif issubclass(class_, BaseTypeReader):
             if class_.reader_name in self.type_readers:
                 raise ReaderError(
                     "Duplicate type reader name: '{}'".format(
                         class_.reader_name))
             self.type_readers[class_.reader_name] = class_
             if class_.target_type in self.type_readers_type:
                 raise ReaderError(
                     "Duplicate type reader type: '{}'".format(
                         class_.target_type))
             self.type_readers_type[class_.target_type] = class_
         else:
             raise ReaderError(
                 "Unknown base class for reader: '{!s}'".format(class_))
예제 #4
0
    def get_type_reader_by_type(self, type_reader):
        try:
            reader_type = type_reader.target_type
        except AttributeError:
            reader_type = type_reader

        type_spec = TypeSpec.parse(reader_type)

        if type_spec.full_name in self.type_readers_type:
            return self.type_readers_type[type_spec.full_name]

        if type_spec.generic_params:
            if type_spec.name in self.generic_type_readers_type:
                generic_type_class = self.generic_type_readers_type[
                    type_spec.name]
                generic_type_reader_class = generic_type_class.create_from_type(
                    type_spec)
                if generic_type_reader_class.reader_name in self.type_readers:
                    raise ReaderError(
                        "Duplicate type reader name from generic: '{}' '{}'".
                        format(generic_type_reader_class.reader_name,
                               generic_type_class.generic_reader_name))
                self.type_readers[generic_type_reader_class.
                                  reader_name] = generic_type_reader_class
                if generic_type_reader_class.target_type in self.type_readers_type:
                    raise ReaderError(
                        "Duplicate type reader type from generic: '{}' '{}'".
                        format(generic_type_reader_class.target_type,
                               generic_type_class.generic_target_type))
                self.type_readers_type[generic_type_reader_class.
                                       target_type] = generic_type_reader_class
                return generic_type_reader_class

        raise ReaderError("Type reader not found: '{}'".format(
            type_spec.full_name))
예제 #5
0
파일: xsb.py 프로젝트: ZandrXandr/Fezzer-2
 def __init__(self, stream):
     start_pos = stream.tell()
     (self.flags, self.category, self.volume, self.pitch, self.priority,
      entry_len) = stream.unpack(_SB_SOUND)
     if self.flags & ~SB_SOUND_FLAGS_MASK:
         raise ReaderError("Unknown flags in SB_SOUND")
     clip_count = 0
     if self.is_complex:
         clip_count = stream.read_byte()
     else:
         self.track = stream.read_uint16()
         self.wavebank = stream.read_byte()
     if self.has_rpc_sound or self.has_rpc_track or self.has_rpc_effect:
         rpc_pos = stream.tell()
         rpc_extra = stream.read_uint16()
         # TODO: parse RPC data
         stream.seek(rpc_pos + rpc_extra)
     if self.has_dsp:
         dsp_pos = stream.tell()
         dsp_extra = stream.read_uint16()
         # TODO: parse DSP data
         stream.seek(dsp_pos + dsp_extra)
     self.clips = []
     if self.is_complex:
         self.clips = [Clip(stream) for _ in range(clip_count)]
     if stream.tell() > entry_len + start_pos:
         raise ReaderError("SB_SOUND length mismatch")
예제 #6
0
def decode32(data, width, height, conv, alpha='yes'):
    if conv not in ('rgba_rgba', 'abgr_rgba', 'bgra_rgba', 'argb_rgba'):
        raise ReaderError("Unknown conversion: '{}'".format(conv))
    if alpha not in ('yes', 'no', 'only'):
        raise ValueError("Invalid alpha parameter: '{}'".format(alpha))
    stride = width * 4
    expected_len = stride * height
    if len(data) != expected_len:
        raise ReaderError("Invalid data size: {} != {}".format(
            len(data), expected_len))
    full_row_ff = bytearray([0xff] * width)
    for pos in range(0, len(data), stride):
        row = bytearray(data[pos:pos + stride])
        if conv == 'bgra_rgba':
            row[2::4], row[1::4], row[0::4], row[3::4] = row[0::4], row[
                1::4], row[2::4], row[3::4]
        elif conv == 'argb_rgba':
            row[3::4], row[0::4], row[1::4], row[2::4] = row[0::4], row[
                1::4], row[2::4], row[3::4]
        elif conv == 'abgr_rgba':
            row[3::4], row[2::4], row[1::4], row[0::4] = row[0::4], row[
                1::4], row[2::4], row[3::4]
        if alpha == 'no':
            row[3::4] = full_row_ff
        elif alpha == 'only':
            row[0::4] = full_row_ff
            row[1::4] = full_row_ff
            row[2::4] = full_row_ff
        yield row
예제 #7
0
    def __init__(self, header, data, dpds=None, seek=None, needs_swap=False):
        self.header_raw = header
        self.data_raw = data
        self.dpds_raw = dpds
        self.seek_raw = seek
        self.needs_swap = needs_swap

        h_s = BinaryStream(data=self.header_raw, big_endian=needs_swap)
        waveformatex_size = h_s.calc_size(self._waveformatex)
        (self.h_format_tag, self.h_channels, self.h_samples_per_sec,
         self.h_avg_bytes_per_sec, self.h_block_align,
         self.h_bits_per_sample) = h_s.unpack(self._waveformatex)
        header_size = waveformatex_size

        # do we have a WAVEFORMATEX
        self.h_size = None
        if len(self.header_raw) >= waveformatex_size + 2:
            self.h_size = h_s.read_uint16()
            header_size += 2

            if self.h_format_tag == WAVE_FORMAT_XMA2:
                waveformat_xma2_size = h_s.calc_size(self._waveformat_xma2)
                if self.h_size != waveformat_xma2_size:
                    raise ReaderError(
                        "Unknown cbSize for XMA2WAVEFORMATEX: {}".format(
                            self.h_size))
                (self.hx_num_streams, self.hx_channel_mask,
                 self.hx_samples_encoded, self.hx_bytes_per_block,
                 self.hx_play_begin, self.hx_play_length, self.hx_loop_begin,
                 self.hx_loop_length, self.hx_loop_count,
                 self.hx_encoder_version,
                 self.hx_block_count) = h_s.unpack(self._waveformat_xma2)
                header_size += waveformat_xma2_size
            elif self.h_format_tag == WAVE_FORMAT_EXTENSIBLE:
                waveformat_extensible_size = h_s.calc_size(
                    self._waveformat_extensible)
                if self.h_size < waveformat_extensible_size:
                    raise ReaderError(
                        "Invalid cbSize for WAVEFORMATEXTENSIBLE: {}".format(
                            self.h_size))
                (self.he_valid_bits_per_sample, self.he_channel_mask,
                 he_subformat_bytes) = h_s.unpack(self._waveformat_extensible)
                self.he_subformat = UUID(bytes_le=he_subformat_bytes)
                header_size += waveformat_extensible_size
                self.he_remainder = None
                if self.h_size > waveformat_extensible_size:
                    self.he_remainder = h_s.read(self.h_size -
                                                 waveformat_extensible_size)
                    header_size += self.h_size - waveformat_extensible_size
                    raise ReaderError(
                        "Extra bytes in WAVEFORMATEXTENSIBLE: {}".format(
                            len(self.he_remainder)))
            self.h_remainder = h_s.read()
            if len(self.h_remainder):
                header_size += len(self.h_remainder)
        if header_size != len(self.header_raw):
            raise ReaderError("Header size mismatch: {} != {}".format(
                header_size, len(self.header_raw)))
예제 #8
0
def decode8(data, width, height, conv):
    if conv not in ('a_xxxa', ):
        raise ReaderError("Unknown conversion: '{}'".format(conv))
    stride = width
    expected_len = stride * height
    if len(data) != expected_len:
        raise ReaderError("Invalid data size: {} != {}".format(
            len(data), expected_len))
    for pos in range(0, len(data), stride):
        row = bytearray([0xff] * width * 4)
        row[3::4] = data[pos:pos + stride]
        yield row
예제 #9
0
 def __init__(self, root_dir):
     root_dir = os.path.normpath(root_dir)
     if not os.path.isdir(root_dir):
         raise ReaderError("Content root directory not found: '%s'" %
                           root_dir)
     self.root_dir = root_dir
     self._asset_dict = OrderedDict(self.find_assets())
     self.assets = self._asset_dict.keys()
예제 #10
0
def get_surface_format(xna_version, surface_format):
    try:
        if xna_version >= VERSION_40:
            return SurfaceFormat4(surface_format)
        else:
            return SurfaceFormat(surface_format)
    except KeyError:
        raise ReaderError("Invalid surface format for V{}: {}".format(
            xna_version, surface_format))
예제 #11
0
 def read_type_id(self):
     type_id = self.read_7bit_encoded_int()
     if type_id == 0:
         # null object
         return None
     try:
         return self.type_readers[type_id - 1]
     except IndexError:
         raise ReaderError("type id out of range: {} > {}".format(
             type_id, len(self.type_readers)))
예제 #12
0
파일: xsb.py 프로젝트: ZandrXandr/Fezzer-2
 def __init__(self, name, stream, is_complex=False):
     self.name = name
     self.flags = stream.read_byte()
     if self.flags & ~SB_CUE_FLAGS_MASK:
         raise ReaderError("Unknown flags in SB_CUE")
     sound_offset = None
     unknown_offset = None
     variation_offset = None
     transition_offset = None
     if self.is_complex:
         if not is_complex:
             raise ReaderError(
                 "SB_CUE_FLAGS_COMPLEX not set for complex cue")
         if self.has_sound:
             sound_offset = fix_offset(stream.read_int32())
         else:
             variation_offset = fix_offset(stream.read_int32())
         if self.has_transition:
             transition_offset = fix_offset(stream.read_int32())
         else:
             unknown_offset = fix_offset(stream.read_int32())
             if unknown_offset:
                 raise ReaderError("unknown_offset set in complex cue")
         (self.limit, self.fade_in, self.fade_out,
          limit_fade_raw) = stream.unpack(_SB_LIMIT)
         self.fade_type = limit_fade_raw & 0x03
         self.limit_type = limit_fade_raw >> 3
     else:
         if is_complex:
             raise ReaderError("SB_CUE_FLAGS_COMPLEX is set for simple cue")
         if self.has_sound:
             sound_offset = fix_offset(stream.read_int32())
         else:
             unknown_offset = fix_offset(stream.read_int32())
             raise ReaderError("SB_CUE_FLAGS_SOUND not set for simple cue")
     next_cue_offset = stream.tell()
     if sound_offset:
         stream.seek(sound_offset)
         self.sound = Sound(stream)
     stream.seek(next_cue_offset)
예제 #13
0
 def read_object(self,
                 expected_type_reader=None,
                 type_params=None,
                 expected_type=None):
     type_id = self.read_7bit_encoded_int()
     if type_id == 0:
         # null object
         return None
     try:
         type_reader = self.type_readers[type_id - 1]
     except IndexError:
         raise ReaderError("type id out of range: {} > {}".format(
             type_id, len(self.type_readers)))
     if expected_type_reader is not None:
         try:
             if expected_type_reader.is_generic_type and expected_type_reader.target_type is None:
                 expected_type = generic_reader_type(
                     expected_type_reader, type_params)
             elif expected_type_reader.is_enum_type:
                 expected_type = generic_reader_type(
                     EnumReader, [expected_type_reader.target_type])
             else:
                 expected_type = expected_type_reader.target_type
         except AttributeError:
             raise ReaderError("bad expected_type_reader: '{}'".format(
                 expected_type_reader))
     if expected_type is not None:
         if expected_type != 'System.Object':
             if type_reader.target_type != expected_type:
                 # check parent type readers
                 for cls in type_reader.__class__.__mro__:
                     if hasattr(cls, 'target_type'):
                         if cls.target_type == expected_type:
                             break
                 else:
                     raise ReaderError(
                         "Unexpected type: '{}' != '{}'".format(
                             type_reader.target_type, expected_type))
     return type_reader.read()
예제 #14
0
 def export(self, filename, export_file=True, export_xml=True):
     if not hasattr(self, 'content'):
         raise ReaderError("XNB content deleted")
     if self.content is None:
         self.parse()
     filename = os.path.normpath(filename)
     dirname = os.path.dirname(filename)
     if not os.path.isdir(dirname):
         os.makedirs(dirname)
     if export_file and hasattr(self.content, 'export'):
         self.content.export(filename)
     if export_xml and hasattr(self.content, 'xml'):
         output_xml(self.content.xml(), filename + '.xml')
예제 #15
0
 def load(cls, data=None, filename=None, parse=True, expected_type=None):
     if filename is not None:
         filename = os.path.normpath(filename)
     stream = BinaryStream(data=data, filename=filename)
     del data
     (sig, platform, version, attribs, size) = stream.unpack(_XNB_HEADER)
     if sig != XNB_SIGNATURE:
         raise ReaderError("bad sig: '{!r}'".format(sig))
     if platform not in XNB_PLATFORMS:
         raise ReaderError("bad platform: '{!r}'".format(platform))
     if version not in XNB_VERSIONS:
         raise ReaderError("bad version: {}".format(version))
     stream_length = stream.length()
     if stream_length != size:
         raise ReaderError("bad size: {} != {}".format(stream_length, size))
     compressed = False
     profile = 0
     if version >= VERSION_40:
         profile = attribs & _PROFILE_MASK
         if profile not in XNB_PROFILES:
             raise ReaderError("bad profile: {}".format(profile))
     if version >= VERSION_30:
         compressed = bool(attribs & _COMPRESS_MASK)
         size -= stream.calc_size(_XNB_HEADER)
     if compressed:
         uncomp = stream.read_int32()
         size -= 4
         content_comp = stream.read(size)
         content = decompress(content_comp, uncomp)
     else:
         content = stream.read(size)
     return cls(content,
                platform,
                version,
                profile,
                compressed,
                parse=parse,
                expected_type=expected_type)
예제 #16
0
    def full_data(self, alpha='yes'):
        if not self.surface_format.reader:
            raise ReaderError("No decoder found: '{}'".format(
                self.surface_format))

        rows = self.surface_format.reader(self.mip_levels[0],
                                          self.width,
                                          self.height,
                                          self.needs_swap,
                                          alpha=alpha)
        data = bytearray()
        for row in rows:
            data.extend(row)
        return bytes(data)
예제 #17
0
 def save(self, filename=None, compress=False):
     if self.file_platform not in XNB_PLATFORMS:
         raise ReaderError("bad platform: '{!r}'".format(
             self.file_platform))
     if self.file_version not in XNB_VERSIONS:
         raise ReaderError("bad version: {}".format(self.file_version))
     attribs = 0
     if self.file_version >= VERSION_40:
         if self.graphics_profile not in XNB_PROFILES:
             raise ReaderError("bad profile: {}".format(
                 self.graphics_profile))
         attribs |= self.graphics_profile & _PROFILE_MASK
     do_compress = False
     if self.file_version >= VERSION_30:
         if compress:
             do_compress = True
             attribs |= _COMPRESS_MASK
     stream = BinaryStream()
     if do_compress:
         raise ReaderError("Recompression not supported")
     else:
         data = self.getvalue()
         size = len(data) + stream.calc_size(_XNB_HEADER)
     stream.pack(_XNB_HEADER, XNB_SIGNATURE, self.file_platform,
                 self.file_version, attribs, size)
     stream.write(data)
     if filename is not None:
         filename = os.path.normpath(filename)
         dirname = os.path.dirname(filename)
         if not os.path.isdir(dirname):
             os.makedirs(dirname)
         if not filename.endswith(XNB_EXTENSION):
             filename += XNB_EXTENSION
         stream.write_file(filename)
     else:
         return stream.getvalue()
예제 #18
0
    def parse(self, expected_type=None, verbose=False):
        if self.content is not None:
            return self.content

        reader_count = self.read_7bit_encoded_int()
        for _ in range(reader_count):
            reader_name = self.read_string()
            reader_version = self.read_int32()
            reader = self.get_type_reader(reader_name, reader_version)
            self.type_readers.append(reader)

        if verbose:
            print("Type: {!s}".format(self.type_readers[0]))

        for reader in self.type_readers:
            reader.init_reader(self.file_platform, self.file_version)

        shared_count = self.read_7bit_encoded_int()

        if shared_count:
            raise ReaderError("Shared resources present")

        self.content = self.read_object(expected_type=expected_type)
        if verbose:
            print("Asset: {!s}".format(self.content))

        for i in range(shared_count):
            obj = self.read_object()
            self.shared_objects.append(obj)
            if verbose:
                print("Shared resource {}: {!s}".format(i, obj))

        remaining = self.read()
        if len(remaining):
            raise ReaderError("remaining: {}".format(len(remaining)))
        return self.content
예제 #19
0
 def find_assets(self):
     for pak_file in self.content_pak_files:
         filename = os.path.join(self.root_dir, pak_file)
         if not os.path.isfile(filename):
             raise ReaderError(
                 "Content pak not found in content root: '{}'".format(
                     filename))
         stream = BinaryStream(filename=filename)
         capacity = stream.read_int32()
         for _ in range(capacity):
             asset_name = stream.read_string()
             asset_size = stream.read_int32()
             asset_data = stream.read(asset_size)
             asset_name = asset_name.replace('\\', '/')
             asset_name = asset_name.lower()
             yield asset_name, asset_data
예제 #20
0
    def export(self, filename):
        if not self.surface_format.reader:
            raise ReaderError("No decoder found: '{}'".format(
                self.surface_format))
        dirname = os.path.dirname(filename)
        if not os.path.isdir(dirname):
            os.makedirs(dirname)

        # hack for ArtObject/TrileSet alpha channel
        alpha = 'yes'
        if 'art objects' in filename or 'trile sets' in filename:
            alpha = 'no'
            rows = self.surface_format.reader(self.mip_levels[0],
                                              self.width,
                                              self.height,
                                              self.needs_swap,
                                              alpha='only')
            write_png(filename + '_alpha', self.width, self.height, rows)
        rows = self.surface_format.reader(self.mip_levels[0],
                                          self.width,
                                          self.height,
                                          self.needs_swap,
                                          alpha=alpha)
        write_png(filename, self.width, self.height, rows)
예제 #21
0
 def read(self):
     raise ReaderError("TextureReader should never be invoked directly")
예제 #22
0
파일: xwb.py 프로젝트: ZandrXandr/Fezzer-2
    def __init__(self, data=None, filename=None, audio_engine=None):
        self.audio_engine = audio_engine

        # open in little endian initially
        stream = BinaryStream(data=data, filename=filename)
        del data

        # check sig to find actual endianess
        h_sig = stream.peek(len(WB_L_SIGNATURE))
        if h_sig == WB_L_SIGNATURE:
            big_endian = False
        elif h_sig == WB_B_SIGNATURE:
            big_endian = True
        else:
            raise ValueError("bad sig: {!r}".format(h_sig))

        # switch stream to correct endianess
        stream.set_endian(big_endian)
        (h_sig, self.h_version,
         self.h_header_version) = stream.unpack(_WB_HEADER)
        regions = {
            k: XWBRegion._make(stream.unpack(_WB_REGION))
            for k in _REGIONS
        }  # pylint: disable-msg=W0212

        # check if we have a valid BANKDATA region and parse it
        bankdata_size = stream.calc_size(_WB_DATA)
        if regions['BANKDATA'].length != bankdata_size:
            raise ReaderError("Invalid BANKDATA size: {} != {}".format(
                regions['BANKDATA'].length, bankdata_size))
        stream.seek(regions['BANKDATA'].offset)
        (self.flags, h_entry_count, h_bank_name_raw,
         h_entry_metadata_element_size, h_entry_name_element_size,
         self.alignment, h_compact_format, buildtime_raw_low,
         buildtime_raw_high) = stream.unpack(_WB_DATA)
        self.bank_name = h_bank_name_raw.rstrip(b'\x00').decode('iso8859-1')
        del h_bank_name_raw
        self.buildtime = filetime_to_datetime(buildtime_raw_low,
                                              buildtime_raw_high)

        if self.flags & ~(WB_TYPE_MASK | WB_FLAGS_MASK):
            raise ReaderError("Unknown flags in WAVEBANK")

        # check what type of ENTRYMETADATA we have and parse it
        if self.has_compact:
            raise ReaderError("Compact format not supported")
        bankentry_size = stream.calc_size(_WB_ENTRY)
        if bankentry_size != h_entry_metadata_element_size:
            raise ReaderError(
                "Unknown EntryMetaDataElementSize: {} != {}".format(
                    bankentry_size, h_entry_metadata_element_size))
        if regions['ENTRYMETADATA'].length != bankentry_size * h_entry_count:
            raise ReaderError("Invalid ENTRYMETADATA size: {} != {}".format(
                regions['ENTRYMETADATA'].length,
                bankentry_size * h_entry_count))
        stream.seek(regions['ENTRYMETADATA'].offset)
        entry_metadata = [
            XWBEntry._make(
                stream.unpack(_WB_ENTRY))  # pylint: disable-msg=W0212,E1101
            for _ in range(h_entry_count)
        ]

        # read ENTRYNAMES if present
        entry_names = []
        if self.has_entry_names and regions['ENTRYNAMES'].offset and regions[
                'ENTRYNAMES'].length:
            if regions[
                    'ENTRYNAMES'].length != h_entry_name_element_size * h_entry_count:
                raise ReaderError(
                    "Invalid ENTRYNAMES region size: {} != {}".format(
                        regions['ENTRYNAMES'].length,
                        h_entry_name_element_size * h_entry_count))
            stream.seek(regions['ENTRYNAMES'].offset)
            entry_names = [
                stream.read(h_entry_name_element_size).rstrip(b'\x00').decode(
                    'iso8859-1') for _ in range(h_entry_count)
            ]

        # read SEEKTABLES if present
        entry_seektables = []
        if self.has_seek_tables and regions['SEEKTABLES'].offset and regions[
                'SEEKTABLES'].length:
            stream.seek(regions['SEEKTABLES'].offset)
            seek_offsets = []
            for _ in range(h_entry_count):
                seek_offsets.append(stream.read_int32())
            seek_data_offset = stream.tell()
            for cur_offset in seek_offsets:
                if cur_offset >= 0:
                    stream.seek(seek_data_offset + cur_offset)
                    packet_count = stream.read_uint32()
                    cur_seek_data = BinaryStream()
                    for _ in range(packet_count):
                        cur_seek_data.write_uint32(stream.read_uint32())
                    entry_seektables.append(cur_seek_data.getvalue())
                else:
                    entry_seektables.append(None)

        self.entries = []
        for i, cur_meta in enumerate(entry_metadata):
            c_entry_flags = cur_meta.flags_duration & WB_ENTRY_FLAGS_MASK
            c_duration = (cur_meta.flags_duration
                          & WB_ENTRY_DURATION_MASK) >> 4
            c_format_tag = cur_meta.format & WB_FORMAT_TAG_MASK
            c_channels = (cur_meta.format & WB_FORMAT_CHANNELS) >> 2
            c_samples_per_sec = (cur_meta.format
                                 & WB_FORMAT_SAMPLES_PER_SEC) >> 5
            c_block_align = (cur_meta.format & WB_FORMAT_BLOCK_ALIGN) >> 23
            c_bits_per_sample = (cur_meta.format
                                 & WB_FORMAT_BITS_PER_SAMPLE) >> 31
            entry_name = None
            if entry_names:
                entry_name = entry_names[i]
            entry_dpds = None
            entry_seek = None
            extra_header = bytes()
            # build format specific header and seek data
            if c_format_tag == WB_FORMAT_TAG_PCM:
                c_format_tag = WAVE_FORMAT_PCM
                if c_bits_per_sample == 1:
                    c_bits_per_sample = 16
                else:
                    c_bits_per_sample = 8
                c_avg_bytes_per_sec = c_samples_per_sec * c_block_align
            elif c_format_tag == WB_FORMAT_TAG_ADPCM:
                c_format_tag = WAVE_FORMAT_ADPCM
                c_bits_per_sample = 4
                c_block_align = (c_block_align +
                                 ADPCM_BLOCK_ALIGN_OFFSET) * c_channels
                cx_samples_per_block = (
                    (c_block_align - (7 * c_channels)) *
                    8) // (c_bits_per_sample * c_channels) + 2
                c_avg_bytes_per_sec = (c_samples_per_sec //
                                       cx_samples_per_block) * c_block_align
                cx_num_coef = len(ADPCM_COEF)
                extra_header = _ADPCM_WAVEFORMAT.pack(cx_samples_per_block,
                                                      cx_num_coef)
                for coef in ADPCM_COEF:
                    extra_header += _ADPCM_WAVEFORMAT_COEF.pack(
                        coef[0], coef[1])
            elif c_format_tag == WB_FORMAT_TAG_WMA:
                if c_bits_per_sample == 1:
                    c_format_tag = WAVE_FORMAT_WMAUDIO3
                else:
                    c_format_tag = WAVE_FORMAT_WMAUDIO2
                c_bits_per_sample = 16
                c_avg_bytes_per_sec = WMA_AVG_BYTES_PER_SEC[c_block_align >> 5]
                c_block_align = WMA_BLOCK_ALIGN[c_block_align & 0x1f]
                if entry_seektables:
                    entry_dpds = entry_seektables[i]
                else:
                    raise ReaderError("No SEEKTABLES found for xWMA format")
            elif c_format_tag == WB_FORMAT_TAG_XMA:
                # lots of placeholders in here but seems to decode ok
                c_format_tag = WAVE_FORMAT_XMA2
                c_bits_per_sample = 16
                c_avg_bytes_per_sec = 0
                cx_num_streams = 1
                if c_channels == 2:
                    cx_channel_mask = 3
                else:
                    cx_channel_mask = 0
                cx_samples_encoded = 0
                cx_bytes_per_block = 0
                cx_play_begin = 0
                cx_play_length = 0
                cx_loop_begin = 0
                cx_loop_length = 0
                cx_loop_count = 0
                cx_encoder_version = 4
                cx_block_count = 1
                extra_header = _XMA_WAVEFORMAT.pack(
                    cx_num_streams, cx_channel_mask, cx_samples_encoded,
                    cx_bytes_per_block, cx_play_begin, cx_play_length,
                    cx_loop_begin, cx_loop_length, cx_loop_count,
                    cx_encoder_version, cx_block_count)
                if entry_seektables:
                    entry_seek = entry_seektables[i]
                else:
                    raise ReaderError("No SEEKTABLES found for XMA2 format")
            else:
                raise ReaderError(
                    "Unhandled entry format: {}".format(c_format_tag))
            cx_size = len(extra_header)
            entry_header = _WAVEFORMATEX.pack(c_format_tag, c_channels,
                                              c_samples_per_sec,
                                              c_avg_bytes_per_sec,
                                              c_block_align, c_bits_per_sample,
                                              cx_size)
            entry_header += extra_header
            # read entry wave data
            stream.seek(regions['ENTRYWAVEDATA'].offset + cur_meta.play_offset)
            # manually swap PCM data if needed
            entry_data = stream.read(cur_meta.play_length)
            if big_endian and c_format_tag == WAVE_FORMAT_PCM and c_bits_per_sample == 16:
                entry_data = bytearray(entry_data)
                entry_data[1::2], entry_data[0::2] = entry_data[
                    0::2], entry_data[1::2]
            self.entries.append(
                Entry(entry_name, entry_header, entry_data, entry_dpds,
                      entry_seek))
예제 #23
0
 def read(self):
     raise ReaderError("ObjectReader should never be invoked directly")
예제 #24
0
파일: xsb.py 프로젝트: ZandrXandr/Fezzer-2
    def __init__(self, data=None, filename=None, audio_engine=None):
        self.audio_engine = audio_engine

        # open in little endian initially
        stream = BinaryStream(data=data, filename=filename)
        del data

        # check sig to find actual endianess
        h_sig = stream.peek(len(SB_L_SIGNATURE))
        if h_sig == SB_L_SIGNATURE:
            big_endian = False
        elif h_sig == SB_B_SIGNATURE:
            big_endian = True
        else:
            raise ValueError("bad sig: {!r}".format(h_sig))

        # switch stream to correct endianess
        stream.set_endian(big_endian)
        (h_sig, self.version, self.header_version, self.crc, buildtime_raw_low,
         buildtime_raw_high, self.platform, h_simple_cue_count,
         h_complex_cue_count, h_unknown_count, h_cue_name_hash_count,
         h_wave_bank_count, h_sound_count, h_cue_names_length,
         simple_cue_offset_raw, complex_cue_offset_raw, cue_name_offset_raw,
         unknown_offset_raw, variation_offset_raw, transition_offset_raw,
         wave_bank_offset_raw, cue_name_hash_offset_raw,
         cue_name_table_offset_raw, sound_offset_raw,
         h_name_raw) = stream.unpack(_SB_HEADER)
        h_simple_cue_offset = fix_offset(simple_cue_offset_raw)
        h_complex_cue_offset = fix_offset(complex_cue_offset_raw)
        h_cue_name_offset = fix_offset(cue_name_offset_raw)
        h_unknown_offset = fix_offset(unknown_offset_raw)
        h_variation_offset = fix_offset(variation_offset_raw)
        h_transition_offset = fix_offset(transition_offset_raw)
        h_wave_bank_offset = fix_offset(wave_bank_offset_raw)
        h_cue_name_hash_offset = fix_offset(cue_name_hash_offset_raw)
        h_cue_name_table_offset = fix_offset(cue_name_table_offset_raw)
        h_sound_offset = fix_offset(sound_offset_raw)
        self.name = h_name_raw.rstrip(b'\x00').decode('iso8859-1')
        del h_name_raw
        self.buildtime = filetime_to_datetime(buildtime_raw_low,
                                              buildtime_raw_high)

        self.wave_banks = []
        if h_wave_bank_count and h_wave_bank_offset:
            stream.seek(h_wave_bank_offset)
            self.wave_banks = [
                stream.read(64).rstrip(b'\x00').decode('iso8859-1')
                for _ in range(h_wave_bank_count)
            ]
        else:
            raise ReaderError("No wave banks found in sound bank")

        cue_name_hash = []
        if h_cue_name_hash_count and h_cue_name_hash_offset:
            stream.seek(h_cue_name_hash_offset)
            cue_name_hash = [
                stream.read_int16() for _ in range(h_cue_name_hash_count)
            ]
        cue_name_hash_entry = []
        if h_cue_names_length and h_cue_name_table_offset:
            stream.seek(h_cue_name_table_offset)
            cue_name_hash_entry = [
                (stream.read_int32(), stream.read_int16())
                for _ in range(h_simple_cue_count + h_complex_cue_count)
            ]
        cue_names = []
        for (name_offset, _) in cue_name_hash_entry:
            stream.seek(name_offset)
            cue_names.append(stream.read_cstring())

        self.cues = []
        self.cues_name = OrderedDict()
        if h_simple_cue_count and h_simple_cue_offset:
            stream.seek(h_simple_cue_offset)
            for i in range(h_simple_cue_count):
                cue_name = None
                if cue_names:
                    cue_name = cue_names[i]
                cue = Cue(cue_name, stream)
                self.cues.append(cue)
                if cue_name:
                    self.cues_name[cue_name] = cue
        if h_complex_cue_count and h_complex_cue_offset:
            stream.seek(h_complex_cue_offset)
            for i in range(h_complex_cue_count):
                cue_name = None
                if cue_names:
                    cue_name = cue_names[h_simple_cue_count + i]
                cue = Cue(cue_name, stream, is_complex=True)
                self.cues.append(cue)
                if cue_name:
                    self.cues_name[cue_name] = cue
예제 #25
0
 def read(self):
     raise ReaderError('ObjectReader invoked for {}'.format(
         self.target_type))
예제 #26
0
 def init_reader(self, file_platform=None, file_version=None):
     GenericValueTypeReader.init_reader(self, file_platform, file_version)
     if not self.readers[0].is_enum_type:
         ReaderError("Not enum type reader: '{}'".format(self.readers[0]))
예제 #27
0
 def read(self):
     raise ReaderError('ModifierReader invoked for {}'.format(
         self.target_type))