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_seek.c
10
11 // This module provides seeking support for WavPack files prior to version 4.0.
12
13 #ifdef ENABLE_LEGACY
14 #ifndef NO_SEEKING
15
16 #include <stdlib.h>
17 #include <string.h>
18
19 #include "wavpack_local.h"
20 #include "unpack3.h"
21
22 static void *unpack_restore (WavpackStream3 *wps, void *source, int keep_resources);
23 static void bs_restore3 (Bitstream3 *bs);
24
25 // This is an extension for WavpackSeekSample (). Note that because WavPack
26 // files created prior to version 4.0 are not inherently seekable, this
27 // function could take a long time if a forward seek is requested to an
28 // area that has not been played (or seeked through) yet.
29
seek_sample3(WavpackContext * wpc,uint32_t desired_index)30 int seek_sample3 (WavpackContext *wpc, uint32_t desired_index)
31 {
32 int points_index = desired_index / (((uint32_t) wpc->total_samples >> 8) + 1);
33 WavpackStream3 *wps = (WavpackStream3 *) wpc->stream3;
34
35 if (desired_index >= wpc->total_samples)
36 return FALSE;
37
38 while (points_index)
39 if (wps->index_points [points_index].saved &&
40 wps->index_points [points_index].sample_index <= desired_index)
41 break;
42 else
43 points_index--;
44
45 if (wps->index_points [points_index].saved)
46 if (wps->index_points [points_index].sample_index > wps->sample_index ||
47 wps->sample_index > desired_index) {
48 wps->sample_index = wps->index_points [points_index].sample_index;
49 unpack_restore (wps, wps->unpack_data + points_index * wps->unpack_size, TRUE);
50 }
51
52 if (desired_index > wps->sample_index) {
53 int32_t *buffer = (int32_t *) malloc (1024 * (wps->wphdr.flags & MONO_FLAG ? 4 : 8));
54 uint32_t samples_to_skip = desired_index - wps->sample_index;
55
56 while (1) {
57 if (samples_to_skip > 1024) {
58 if (unpack_samples3 (wpc, buffer, 1024) == 1024)
59 samples_to_skip -= 1024;
60 else
61 break;
62 }
63 else {
64 samples_to_skip -= unpack_samples3 (wpc, buffer, samples_to_skip);
65 break;
66 }
67 }
68
69 free (buffer);
70
71 if (samples_to_skip)
72 return FALSE;
73 }
74
75 return TRUE;
76 }
77
78 // This function restores the unpacking context from the specified pointer
79 // and returns the updated pointer. After this call, unpack_samples() will
80 // continue where it left off immediately before unpack_save() was called.
81 // If the WavPack files and bitstreams might have been closed and reopened,
82 // then the "keep_resources" flag should be set to avoid using the "old"
83 // resources that were originally saved (and are probably now invalid).
84
unpack_restore(WavpackStream3 * wps,void * source,int keep_resources)85 static void *unpack_restore (WavpackStream3 *wps, void *source, int keep_resources)
86 {
87 int flags = wps->wphdr.flags, tcount;
88 struct decorr_pass *dpp;
89 FILE *temp_file;
90 unsigned char *temp_buf;
91
92 unpack_init3 (wps);
93 temp_file = wps->wvbits.id;
94 temp_buf = wps->wvbits.buf;
95 RESTORE (wps->wvbits, source);
96
97 if (keep_resources) {
98 wps->wvbits.id = temp_file;
99 wps->wvbits.ptr += temp_buf - wps->wvbits.buf;
100 wps->wvbits.end += temp_buf - wps->wvbits.buf;
101 wps->wvbits.buf = temp_buf;
102 }
103
104 bs_restore3 (&wps->wvbits);
105
106 if (flags & WVC_FLAG) {
107 temp_file = wps->wvcbits.id;
108 temp_buf = wps->wvcbits.buf;
109 RESTORE (wps->wvcbits, source);
110
111 if (keep_resources) {
112 wps->wvcbits.id = temp_file;
113 wps->wvcbits.ptr += temp_buf - wps->wvcbits.buf;
114 wps->wvcbits.end += temp_buf - wps->wvcbits.buf;
115 wps->wvcbits.buf = temp_buf;
116 }
117
118 bs_restore3 (&wps->wvcbits);
119 }
120
121 if (wps->wphdr.version == 3) {
122 if (wps->wphdr.bits) {
123 RESTORE (wps->w4, source);
124 }
125 else {
126 RESTORE (wps->w1, source);
127 }
128
129 RESTORE (wps->w3, source);
130 RESTORE (wps->dc.crc, source);
131 }
132 else
133 RESTORE (wps->w2, source);
134
135 if (wps->wphdr.bits) {
136 RESTORE (wps->dc.error, source);
137 }
138 else {
139 RESTORE (wps->dc.sum_level, source);
140 RESTORE (wps->dc.left_level, source);
141 RESTORE (wps->dc.right_level, source);
142 RESTORE (wps->dc.diff_level, source);
143 }
144
145 if (flags & OVER_20) {
146 RESTORE (wps->dc.last_extra_bits, source);
147 RESTORE (wps->dc.extra_bits_count, source);
148 }
149
150 if (!(flags & EXTREME_DECORR)) {
151 RESTORE (wps->dc.sample, source);
152 RESTORE (wps->dc.weight, source);
153 }
154
155 if (flags & (HIGH_FLAG | NEW_HIGH_FLAG))
156 for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) {
157 if (dpp->term > 0) {
158 int count = dpp->term;
159 int index = wps->dc.m;
160
161 RESTORE (dpp->weight_A, source);
162
163 while (count--) {
164 RESTORE (dpp->samples_A [index], source);
165 index = (index + 1) & (MAX_TERM - 1);
166 }
167
168 if (!(flags & MONO_FLAG)) {
169 count = dpp->term;
170 index = wps->dc.m;
171
172 RESTORE (dpp->weight_B, source);
173
174 while (count--) {
175 RESTORE (dpp->samples_B [index], source);
176 index = (index + 1) & (MAX_TERM - 1);
177 }
178 }
179 }
180 else {
181 RESTORE (dpp->weight_A, source);
182 RESTORE (dpp->weight_B, source);
183 RESTORE (dpp->samples_A [0], source);
184 RESTORE (dpp->samples_B [0], source);
185 }
186 }
187
188 return source;
189 }
190
191 // This function is called after a call to unpack_restore() has restored
192 // the BitStream structure to a previous state and causes any required data
193 // to be read from the file. This function is NOT supported for overlapped
194 // operation.
195
bs_restore3(Bitstream3 * bs)196 static void bs_restore3 (Bitstream3 *bs)
197 {
198 uint32_t bytes_to_read = (uint32_t)(bs->end - bs->ptr - 1), bytes_read;
199
200 bs->reader->set_pos_abs (bs->id, bs->fpos - bytes_to_read);
201
202 if (bytes_to_read > 0) {
203
204 bytes_read = bs->reader->read_bytes (bs->id, bs->ptr + 1, bytes_to_read);
205
206 if (bytes_to_read != bytes_read)
207 bs->end = bs->ptr + 1 + bytes_read;
208 }
209 }
210
211 #endif // NO_SEEKING
212 #endif // ENABLE_LEGACY
213