//////////////////////////////////////////////////////////////////////////// // **** WAVPACK **** // // Hybrid Lossless Wavefile Compressor // // Copyright (c) 1998 - 2013 Conifer Software. // // All Rights Reserved. // // Distributed under the BSD Software License (see license.txt) // //////////////////////////////////////////////////////////////////////////// // unpack3_seek.c // This module provides seeking support for WavPack files prior to version 4.0. #ifdef ENABLE_LEGACY #ifndef NO_SEEKING #include #include #include "wavpack_local.h" #include "unpack3.h" static void *unpack_restore (WavpackStream3 *wps, void *source, int keep_resources); static void bs_restore3 (Bitstream3 *bs); // This is an extension for WavpackSeekSample (). Note that because WavPack // files created prior to version 4.0 are not inherently seekable, this // function could take a long time if a forward seek is requested to an // area that has not been played (or seeked through) yet. int seek_sample3 (WavpackContext *wpc, uint32_t desired_index) { int points_index = desired_index / (((uint32_t) wpc->total_samples >> 8) + 1); WavpackStream3 *wps = (WavpackStream3 *) wpc->stream3; if (desired_index >= wpc->total_samples) return FALSE; while (points_index) if (wps->index_points [points_index].saved && wps->index_points [points_index].sample_index <= desired_index) break; else points_index--; if (wps->index_points [points_index].saved) if (wps->index_points [points_index].sample_index > wps->sample_index || wps->sample_index > desired_index) { wps->sample_index = wps->index_points [points_index].sample_index; unpack_restore (wps, wps->unpack_data + points_index * wps->unpack_size, TRUE); } if (desired_index > wps->sample_index) { int32_t *buffer = (int32_t *) malloc (1024 * (wps->wphdr.flags & MONO_FLAG ? 4 : 8)); uint32_t samples_to_skip = desired_index - wps->sample_index; while (1) { if (samples_to_skip > 1024) { if (unpack_samples3 (wpc, buffer, 1024) == 1024) samples_to_skip -= 1024; else break; } else { samples_to_skip -= unpack_samples3 (wpc, buffer, samples_to_skip); break; } } free (buffer); if (samples_to_skip) return FALSE; } return TRUE; } // This function restores the unpacking context from the specified pointer // and returns the updated pointer. After this call, unpack_samples() will // continue where it left off immediately before unpack_save() was called. // If the WavPack files and bitstreams might have been closed and reopened, // then the "keep_resources" flag should be set to avoid using the "old" // resources that were originally saved (and are probably now invalid). static void *unpack_restore (WavpackStream3 *wps, void *source, int keep_resources) { int flags = wps->wphdr.flags, tcount; struct decorr_pass *dpp; FILE *temp_file; unsigned char *temp_buf; unpack_init3 (wps); temp_file = wps->wvbits.id; temp_buf = wps->wvbits.buf; RESTORE (wps->wvbits, source); if (keep_resources) { wps->wvbits.id = temp_file; wps->wvbits.ptr += temp_buf - wps->wvbits.buf; wps->wvbits.end += temp_buf - wps->wvbits.buf; wps->wvbits.buf = temp_buf; } bs_restore3 (&wps->wvbits); if (flags & WVC_FLAG) { temp_file = wps->wvcbits.id; temp_buf = wps->wvcbits.buf; RESTORE (wps->wvcbits, source); if (keep_resources) { wps->wvcbits.id = temp_file; wps->wvcbits.ptr += temp_buf - wps->wvcbits.buf; wps->wvcbits.end += temp_buf - wps->wvcbits.buf; wps->wvcbits.buf = temp_buf; } bs_restore3 (&wps->wvcbits); } if (wps->wphdr.version == 3) { if (wps->wphdr.bits) { RESTORE (wps->w4, source); } else { RESTORE (wps->w1, source); } RESTORE (wps->w3, source); RESTORE (wps->dc.crc, source); } else RESTORE (wps->w2, source); if (wps->wphdr.bits) { RESTORE (wps->dc.error, source); } else { RESTORE (wps->dc.sum_level, source); RESTORE (wps->dc.left_level, source); RESTORE (wps->dc.right_level, source); RESTORE (wps->dc.diff_level, source); } if (flags & OVER_20) { RESTORE (wps->dc.last_extra_bits, source); RESTORE (wps->dc.extra_bits_count, source); } if (!(flags & EXTREME_DECORR)) { RESTORE (wps->dc.sample, source); RESTORE (wps->dc.weight, source); } if (flags & (HIGH_FLAG | NEW_HIGH_FLAG)) for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) { if (dpp->term > 0) { int count = dpp->term; int index = wps->dc.m; RESTORE (dpp->weight_A, source); while (count--) { RESTORE (dpp->samples_A [index], source); index = (index + 1) & (MAX_TERM - 1); } if (!(flags & MONO_FLAG)) { count = dpp->term; index = wps->dc.m; RESTORE (dpp->weight_B, source); while (count--) { RESTORE (dpp->samples_B [index], source); index = (index + 1) & (MAX_TERM - 1); } } } else { RESTORE (dpp->weight_A, source); RESTORE (dpp->weight_B, source); RESTORE (dpp->samples_A [0], source); RESTORE (dpp->samples_B [0], source); } } return source; } // This function is called after a call to unpack_restore() has restored // the BitStream structure to a previous state and causes any required data // to be read from the file. This function is NOT supported for overlapped // operation. static void bs_restore3 (Bitstream3 *bs) { uint32_t bytes_to_read = (uint32_t)(bs->end - bs->ptr - 1), bytes_read; bs->reader->set_pos_abs (bs->id, bs->fpos - bytes_to_read); if (bytes_to_read > 0) { bytes_read = bs->reader->read_bytes (bs->id, bs->ptr + 1, bytes_to_read); if (bytes_to_read != bytes_read) bs->end = bs->ptr + 1 + bytes_read; } } #endif // NO_SEEKING #endif // ENABLE_LEGACY