diff --git a/Lib/aifc.py b/Lib/aifc.py index a4d9616c695..6c19dea98dc 100644 --- a/Lib/aifc.py +++ b/Lib/aifc.py @@ -293,8 +293,6 @@ def initfp(self, file): self._comm_chunk_read = 0 while 1: self._ssnd_seek_needed = 1 - #DEBUG: SGI's soundfiler has a bug. There should - # be no need to check for EOF here. try: chunk = Chunk(self._file) except EOFError: @@ -337,10 +335,6 @@ def __init__(self, f): # else, assume it is an open file object already self.initfp(f) - def __del__(self): - if self._file: - self.close() - # # User visible methods. # diff --git a/Lib/chunk.py b/Lib/chunk.py index 231a59caff0..fbbb1c122dc 100644 --- a/Lib/chunk.py +++ b/Lib/chunk.py @@ -49,19 +49,24 @@ """ class Chunk: - def __init__(self, file, align = 1): + def __init__(self, file, align = 1, bigendian = 1, inclheader = 0): import struct self.closed = 0 self.align = align # whether to align to word (2-byte) boundaries + if bigendian: + strflag = '>' + else: + strflag = '<' self.file = file self.chunkname = file.read(4) if len(self.chunkname) < 4: raise EOFError try: - self.chunksize = struct.unpack('>l', file.read(4))[0] + self.chunksize = struct.unpack(strflag+'l', file.read(4))[0] except struct.error: raise EOFError - self.chunksize = self.chunksize - 8 # subtract header + if inclheader: + self.chunksize = self.chunksize - 8 # subtract header self.size_read = 0 try: self.offset = self.file.tell() @@ -74,6 +79,10 @@ def getname(self): """Return the name (ID) of the current chunk.""" return self.chunkname + def getsize(self): + """Return the size of the current chunk.""" + return self.chunksize + def close(self): if not self.closed: self.skip() diff --git a/Lib/wave.py b/Lib/wave.py index 5344db2aeb9..aec9bdf81b0 100644 --- a/Lib/wave.py +++ b/Lib/wave.py @@ -85,87 +85,7 @@ else: big_endian = 0 -def _read_long(file): - x = 0L - for i in range(4): - byte = file.read(1) - if byte == '': - raise EOFError - x = x + (ord(byte) << (8 * i)) - if x >= 0x80000000L: - x = x - 0x100000000L - return int(x) - -def _read_ulong(file): - x = 0L - for i in range(4): - byte = file.read(1) - if byte == '': - raise EOFError - x = x + (ord(byte) << (8 * i)) - return x - -def _read_short(file): - x = 0 - for i in range(2): - byte = file.read(1) - if byte == '': - raise EOFError - x = x + (ord(byte) << (8 * i)) - if x >= 0x8000: - x = x - 0x10000 - return x - -def _write_short(f, x): - d, m = divmod(x, 256) - f.write(chr(m)) - f.write(chr(d)) - -def _write_long(f, x): - if x < 0: - x = x + 0x100000000L - for i in range(4): - d, m = divmod(x, 256) - f.write(chr(int(m))) - x = d - -class Chunk: - def __init__(self, file): - self.file = file - self.chunkname = self.file.read(4) - if len(self.chunkname) < 4: - raise EOFError - self.chunksize = _read_long(self.file) - self.size_read = 0 - self.offset = self.file.tell() - - def rewind(self): - self.file.seek(self.offset, 0) - self.size_read = 0 - - def setpos(self, pos): - if pos < 0 or pos > self.chunksize: - raise RuntimeError - self.file.seek(self.offset + pos, 0) - self.size_read = pos - - def read(self, length): - if self.size_read >= self.chunksize: - return '' - if length > self.chunksize - self.size_read: - length = self.chunksize - self.size_read - data = self.file.read(length) - self.size_read = self.size_read + len(data) - return data - - def skip(self): - try: - self.file.seek(self.chunksize - self.size_read, 1) - except RuntimeError: - while self.size_read < self.chunksize: - dummy = self.read(8192) - if not dummy: - raise EOFError +from chunk import Chunk class Wave_read: # Variables used in this class: @@ -197,41 +117,34 @@ class Wave_read: # _data_chunk -- instantiation of a chunk class for the DATA chunk # _framesize -- size of one frame in the file -## access _file, _nchannels, _nframes, _sampwidth, _framerate, \ -## _comptype, _compname, _soundpos, \ -## _fmt_chunk_read, _data_seek_needed, \ -## _data_chunk, _framesize: private - def initfp(self, file): - self._file = file self._convert = None self._soundpos = 0 - form = self._file.read(4) - if form != 'RIFF': + self._file = Chunk(file, bigendian = 0) + if self._file.getname() != 'RIFF': raise Error, 'file does not start with RIFF id' - formlength = _read_long(self._file) - if formlength <= 0: - raise Error, 'invalid FORM chunk data size' - formdata = self._file.read(4) - formlength = formlength - 4 - if formdata != 'WAVE': + if self._file.read(4) != 'WAVE': raise Error, 'not a WAVE file' self._fmt_chunk_read = 0 - while formlength > 0: + self._data_chunk = None + while 1: self._data_seek_needed = 1 - chunk = Chunk(self._file) - if chunk.chunkname == 'fmt ': + try: + chunk = Chunk(self._file, bigendian = 0) + except EOFError: + break + chunkname = chunk.getname() + if chunkname == 'fmt ': self._read_fmt_chunk(chunk) self._fmt_chunk_read = 1 - elif chunk.chunkname == 'data': + elif chunkname == 'data': if not self._fmt_chunk_read: raise Error, 'data chunk before fmt chunk' self._data_chunk = chunk self._nframes = chunk.chunksize / self._framesize self._data_seek_needed = 0 - formlength = formlength - 8 - chunk.chunksize - if formlength > 0: - chunk.skip() + break + chunk.skip() if not self._fmt_chunk_read or not self._data_chunk: raise Error, 'fmt chunk and/or data chunk missing' @@ -241,10 +154,6 @@ def __init__(self, f): # else, assume it is an open file object already self.initfp(f) - def __del__(self): - if self._file: - self.close() - # # User visible methods. # @@ -298,10 +207,10 @@ def setpos(self, pos): def readframes(self, nframes): if self._data_seek_needed: - self._data_chunk.rewind() + self._data_chunk.seek(0, 0) pos = self._soundpos * self._framesize if pos: - self._data_chunk.setpos(pos) + self._data_chunk.seek(pos, 0) self._data_seek_needed = 0 if nframes == 0: return '' @@ -310,12 +219,17 @@ def readframes(self, nframes): # something that only looks like a file object, so # we have to reach into the innards of the chunk object import array + chunk = self._data_chunk data = array.array(_array_fmts[self._sampwidth]) nitems = nframes * self._nchannels - if nitems * self._sampwidth > self._data_chunk.chunksize - self._data_chunk.size_read: - nitems = (self._data_chunk.chunksize - self._data_chunk.size_read) / self._sampwidth - data.fromfile(self._data_chunk.file, nitems) - self._data_chunk.size_read = self._data_chunk.size_read + nitems * self._sampwidth + if nitems * self._sampwidth > chunk.chunksize - chunk.size_read: + nitems = (chunk.chunksize - chunk.size_read) / self._sampwidth + data.fromfile(chunk.file.file, nitems) + # "tell" data chunk how much was read + chunk.size_read = chunk.size_read + nitems * self._sampwidth + # do the same for the outermost chunk + chunk = chunk.file + chunk.size_read = chunk.size_read + nitems * self._sampwidth data.byteswap() data = data.tostring() else: @@ -328,16 +242,12 @@ def readframes(self, nframes): # # Internal methods. # -## access *: private def _read_fmt_chunk(self, chunk): - wFormatTag = _read_short(chunk) - self._nchannels = _read_short(chunk) - self._framerate = _read_long(chunk) - dwAvgBytesPerSec = _read_long(chunk) - wBlockAlign = _read_short(chunk) + wFormatTag, self._nchannels, self._framerate, dwAvgBytesPerSec, wBlockAlign = struct.unpack('