| 101 | |
| 102 | |
| 103 | class _Chunk: |
| 104 | def __init__(self, file, align=True, bigendian=True, inclheader=False): |
| 105 | self.closed = False |
| 106 | self.align = align # whether to align to word (2-byte) boundaries |
| 107 | if bigendian: |
| 108 | strflag = '>' |
| 109 | else: |
| 110 | strflag = '<' |
| 111 | self.file = file |
| 112 | self.chunkname = file.read(4) |
| 113 | if len(self.chunkname) < 4: |
| 114 | raise EOFError |
| 115 | try: |
| 116 | self.chunksize = struct.unpack_from(strflag+'L', file.read(4))[0] |
| 117 | except struct.error: |
| 118 | raise EOFError from None |
| 119 | if inclheader: |
| 120 | self.chunksize = self.chunksize - 8 # subtract header |
| 121 | self.size_read = 0 |
| 122 | try: |
| 123 | self.offset = self.file.tell() |
| 124 | except (AttributeError, OSError): |
| 125 | self.seekable = False |
| 126 | else: |
| 127 | self.seekable = True |
| 128 | |
| 129 | def getname(self): |
| 130 | """Return the name (ID) of the current chunk.""" |
| 131 | return self.chunkname |
| 132 | |
| 133 | def close(self): |
| 134 | if not self.closed: |
| 135 | try: |
| 136 | self.skip() |
| 137 | finally: |
| 138 | self.closed = True |
| 139 | |
| 140 | def seek(self, pos, whence=0): |
| 141 | """Seek to specified position into the chunk. |
| 142 | Default position is 0 (start of chunk). |
| 143 | If the file is not seekable, this will result in an error. |
| 144 | """ |
| 145 | |
| 146 | if self.closed: |
| 147 | raise ValueError("I/O operation on closed file") |
| 148 | if not self.seekable: |
| 149 | raise OSError("cannot seek") |
| 150 | if whence == 1: |
| 151 | pos = pos + self.size_read |
| 152 | elif whence == 2: |
| 153 | pos = pos + self.chunksize |
| 154 | if pos < 0 or pos > self.chunksize: |
| 155 | raise RuntimeError |
| 156 | self.file.seek(self.offset + pos, 0) |
| 157 | self.size_read = pos |
| 158 | |
| 159 | def tell(self): |
| 160 | if self.closed: |