Vega strike Python Modules doc  0.5.1
Documentation of the " Modules " folder of Vega strike
 All Data Structures Namespaces Files Functions Variables
chunk.py
Go to the documentation of this file.
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 1:
29  try:
30  chunk = Chunk(file)
31  except EOFError:
32  break
33  chunktype = chunk.getname()
34  while 1:
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 = 1, bigendian = 1, inclheader = 0):
53  import struct
54  self.closed = 0
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 = 0
75  else:
76  self.seekable = 1
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 = 1
90 
91  def isatty(self):
92  if self.closed:
93  raise ValueError, "I/O operation on closed file"
94  return 0
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