//////////////////////////////////////////////////////////////////////////// // **** WAVPACK **** // // Hybrid Lossless Wavefile Compressor // // Copyright (c) 1998 - 2006 Conifer Software. // // All Rights Reserved. // // Distributed under the BSD Software License (see license.txt) // //////////////////////////////////////////////////////////////////////////// // bits.c // This module provides utilities to support the BitStream structure which is // used to read and write all WavPack audio data streams. It also contains a // wrapper for the stream I/O functions and a set of functions dealing with // endian-ness, both for enhancing portability. Finally, a debug wrapper for // the malloc() system is provided. #include "wavpack_local.h" #include #include #include #include #if defined(WIN32) #include #else #if defined(__OS2__) #include #endif #include #endif ////////////////////////// Bitstream functions //////////////////////////////// #if !defined(NO_UNPACK) || defined(INFO_ONLY) // Open the specified BitStream and associate with the specified buffer. static void bs_read (Bitstream *bs); void bs_open_read (Bitstream *bs, void *buffer_start, void *buffer_end) { bs->error = bs->sr = bs->bc = 0; bs->ptr = (bs->buf = buffer_start) - 1; bs->end = buffer_end; bs->wrap = bs_read; } // This function is only called from the getbit() and getbits() macros when // the BitStream has been exhausted and more data is required. Sinve these // bistreams no longer access files, this function simple sets an error and // resets the buffer. static void bs_read (Bitstream *bs) { bs->ptr = bs->buf - 1; bs->error = 1; } // This function is called to close the bitstream. It returns the number of // full bytes actually read as bits. uint32_t bs_close_read (Bitstream *bs) { uint32_t bytes_read; if (bs->bc < sizeof (*(bs->ptr)) * 8) bs->ptr++; bytes_read = (uint32_t)(bs->ptr - bs->buf) * sizeof (*(bs->ptr)); if (!(bytes_read & 1)) ++bytes_read; CLEAR (*bs); return bytes_read; } #endif #ifndef NO_PACK // Open the specified BitStream using the specified buffer pointers. It is // assumed that enough buffer space has been allocated for all data that will // be written, otherwise an error will be generated. static void bs_write (Bitstream *bs); void bs_open_write (Bitstream *bs, void *buffer_start, void *buffer_end) { bs->error = bs->sr = bs->bc = 0; bs->ptr = bs->buf = buffer_start; bs->end = buffer_end; bs->wrap = bs_write; } // This function is only called from the putbit() and putbits() macros when // the buffer is full, which is now flagged as an error. static void bs_write (Bitstream *bs) { bs->ptr = bs->buf; bs->error = 1; } // This function forces a flushing write of the specified BitStream, and // returns the total number of bytes written into the buffer. uint32_t bs_close_write (Bitstream *bs) { uint32_t bytes_written; if (bs->error) return (uint32_t) -1; while (1) { while (bs->bc) putbit_1 (bs); bytes_written = (uint32_t)(bs->ptr - bs->buf) * sizeof (*(bs->ptr)); if (bytes_written & 1) { putbit_1 (bs); } else break; }; CLEAR (*bs); return bytes_written; } #endif /////////////////////// Endian Correction Routines //////////////////////////// void little_endian_to_native (void *data, char *format) { unsigned char *cp = (unsigned char *) data; int32_t temp; while (*format) { switch (*format) { case 'L': temp = cp [0] + ((int32_t) cp [1] << 8) + ((int32_t) cp [2] << 16) + ((int32_t) cp [3] << 24); * (int32_t *) cp = temp; cp += 4; break; case 'S': temp = cp [0] + (cp [1] << 8); * (short *) cp = (short) temp; cp += 2; break; default: if (isdigit (*format)) cp += *format - '0'; break; } format++; } } void native_to_little_endian (void *data, char *format) { unsigned char *cp = (unsigned char *) data; int32_t temp; while (*format) { switch (*format) { case 'L': temp = * (int32_t *) cp; *cp++ = (unsigned char) temp; *cp++ = (unsigned char) (temp >> 8); *cp++ = (unsigned char) (temp >> 16); *cp++ = (unsigned char) (temp >> 24); break; case 'S': temp = * (short *) cp; *cp++ = (unsigned char) temp; *cp++ = (unsigned char) (temp >> 8); break; default: if (isdigit (*format)) cp += *format - '0'; break; } format++; } } ////////////////////////// Debug Wrapper for Malloc /////////////////////////// #ifdef DEBUG_ALLOC void *vptrs [512]; static void *add_ptr (void *ptr) { int i; for (i = 0; i < 512; ++i) if (!vptrs [i]) { vptrs [i] = ptr; break; } if (i == 512) error_line ("too many mallocs!"); return ptr; } static void *del_ptr (void *ptr) { int i; for (i = 0; i < 512; ++i) if (vptrs [i] == ptr) { vptrs [i] = NULL; break; } if (i == 512) error_line ("free invalid ptr!"); return ptr; } void *malloc_db (uint32_t size) { if (size) return add_ptr (malloc (size)); else return NULL; } void free_db (void *ptr) { if (ptr) free (del_ptr (ptr)); } void *realloc_db (void *ptr, uint32_t size) { if (ptr && size) return add_ptr (realloc (del_ptr (ptr), size)); else if (size) return malloc_db (size); else free_db (ptr); return NULL; } int32_t dump_alloc (void) { int i, j; for (j = i = 0; i < 512; ++i) if (vptrs [i]) j++; return j; } #endif