static #endif SquashFile* squash_file_wopen_with_options (SquashCodec* codec, const wchar_t* filename, const wchar_t* mode, SquashOptions* options) { assert (codec != NULL); assert (filename != NULL); assert (mode != NULL); #if !defined(_WIN32) char* nfilename = squash_charset_wide_to_utf8 (filename); if (nfilename == NULL) return NULL; char* nmode = squash_charset_wide_to_utf8 (mode); if (nmode == NULL) { squash_free (nfilename); return NULL; } SquashFile* file = squash_file_open_with_options (codec, nfilename, nmode, options); squash_free (nfilename); squash_free (nmode); return file; #else FILE* fp = _wfopen (filename, mode); if (HEDLEY_UNLIKELY(fp == NULL)) return NULL; return squash_file_steal_with_options (codec, fp, options); #endif }
/** * @brief Open a file using a with the specified options * * @a filename is assumed to be UTF-8 encoded. On Windows, this * function will call @ref squash_file_wopen_with_options internally. * On other platforms, filenames on disk are assumed to be in UTF-8 * format, therefore the @a filename is passed through to `fopen` * without any conversion. * * @param filename name of the file to open * @param mode file mode * @param codec codec to use * @param options options * @return The opened file, or *NULL* on error * @see squash_file_open * @see squash_file_wopen_with_options */ SquashFile* squash_file_open_with_options (SquashCodec* codec, const char* filename, const char* mode, SquashOptions* options) { assert (filename != NULL); assert (mode != NULL); assert (codec != NULL); #if !defined(_WIN32) FILE* fp = fopen (filename, mode); if (HEDLEY_UNLIKELY(fp == NULL)) return NULL; return squash_file_steal_with_options (codec, fp, options); #else wchar_t* wfilename = squash_charset_utf8_to_wide (filename); if (wfilename == NULL) return NULL; wchar_t* wmode = squash_charset_utf8_to_wide (mode); if (wmode == NULL) { squash_free (wfilename); return NULL; } SquashFile* file = squash_file_wopen_with_options (codec, wfilename, wmode, options); squash_free (wfilename); squash_free (wmode); return file; #endif }
/* * Open an oggflac file * sound_format will be modified and private state information * will be returned. */ void *oggflac_open( char *filename, sound_format_t *sound_format ) { oggflac_data_t *oggflac_data; OggFLAC__StreamDecoderState state; /* Allocate space for data */ squash_malloc( oggflac_data, sizeof(oggflac_data_t) ); if( (oggflac_data->decoder = OggFLAC__stream_decoder_new()) == NULL ) { squash_free( oggflac_data ); squash_error( "Unable to create oggflac decoder" ); } if( !OggFLAC__stream_decoder_set_filename( oggflac_data->decoder, filename ) ) { squash_free( oggflac_data ); squash_error( "Unable to set filename in decoder" ); } OggFLAC__stream_decoder_set_metadata_callback( oggflac_data->decoder, oggflac_metadata_callback_decode_frame ); OggFLAC__stream_decoder_set_write_callback( oggflac_data->decoder, oggflac_write_callback_decode_frame ); OggFLAC__stream_decoder_set_error_callback( oggflac_data->decoder, oggflac_error_callback ); OggFLAC__stream_decoder_set_client_data( oggflac_data->decoder, oggflac_data ); state = OggFLAC__stream_decoder_init( oggflac_data->decoder ); switch( state ) { case OggFLAC__STREAM_DECODER_OK: /* no problem */ break; case OggFLAC__STREAM_DECODER_OGG_ERROR: case OggFLAC__STREAM_DECODER_READ_ERROR case OggFLAC__STREAM_DECODER_FLAC_STREAM_DECODER_ERROR: case OggFLAC__STREAM_DECODER_INVALID_CALLBACK: case OggFLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR: case OggFLAC__STREAM_DECODER_ALREADY_INITIALIZED: case OggFLAC__STREAM_DECODER_UNINITIALIZED: squash_free( oggflac_data ); squash_error( "Unable to initialize decoder: %s", OggFLAC__StreamDecoderStateString[ state ] ); break; } oggflac_data->buffer = NULL; oggflac_data->buffer_size = 0; oggflac_data->channels = -1; oggflac_data->sample_rate = -1; oggflac_data->duration = -1; OggFLAC__stream_decoder_process_until_end_of_metadata( oggflac_data->decoder ); sound_format->rate = oggflac_data->sample_rate; sound_format->channels = oggflac_data->channels; sound_format->bits = 16; sound_format->byte_format = SOUND_LITTLE; /* Return data */ return (void *)oggflac_data; }
/* * Close the opened song. */ void oggflac_close( void *data ) { oggflac_data_t *oggflac_data = (oggflac_data_t *)data; OggFLAC__stream_decoder_finish( oggflac_data->decoder ); OggFLAC__stream_decoder_delete( oggflac_data->decoder ); /* Free allocated storage */ squash_free( oggflac_data->buffer ); oggflac_data->buffer_size = 0; squash_free( oggflac_data ); return; }
void oggflac_metadata_callback_load_meta( const OggFLAC__StreamDecoder *decoder, const OggFLAC__StreamMetadata *metadata, void *client_data ) { OggFLAC__StreamMetadata_VorbisComment comment = metadata->data.vorbis_comment; int i; char *start, *end, *key, *value; if( metadata->type != OggFLAC__METADATA_TYPE_VORBIS_COMMENT ) { return; } for(i = 0; i < comment.num_comments; i++ ) { /* TODO: Make this faster, don't malloc start. */ int length = comment.comments[i].length; squash_malloc( start, length+1 ); memcpy( start, comment.comments[i].entry, length ); start[ length ] = '\0'; end = strchr( start, '=' ); if( end == NULL ) { continue; } key = copy_string( start, end - 1 ); value = strdup( end+1 ); insert_meta_data( client_data, NULL, key, value ); squash_free(start); } }
/** * @brief Destroy a stream. * @protected * * @warning This function must only be used to implement a subclass of * @ref SquashObject. Each subclass should implement a *_destroy * function which should perform any operations needed to destroy * their own data and chain up to the *_destroy function of the base * class, eventually invoking ::squash_object_destroy. Invoking this * function in any other context is likely to cause a memory leak or * crash. If you are not creating a subclass, you should be calling * @ref squash_object_unref instead. * * @param stream The stream. * * @see squash_object_destroy */ void squash_stream_destroy (void* stream) { SquashStream* s; assert (stream != NULL); s = (SquashStream*) stream; if (SQUASH_UNLIKELY(s->priv != NULL)) { SquashStreamPrivate* priv = (SquashStreamPrivate*) s->priv; if (!priv->finished) { squash_stream_send_to_thread (s, SQUASH_OPERATION_TERMINATE); } cnd_destroy (&(priv->request_cnd)); cnd_destroy (&(priv->result_cnd)); mtx_destroy (&(priv->io_mtx)); squash_free (s->priv); } if (s->destroy_user_data != NULL && s->user_data != NULL) { s->destroy_user_data (s->user_data); } if (s->options != NULL) { s->options = squash_object_unref (s->options); } squash_object_destroy (stream); }
/** * @brief Free a file * * This function will free the @ref SquashFile, but unlike @ref * squash_file_close it will not actually close the underlying *FILE* * pointer. Instead, it will return the value in the @a fp argument, * allowing you to further manipulate it. * * @warning On Windows you should not use this function unless Squash * is linked against the same runtime as the code you want to continue * using the file pointer from; see * http://siomsystems.com/mixing-visual-studio-versions/ for more * information. * * @param file file to free * @param[out] fp location to store the underlying *FILE* pointer * @return @ref SQUASH_OK on success or a negative error code on * failure */ SquashStatus squash_file_free (SquashFile* file, FILE** fp) { SquashStatus res = SQUASH_OK; if (HEDLEY_UNLIKELY(file == NULL)) { if (fp != NULL) *fp = NULL; return SQUASH_OK; } squash_file_lock (file); if (file->stream != NULL && file->stream->stream_type == SQUASH_STREAM_COMPRESS) res = squash_file_write_internal (file, 0, NULL, SQUASH_OPERATION_FINISH); #if defined(SQUASH_MMAP_IO) squash_mapped_file_destroy (&(file->map), false); #endif if (fp != NULL) *fp = file->fp; SQUASH_FUNLOCKFILE(file->fp); squash_object_unref (file->stream); squash_object_unref (file->options); squash_file_unlock (file); mtx_destroy (&(file->mtx)); squash_free (file); return res; }
static void squash_lz4f_stream_destroy (void* stream) { SquashLZ4FStream* s = (SquashLZ4FStream*) stream; if (((SquashStream*) stream)->stream_type == SQUASH_STREAM_COMPRESS) { LZ4F_freeCompressionContext(s->data.comp.ctx); if (s->data.comp.output_buffer != NULL) squash_free (s->data.comp.output_buffer); } else { LZ4F_freeDecompressionContext(s->data.decomp.ctx); } squash_stream_destroy (stream); }
static #endif SquashStatus squash_file_vwprintf (SquashFile* file, const wchar_t* format, va_list ap) { SquashStatus res = SQUASH_OK; int size; wchar_t* buf = NULL; assert (file != NULL); assert (format != NULL); size = _vscwprintf (format, ap); if (HEDLEY_UNLIKELY(size < 0)) return squash_error (SQUASH_FAILED); buf = calloc (size + 1, sizeof (wchar_t)); if (HEDLEY_UNLIKELY(buf == NULL)) return squash_error (SQUASH_MEMORY); #if !defined(_WIN32) const int written = vswprintf (buf, size + 1, format, ap); #else const int written = _vsnwprintf (buf, size + 1, format, ap); #endif if (HEDLEY_UNLIKELY(written != size)) { res = squash_error (SQUASH_FAILED); } else { size_t data_size; char* data; bool conv_success = squash_charset_convert (&data_size, &data, "UTF-8", size * sizeof(wchar_t), (char*) buf, squash_charset_get_wide ()); if (HEDLEY_LIKELY(conv_success)) res = squash_file_write (file, data_size, (uint8_t*) data); else res = squash_error (SQUASH_FAILED); } squash_free (buf); return res; }
SquashStatus squash_file_vprintf (SquashFile* file, const char* format, va_list ap) { SquashStatus res = SQUASH_OK; int size; char* heap_buf = NULL; assert (file != NULL); assert (format != NULL); #if defined(_WIN32) size = _vscprintf (format, ap); if (HEDLEY_UNLIKELY(size < 0)) return squash_error (SQUASH_FAILED); #else char buf[256]; size = vsnprintf (buf, sizeof (buf), format, ap); if (HEDLEY_UNLIKELY(size < 0)) return squash_error (SQUASH_FAILED); else if (size >= (int) sizeof (buf)) #endif { heap_buf = squash_malloc (size + 1); if (HEDLEY_UNLIKELY(heap_buf == NULL)) return squash_error (SQUASH_MEMORY); const int written = vsnprintf (heap_buf, size + 1, format, ap); if (HEDLEY_UNLIKELY(written != size)) res = squash_error (SQUASH_FAILED); } if (HEDLEY_LIKELY(res == SQUASH_OK)) { res = squash_file_write (file, size, #if !defined(_WIN32) (heap_buf == NULL) ? (uint8_t*) buf : #endif (uint8_t*) heap_buf); } squash_free (heap_buf); return res; }
static SquashStatus squash_brieflz_compress_buffer (SquashCodec* codec, size_t* compressed_size, uint8_t compressed[HEDLEY_ARRAY_PARAM(*compressed_size)], size_t uncompressed_size, const uint8_t uncompressed[HEDLEY_ARRAY_PARAM(uncompressed_size)], SquashOptions* options) { uint8_t *dst = compressed; void *workmem = NULL; unsigned long size; #if ULONG_MAX < SIZE_MAX if (HEDLEY_UNLIKELY(ULONG_MAX < uncompressed_size) || HEDLEY_UNLIKELY(ULONG_MAX < *compressed_size)) return squash_error (SQUASH_RANGE); #endif if (HEDLEY_UNLIKELY((unsigned long) *compressed_size < squash_brieflz_get_max_compressed_size (codec, uncompressed_size))) { return squash_error (SQUASH_BUFFER_FULL); } workmem = squash_malloc (blz_workmem_size ((unsigned long) uncompressed_size)); if (HEDLEY_UNLIKELY(workmem == NULL)) { return squash_error (SQUASH_MEMORY); } size = blz_pack (uncompressed, dst, (unsigned long) uncompressed_size, workmem); squash_free (workmem); #if SIZE_MAX < ULONG_MAX if (HEDLEY_UNLIKELY(SIZE_MAX < size)) return squash_error (SQUASH_RANGE); #endif *compressed_size = (size_t) size; return SQUASH_OK; }
/** * @brief Decrement the reference count on an object. * * Once the reference count reaches 0 the object will be freed. * * @param obj The object to decrease the reference count of. * @return NULL */ void* squash_object_unref (void* obj) { if (obj == NULL) return NULL; SquashObject* object = (SquashObject*) obj; unsigned int ref_count = squash_atomic_dec (&(object->ref_count)); if (ref_count == 1) { if (SQUASH_LIKELY(object->destroy_notify != NULL)) object->destroy_notify (obj); squash_free (obj); return NULL; } else { return NULL; } }
static SquashStatus squash_lzg_compress_buffer (SquashCodec* codec, size_t* compressed_size, uint8_t compressed[HEDLEY_ARRAY_PARAM(*compressed_size)], size_t uncompressed_size, const uint8_t uncompressed[HEDLEY_ARRAY_PARAM(uncompressed_size)], SquashOptions* options) { lzg_encoder_config_t cfg = { squash_options_get_int_at (options, codec, SQUASH_LZG_OPT_LEVEL), squash_options_get_bool_at (options, codec, SQUASH_LZG_OPT_FAST), NULL, NULL }; #if UINT32_MAX < SIZE_MAX if (HEDLEY_UNLIKELY(UINT32_MAX < uncompressed_size) || HEDLEY_UNLIKELY(UINT32_MAX < *compressed_size)) return squash_error (SQUASH_RANGE); #endif uint8_t* workmem = squash_calloc (LZG_WorkMemSize (&cfg), 1); if (HEDLEY_UNLIKELY(workmem == NULL)) return squash_error (SQUASH_MEMORY); lzg_uint32_t res = LZG_EncodeFull ((const unsigned char*) uncompressed, (lzg_uint32_t) uncompressed_size, (unsigned char*) compressed, (lzg_uint32_t) *compressed_size, &cfg, workmem); squash_free (workmem); if (res == 0) { return squash_error (SQUASH_FAILED); } else { #if SIZE_MAX < UINT32_MAX if (HEDLEY_UNLIKELY(SIZE_MAX < res)) return squash_error (SQUASH_RANGE); #endif *compressed_size = (size_t) res; return SQUASH_OK; } }
static void squash_brotli_free (void* opaque, void* ptr) { squash_free (ptr); }
static void squash_bsc_free (void* ptr) { squash_free (ptr); }
/** * @brief load a %SquashPlugin * * @note This function is generally only useful inside of a callback * passed to ::squash_foreach_plugin. Every other way to get a plugin * (such as ::squash_get_plugin) will initialize the plugin as well * (and return *NULL* instead of the plugin if initialization fails). * The foreach functions, however, do not initialize the plugin since * doing so requires actually loading the plugin. * * @param plugin The plugin to load. * @return A status code. * @retval SQUASH_OK The plugin has been loaded. * @retval SQUASH_UNABLE_TO_LOAD Unable to load plugin. */ SquashStatus squash_plugin_init (SquashPlugin* plugin) { if (plugin->plugin == NULL) { #if !defined(_WIN32) void* handle; #else HMODULE handle; #endif char* plugin_file_name; plugin_file_name = squash_strdup_printf ("%s/%ssquash%s-plugin-%s%s", plugin->directory, SQUASH_SHARED_LIBRARY_PREFIX, SQUASH_VERSION_API, plugin->name, SQUASH_SHARED_LIBRARY_SUFFIX); if (plugin_file_name == NULL) return squash_error (SQUASH_MEMORY); #if !defined(_WIN32) handle = dlopen (plugin_file_name, RTLD_LAZY); #else handle = LoadLibrary (TEXT(plugin_file_name)); if (handle == NULL) { squash_free (plugin_file_name); #if defined(_DEBUG) plugin_file_name = squash_strdup_printf ("%s/Debug/%ssquash%s-plugin-%s%s", plugin->directory, SQUASH_SHARED_LIBRARY_PREFIX, SQUASH_VERSION_API, plugin->name, SQUASH_SHARED_LIBRARY_SUFFIX); #else plugin_file_name = squash_strdup_printf ("%s/Release/%ssquash%s-plugin-%s%s", plugin->directory, SQUASH_SHARED_LIBRARY_PREFIX, SQUASH_VERSION_API, plugin->name, SQUASH_SHARED_LIBRARY_SUFFIX); #endif handle = LoadLibrary (TEXT(plugin_file_name)); } #endif squash_free (plugin_file_name); if (SQUASH_LIKELY(handle != NULL)) { SQUASH_MTX_LOCK(plugin_init); if (plugin->plugin == NULL) { plugin->plugin = handle; handle = NULL; } SQUASH_MTX_UNLOCK(plugin_init); } else { return squash_error (SQUASH_UNABLE_TO_LOAD); } if (handle != NULL) { #if !defined(_WIN32) dlclose (handle); #else FreeLibrary (handle); #endif } else { SquashStatus (*init_func) (SquashPlugin*); #if !defined(_WIN32) *(void **) (&init_func) = dlsym (plugin->plugin, "squash_plugin_init_plugin"); #else *(void **) (&init_func) = GetProcAddress (plugin->plugin, "squash_plugin_init_plugin"); #endif if (init_func != NULL) { init_func (plugin); } } } return SQUASH_LIKELY(plugin->plugin != NULL) ? SQUASH_OK : squash_error (SQUASH_UNABLE_TO_LOAD); }
static void squash_csc_free (void* p, void* address) { squash_free (address); }
static void squash_density_free (void* ptr) { squash_free (ptr); }