symbian-qemu-0.9.1-12/python-win32-2.6.1/lib/chunk.py
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 """Simple class to read IFF chunks.
       
     2 
       
     3 An IFF chunk (used in formats such as AIFF, TIFF, RMFF (RealMedia File
       
     4 Format)) has the following structure:
       
     5 
       
     6 +----------------+
       
     7 | ID (4 bytes)   |
       
     8 +----------------+
       
     9 | size (4 bytes) |
       
    10 +----------------+
       
    11 | data           |
       
    12 | ...            |
       
    13 +----------------+
       
    14 
       
    15 The ID is a 4-byte string which identifies the type of chunk.
       
    16 
       
    17 The size field (a 32-bit value, encoded using big-endian byte order)
       
    18 gives the size of the whole chunk, including the 8-byte header.
       
    19 
       
    20 Usually an IFF-type file consists of one or more chunks.  The proposed
       
    21 usage of the Chunk class defined here is to instantiate an instance at
       
    22 the start of each chunk and read from the instance until it reaches
       
    23 the end, after which a new instance can be instantiated.  At the end
       
    24 of the file, creating a new instance will fail with a EOFError
       
    25 exception.
       
    26 
       
    27 Usage:
       
    28 while True:
       
    29     try:
       
    30         chunk = Chunk(file)
       
    31     except EOFError:
       
    32         break
       
    33     chunktype = chunk.getname()
       
    34     while True:
       
    35         data = chunk.read(nbytes)
       
    36         if not data:
       
    37             pass
       
    38         # do something with data
       
    39 
       
    40 The interface is file-like.  The implemented methods are:
       
    41 read, close, seek, tell, isatty.
       
    42 Extra methods are: skip() (called by close, skips to the end of the chunk),
       
    43 getname() (returns the name (ID) of the chunk)
       
    44 
       
    45 The __init__ method has one required argument, a file-like object
       
    46 (including a chunk instance), and one optional argument, a flag which
       
    47 specifies whether or not chunks are aligned on 2-byte boundaries.  The
       
    48 default is 1, i.e. aligned.
       
    49 """
       
    50 
       
    51 class Chunk:
       
    52     def __init__(self, file, align=True, bigendian=True, inclheader=False):
       
    53         import struct
       
    54         self.closed = False
       
    55         self.align = align      # whether to align to word (2-byte) boundaries
       
    56         if bigendian:
       
    57             strflag = '>'
       
    58         else:
       
    59             strflag = '<'
       
    60         self.file = file
       
    61         self.chunkname = file.read(4)
       
    62         if len(self.chunkname) < 4:
       
    63             raise EOFError
       
    64         try:
       
    65             self.chunksize = struct.unpack(strflag+'L', file.read(4))[0]
       
    66         except struct.error:
       
    67             raise EOFError
       
    68         if inclheader:
       
    69             self.chunksize = self.chunksize - 8 # subtract header
       
    70         self.size_read = 0
       
    71         try:
       
    72             self.offset = self.file.tell()
       
    73         except (AttributeError, IOError):
       
    74             self.seekable = False
       
    75         else:
       
    76             self.seekable = True
       
    77 
       
    78     def getname(self):
       
    79         """Return the name (ID) of the current chunk."""
       
    80         return self.chunkname
       
    81 
       
    82     def getsize(self):
       
    83         """Return the size of the current chunk."""
       
    84         return self.chunksize
       
    85 
       
    86     def close(self):
       
    87         if not self.closed:
       
    88             self.skip()
       
    89             self.closed = True
       
    90 
       
    91     def isatty(self):
       
    92         if self.closed:
       
    93             raise ValueError, "I/O operation on closed file"
       
    94         return False
       
    95 
       
    96     def seek(self, pos, whence=0):
       
    97         """Seek to specified position into the chunk.
       
    98         Default position is 0 (start of chunk).
       
    99         If the file is not seekable, this will result in an error.
       
   100         """
       
   101 
       
   102         if self.closed:
       
   103             raise ValueError, "I/O operation on closed file"
       
   104         if not self.seekable:
       
   105             raise IOError, "cannot seek"
       
   106         if whence == 1:
       
   107             pos = pos + self.size_read
       
   108         elif whence == 2:
       
   109             pos = pos + self.chunksize
       
   110         if pos < 0 or pos > self.chunksize:
       
   111             raise RuntimeError
       
   112         self.file.seek(self.offset + pos, 0)
       
   113         self.size_read = pos
       
   114 
       
   115     def tell(self):
       
   116         if self.closed:
       
   117             raise ValueError, "I/O operation on closed file"
       
   118         return self.size_read
       
   119 
       
   120     def read(self, size=-1):
       
   121         """Read at most size bytes from the chunk.
       
   122         If size is omitted or negative, read until the end
       
   123         of the chunk.
       
   124         """
       
   125 
       
   126         if self.closed:
       
   127             raise ValueError, "I/O operation on closed file"
       
   128         if self.size_read >= self.chunksize:
       
   129             return ''
       
   130         if size < 0:
       
   131             size = self.chunksize - self.size_read
       
   132         if size > self.chunksize - self.size_read:
       
   133             size = self.chunksize - self.size_read
       
   134         data = self.file.read(size)
       
   135         self.size_read = self.size_read + len(data)
       
   136         if self.size_read == self.chunksize and \
       
   137            self.align and \
       
   138            (self.chunksize & 1):
       
   139             dummy = self.file.read(1)
       
   140             self.size_read = self.size_read + len(dummy)
       
   141         return data
       
   142 
       
   143     def skip(self):
       
   144         """Skip the rest of the chunk.
       
   145         If you are not interested in the contents of the chunk,
       
   146         this method should be called so that the file points to
       
   147         the start of the next chunk.
       
   148         """
       
   149 
       
   150         if self.closed:
       
   151             raise ValueError, "I/O operation on closed file"
       
   152         if self.seekable:
       
   153             try:
       
   154                 n = self.chunksize - self.size_read
       
   155                 # maybe fix alignment
       
   156                 if self.align and (self.chunksize & 1):
       
   157                     n = n + 1
       
   158                 self.file.seek(n, 1)
       
   159                 self.size_read = self.size_read + n
       
   160                 return
       
   161             except IOError:
       
   162                 pass
       
   163         while self.size_read < self.chunksize:
       
   164             n = min(8192, self.chunksize - self.size_read)
       
   165             dummy = self.read(n)
       
   166             if not dummy:
       
   167                 raise EOFError