71
71
is destroyed.
72
72
"""
73
73
74
- from chunk import Chunk
75
74
from collections import namedtuple
76
75
import builtins
77
76
import struct
@@ -100,6 +99,119 @@ def _byteswap(data, width):
100
99
return bytes (swapped_data )
101
100
102
101
102
+ class _Chunk :
103
+ def __init__ (self , file , align = True , bigendian = True , inclheader = False ):
104
+ import struct
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 :
161
+ raise ValueError ("I/O operation on closed file" )
162
+ return self .size_read
163
+
164
+ def read (self , size = - 1 ):
165
+ """Read at most size bytes from the chunk.
166
+ If size is omitted or negative, read until the end
167
+ of the chunk.
168
+ """
169
+
170
+ if self .closed :
171
+ raise ValueError ("I/O operation on closed file" )
172
+ if self .size_read >= self .chunksize :
173
+ return b''
174
+ if size < 0 :
175
+ size = self .chunksize - self .size_read
176
+ if size > self .chunksize - self .size_read :
177
+ size = self .chunksize - self .size_read
178
+ data = self .file .read (size )
179
+ self .size_read = self .size_read + len (data )
180
+ if self .size_read == self .chunksize and \
181
+ self .align and \
182
+ (self .chunksize & 1 ):
183
+ dummy = self .file .read (1 )
184
+ self .size_read = self .size_read + len (dummy )
185
+ return data
186
+
187
+ def skip (self ):
188
+ """Skip the rest of the chunk.
189
+ If you are not interested in the contents of the chunk,
190
+ this method should be called so that the file points to
191
+ the start of the next chunk.
192
+ """
193
+
194
+ if self .closed :
195
+ raise ValueError ("I/O operation on closed file" )
196
+ if self .seekable :
197
+ try :
198
+ n = self .chunksize - self .size_read
199
+ # maybe fix alignment
200
+ if self .align and (self .chunksize & 1 ):
201
+ n = n + 1
202
+ self .file .seek (n , 1 )
203
+ self .size_read = self .size_read + n
204
+ return
205
+ except OSError :
206
+ pass
207
+ while self .size_read < self .chunksize :
208
+ n = min (8192 , self .chunksize - self .size_read )
209
+ dummy = self .read (n )
210
+ if not dummy :
211
+ raise EOFError
212
+
213
+
214
+
103
215
class Wave_read :
104
216
"""Variables used in this class:
105
217
@@ -134,7 +246,7 @@ class Wave_read:
134
246
def initfp (self , file ):
135
247
self ._convert = None
136
248
self ._soundpos = 0
137
- self ._file = Chunk (file , bigendian = 0 )
249
+ self ._file = _Chunk (file , bigendian = 0 )
138
250
if self ._file .getname () != b'RIFF' :
139
251
raise Error ('file does not start with RIFF id' )
140
252
if self ._file .read (4 ) != b'WAVE' :
@@ -144,7 +256,7 @@ def initfp(self, file):
144
256
while 1 :
145
257
self ._data_seek_needed = 1
146
258
try :
147
- chunk = Chunk (self ._file , bigendian = 0 )
259
+ chunk = _Chunk (self ._file , bigendian = 0 )
148
260
except EOFError :
149
261
break
150
262
chunkname = chunk .getname ()
0 commit comments