1 ////////////////////////////////////////////////////////////////////////////
2 // **** WAVPACK **** //
3 // Hybrid Lossless Wavefile Compressor //
4 // Copyright (c) 1998 - 2013 Conifer Software. //
5 // All Rights Reserved. //
6 // Distributed under the BSD Software License (see license.txt) //
7 ////////////////////////////////////////////////////////////////////////////
8
9 // unpack3_open.c
10
11 // This module provides an extension to the open_utils.c module for handling
12 // WavPack files prior to version 4.0, not including "raw" files. As these
13 // modes are all obsolete and are no longer written, this code will not be
14 // fully documented other than the global functions. However, full documentation
15 // is provided in the version 3.97 source code. Note that this module only
16 // provides the functionality of opening the files and obtaining information
17 // from them; the actual audio decoding is located in the unpack3.c module.
18
19 #ifdef ENABLE_LEGACY
20
21 #include <stdlib.h>
22 #include <string.h>
23
24 #include "wavpack_local.h"
25 #include "unpack3.h"
26
27 #define ATTEMPT_ERROR_MUTING
28
29 // This provides an extension to the WavpackOpenFileRead () function contained
30 // in the wputils.c module. It is assumed that an 'R' had been read as the
31 // first character of the file/stream (indicating a non-raw pre version 4.0
32 // WavPack file) and had been pushed back onto the stream (or simply seeked
33 // back to).
34
open_file3(WavpackContext * wpc,char * error)35 WavpackContext *open_file3 (WavpackContext *wpc, char *error)
36 {
37 RiffChunkHeader RiffChunkHeader;
38 ChunkHeader ChunkHeader;
39 WavpackHeader3 wphdr;
40 WavpackStream3 *wps;
41 WaveHeader3 wavhdr;
42
43 CLEAR (wavhdr);
44 wpc->stream3 = wps = (WavpackStream3 *) malloc (sizeof (WavpackStream3));
45 CLEAR (*wps);
46
47 if (wpc->reader->read_bytes (wpc->wv_in, &RiffChunkHeader, sizeof (RiffChunkHeader)) !=
48 sizeof (RiffChunkHeader)) {
49 if (error) strcpy (error, "not a valid WavPack file!");
50 return WavpackCloseFile (wpc);
51 }
52
53 if (!strncmp (RiffChunkHeader.ckID, "RIFF", 4) && !strncmp (RiffChunkHeader.formType, "WAVE", 4)) {
54
55 if (wpc->open_flags & OPEN_WRAPPER) {
56 wpc->wrapper_data = (unsigned char *)malloc (wpc->wrapper_bytes = sizeof (RiffChunkHeader));
57 memcpy (wpc->wrapper_data, &RiffChunkHeader, sizeof (RiffChunkHeader));
58 }
59
60 // If the first chunk is a wave RIFF header, then read the various chunks
61 // until we get to the "data" chunk (and WavPack header should follow). If
62 // the first chunk is not a RIFF, then we assume a "raw" WavPack file and
63 // the WavPack header must be first.
64
65 while (1) {
66
67 if (wpc->reader->read_bytes (wpc->wv_in, &ChunkHeader, sizeof (ChunkHeader)) !=
68 sizeof (ChunkHeader)) {
69 if (error) strcpy (error, "not a valid WavPack file!");
70 return WavpackCloseFile (wpc);
71 }
72 else {
73 if (wpc->open_flags & OPEN_WRAPPER) {
74 wpc->wrapper_data = (unsigned char *)realloc (wpc->wrapper_data, wpc->wrapper_bytes + sizeof (ChunkHeader));
75 memcpy (wpc->wrapper_data + wpc->wrapper_bytes, &ChunkHeader, sizeof (ChunkHeader));
76 wpc->wrapper_bytes += sizeof (ChunkHeader);
77 }
78
79 WavpackLittleEndianToNative (&ChunkHeader, ChunkHeaderFormat);
80
81 if (!strncmp (ChunkHeader.ckID, "fmt ", 4)) {
82
83 if (ChunkHeader.ckSize < sizeof (wavhdr) ||
84 wpc->reader->read_bytes (wpc->wv_in, &wavhdr, sizeof (wavhdr)) != sizeof (wavhdr)) {
85 if (error) strcpy (error, "not a valid WavPack file!");
86 return WavpackCloseFile (wpc);
87 }
88 else if (wpc->open_flags & OPEN_WRAPPER) {
89 wpc->wrapper_data = (unsigned char *)realloc (wpc->wrapper_data, wpc->wrapper_bytes + sizeof (wavhdr));
90 memcpy (wpc->wrapper_data + wpc->wrapper_bytes, &wavhdr, sizeof (wavhdr));
91 wpc->wrapper_bytes += sizeof (wavhdr);
92 }
93
94 WavpackLittleEndianToNative (&wavhdr, WaveHeader3Format);
95
96 if (ChunkHeader.ckSize > sizeof (wavhdr)) {
97 uint32_t bytes_to_skip = (ChunkHeader.ckSize + 1 - sizeof (wavhdr)) & ~1L;
98
99 if (bytes_to_skip > 1024 * 1024) {
100 if (error) strcpy (error, "not a valid WavPack file!");
101 return WavpackCloseFile (wpc);
102 }
103
104 if (wpc->open_flags & OPEN_WRAPPER) {
105 wpc->wrapper_data = (unsigned char *)realloc (wpc->wrapper_data, wpc->wrapper_bytes + bytes_to_skip);
106 wpc->reader->read_bytes (wpc->wv_in, wpc->wrapper_data + wpc->wrapper_bytes, bytes_to_skip);
107 wpc->wrapper_bytes += bytes_to_skip;
108 }
109 else {
110 unsigned char *temp = (unsigned char *)malloc (bytes_to_skip);
111 wpc->reader->read_bytes (wpc->wv_in, temp, bytes_to_skip);
112 free (temp);
113 }
114 }
115 }
116 else if (!strncmp (ChunkHeader.ckID, "data", 4))
117 break;
118 else if ((ChunkHeader.ckSize + 1) & ~1L) {
119 uint32_t bytes_to_skip = (ChunkHeader.ckSize + 1) & ~1L;
120
121 if (bytes_to_skip > 1024 * 1024) {
122 if (error) strcpy (error, "not a valid WavPack file!");
123 return WavpackCloseFile (wpc);
124 }
125
126 if (wpc->open_flags & OPEN_WRAPPER) {
127 wpc->wrapper_data = (unsigned char *)realloc (wpc->wrapper_data, wpc->wrapper_bytes + bytes_to_skip);
128 wpc->reader->read_bytes (wpc->wv_in, wpc->wrapper_data + wpc->wrapper_bytes, bytes_to_skip);
129 wpc->wrapper_bytes += bytes_to_skip;
130 }
131 else {
132 unsigned char *temp = (unsigned char *)malloc (bytes_to_skip);
133 wpc->reader->read_bytes (wpc->wv_in, temp, bytes_to_skip);
134 free (temp);
135 }
136 }
137 }
138 }
139 }
140 else {
141 if (error) strcpy (error, "not a valid WavPack file!");
142 return WavpackCloseFile (wpc);
143 }
144
145 if (wavhdr.FormatTag != 1 || !wavhdr.NumChannels || wavhdr.NumChannels > 2 ||
146 !wavhdr.SampleRate || wavhdr.BitsPerSample < 16 || wavhdr.BitsPerSample > 24 ||
147 wavhdr.BlockAlign / wavhdr.NumChannels > 3 || wavhdr.BlockAlign % wavhdr.NumChannels ||
148 wavhdr.BlockAlign / wavhdr.NumChannels < (wavhdr.BitsPerSample + 7) / 8) {
149 if (error) strcpy (error, "not a valid WavPack file!");
150 return WavpackCloseFile (wpc);
151 }
152
153 wpc->total_samples = ChunkHeader.ckSize / wavhdr.NumChannels /
154 ((wavhdr.BitsPerSample > 16) ? 3 : 2);
155
156 if (wpc->reader->read_bytes (wpc->wv_in, &wphdr, 10) != 10) {
157 if (error) strcpy (error, "not a valid WavPack file!");
158 return WavpackCloseFile (wpc);
159 }
160
161 if (((char *) &wphdr) [8] == 2 && (wpc->reader->read_bytes (wpc->wv_in, ((char *) &wphdr) + 10, 2) != 2)) {
162 if (error) strcpy (error, "not a valid WavPack file!");
163 return WavpackCloseFile (wpc);
164 }
165 else if (((char *) &wphdr) [8] == 3 && (wpc->reader->read_bytes (wpc->wv_in, ((char *) &wphdr) + 10,
166 sizeof (wphdr) - 10) != sizeof (wphdr) - 10)) {
167 if (error) strcpy (error, "not a valid WavPack file!");
168 return WavpackCloseFile (wpc);
169 }
170
171 WavpackLittleEndianToNative (&wphdr, WavpackHeader3Format);
172
173 // make sure this is a version we know about
174
175 if (strncmp (wphdr.ckID, "wvpk", 4) || wphdr.version < 1 || wphdr.version > 3) {
176 if (error) strcpy (error, "not a valid WavPack file!");
177 return WavpackCloseFile (wpc);
178 }
179
180 // Because I ran out of flag bits in the WavPack header, an amazingly ugly
181 // kludge was forced upon me! This code takes care of preparing the flags
182 // field for internal use and checking for unknown formats we can't decode
183
184 if (wphdr.version == 3) {
185
186 if (wphdr.flags & EXTREME_DECORR) {
187
188 if ((wphdr.flags & NOT_STORED_FLAGS) ||
189 ((wphdr.bits) &&
190 (((wphdr.flags & NEW_HIGH_FLAG) &&
191 (wphdr.flags & (FAST_FLAG | HIGH_FLAG))) ||
192 (wphdr.flags & CROSS_DECORR)))) {
193 if (error) strcpy (error, "not a valid WavPack file!");
194 return WavpackCloseFile (wpc);
195 }
196
197 if (wphdr.flags & CANCEL_EXTREME)
198 wphdr.flags &= ~(EXTREME_DECORR | CANCEL_EXTREME);
199 }
200 else
201 wphdr.flags &= ~CROSS_DECORR;
202 }
203
204 // check to see if we should look for a "correction" file, and if so try
205 // to open it for reading, then set WVC_FLAG accordingly
206
207 if (wpc->wvc_in && wphdr.version == 3 && wphdr.bits && (wphdr.flags & NEW_HIGH_FLAG)) {
208 wpc->file2len = wpc->reader->get_length (wpc->wvc_in);
209 wphdr.flags |= WVC_FLAG;
210 wpc->wvc_flag = TRUE;
211 }
212 else
213 wphdr.flags &= ~WVC_FLAG;
214
215 // check WavPack version to handle special requirements of versions
216 // before 3.0 that had smaller headers
217
218 if (wphdr.version < 3) {
219 wphdr.total_samples = (int32_t) wpc->total_samples;
220 wphdr.flags = wavhdr.NumChannels == 1 ? MONO_FLAG : 0;
221 wphdr.shift = 16 - wavhdr.BitsPerSample;
222
223 if (wphdr.version == 1)
224 wphdr.bits = 0;
225 }
226
227 wpc->config.sample_rate = wavhdr.SampleRate;
228 wpc->config.num_channels = wavhdr.NumChannels;
229 wpc->config.channel_mask = 5 - wavhdr.NumChannels;
230
231 if (wphdr.flags & MONO_FLAG)
232 wpc->config.flags |= CONFIG_MONO_FLAG;
233
234 if (wphdr.flags & EXTREME_DECORR)
235 wpc->config.flags |= CONFIG_HIGH_FLAG;
236
237 if (wphdr.bits) {
238 if (wphdr.flags & NEW_HIGH_FLAG)
239 wpc->config.flags |= CONFIG_HYBRID_FLAG;
240 else
241 wpc->config.flags |= CONFIG_LOSSY_MODE;
242 }
243 else if (!(wphdr.flags & HIGH_FLAG))
244 wpc->config.flags |= CONFIG_FAST_FLAG;
245
246 wpc->config.bytes_per_sample = (wphdr.flags & BYTES_3) ? 3 : 2;
247 wpc->config.bits_per_sample = wavhdr.BitsPerSample;
248
249 memcpy (&wps->wphdr, &wphdr, sizeof (wphdr));
250 wps->wvbits.bufsiz = wps->wvcbits.bufsiz = 1024 * 1024;
251 return wpc;
252 }
253
254 // return currently decoded sample index
255
get_sample_index3(WavpackContext * wpc)256 uint32_t get_sample_index3 (WavpackContext *wpc)
257 {
258 WavpackStream3 *wps = (WavpackStream3 *) wpc->stream3;
259
260 return (wps) ? wps->sample_index : (uint32_t) -1;
261 }
262
get_version3(WavpackContext * wpc)263 int get_version3 (WavpackContext *wpc)
264 {
265 WavpackStream3 *wps = (WavpackStream3 *) wpc->stream3;
266
267 return (wps) ? wps->wphdr.version : 0;
268 }
269
free_stream3(WavpackContext * wpc)270 void free_stream3 (WavpackContext *wpc)
271 {
272 WavpackStream3 *wps = (WavpackStream3 *) wpc->stream3;
273
274 if (wps) {
275 #ifndef NO_SEEKING
276 if (wps->unpack_data)
277 free (wps->unpack_data);
278 #endif
279 if ((wps->wphdr.flags & WVC_FLAG) && wps->wvcbits.buf)
280 free (wps->wvcbits.buf);
281
282 if (wps->wvbits.buf)
283 free (wps->wvbits.buf);
284
285 free (wps);
286 }
287 }
288
289 #endif // ENABLE_LEGACY
290