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