diff options
author | Guido van Rossum <guido@python.org> | 1999-06-09 13:32:28 (GMT) |
---|---|---|
committer | Guido van Rossum <guido@python.org> | 1999-06-09 13:32:28 (GMT) |
commit | 8ea7bb8e78e2b502c7ca237411aa79ac24347eca (patch) | |
tree | c5794ab155ca8973bfe1ea212e457efbf0da0b93 /Lib/chunk.py | |
parent | 1f2e09bc45faa25c95f4e4ea1b24201af916179c (diff) | |
download | cpython-8ea7bb8e78e2b502c7ca237411aa79ac24347eca.zip cpython-8ea7bb8e78e2b502c7ca237411aa79ac24347eca.tar.gz cpython-8ea7bb8e78e2b502c7ca237411aa79ac24347eca.tar.bz2 |
Patch/new code by Sjoerd Mullender:
Separate the Chunk class out of the aifc module into a new "chunk" module.
Diffstat (limited to 'Lib/chunk.py')
-rw-r--r-- | Lib/chunk.py | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/Lib/chunk.py b/Lib/chunk.py new file mode 100644 index 0000000..0a9abd2 --- /dev/null +++ b/Lib/chunk.py @@ -0,0 +1,142 @@ +"""Simple class to read IFF chunks. + +An IFF chunk (used in formats such as AIFF, TIFF, RMFF (RealMedia File +Format)) has the following structure: + ++----------------+ +| ID (4 bytes) | ++----------------+ +| size (4 bytes) | ++----------------+ +| data | +| ... | ++----------------+ + +The ID is a 4-byte string which identifies the type of chunk. + +The size field (a 32-bit value, encoded using big-endian byte order) +gives the size of the whole chunk, including the 8-byte header. + +Usually a IFF-type file consists of one or more chunks. The proposed +usage of the Chunk class defined here is to instantiate an instance at +the start of each chunk and read from the instance until it reaches +the end, after which a new instance can be instantiated. At the end +of the file, creating a new instance will fail with a EOFError +exception. + +Usage: +while 1: + try: + chunk = Chunk(file) + except EOFError: + break + chunktype = chunk.getname() + while 1: + data = chunk.read(nbytes) + if not data: + pass + # do something with data + +The interface is file-like. The implemented methods are: +read, close, seek, tell, isatty. +Extra methods are: skip() (called by close, skips to the end of the chunk), +getname() (returns the name (ID) of the chunk) + +The __init__ method has one required argument, a file-like object +(including a chunk instance), and one optional argument, a flag which +specifies whether or not chunks are aligned on 2-byte boundaries. The +default is 1, i.e. aligned. +""" + +class Chunk: + def __init__(self, file, align = 1): + import struct + self.closed = 0 + self.align = align # whether to align to word (2-byte) boundaries + 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] + except struct.error: + raise EOFError + self.size_read = 0 + self.offset = self.file.tell() + + def getname(self): + """Return the name (ID) of the current chunk.""" + return self.chunkname + + def close(self): + if not self.closed: + self.skip() + self.closed = 1 + + def isatty(self): + if self.closed: + raise ValueError, "I/O operation on closed file" + return 0 + + def seek(self, pos, mode = 0): + """Seek to specified position into the chunk. + Default position is 0 (start of chunk). + If the file is not seekable, this will result in an error. + """ + + if self.closed: + raise ValueError, "I/O operation on closed file" + if mode == 1: + pos = pos + self.size_read + elif mode == 2: + pos = pos + self.chunk_size + if pos < 0 or pos > self.chunksize: + raise RuntimeError + self.file.seek(self.offset + pos, 0) + self.size_read = pos + + def tell(self): + if self.closed: + raise ValueError, "I/O operation on closed file" + return self.size_read + + def read(self, n = -1): + """Read at most n bytes from the chunk. + If n is omitted or negative, read until the end + of the chunk. + """ + + if self.closed: + raise ValueError, "I/O operation on closed file" + if self.size_read >= self.chunksize: + return '' + if n < 0: + n = self.chunksize - self.size_read + if n > self.chunksize - self.size_read: + n = self.chunksize - self.size_read + data = self.file.read(n) + self.size_read = self.size_read + len(data) + if self.size_read == self.chunksize and \ + self.align and \ + (self.chunksize & 1): + dummy = self.file.read(1) + self.size_read = self.size_read + len(dummy) + return data + + def skip(self): + """Skip the rest of the chunk. + If you are not interested in the contents of the chunk, + this method should be called so that the file points to + the start of the next chunk. + """ + + if self.closed: + raise ValueError, "I/O operation on closed file" + 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 + |