diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
commit | 6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch) | |
tree | a68f146d7fa01f0134297619fbe7e33db084e0aa /modules/freetype2/src/bzip2/ftbzip2.c | |
parent | Initial commit. (diff) | |
download | thunderbird-upstream.tar.xz thunderbird-upstream.zip |
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'modules/freetype2/src/bzip2/ftbzip2.c')
-rw-r--r-- | modules/freetype2/src/bzip2/ftbzip2.c | 530 |
1 files changed, 530 insertions, 0 deletions
diff --git a/modules/freetype2/src/bzip2/ftbzip2.c b/modules/freetype2/src/bzip2/ftbzip2.c new file mode 100644 index 0000000000..6cf10678b7 --- /dev/null +++ b/modules/freetype2/src/bzip2/ftbzip2.c @@ -0,0 +1,530 @@ +/**************************************************************************** + * + * ftbzip2.c + * + * FreeType support for .bz2 compressed files. + * + * This optional component relies on libbz2. It should mainly be used to + * parse compressed PCF fonts, as found with many X11 server + * distributions. + * + * Copyright (C) 2010-2023 by + * Joel Klinghed. + * + * based on `src/gzip/ftgzip.c' + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#include <freetype/internal/ftmemory.h> +#include <freetype/internal/ftstream.h> +#include <freetype/internal/ftdebug.h> +#include <freetype/ftbzip2.h> +#include FT_CONFIG_STANDARD_LIBRARY_H + + +#include <freetype/ftmoderr.h> + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX Bzip2_Err_ +#define FT_ERR_BASE FT_Mod_Err_Bzip2 + +#include <freetype/fterrors.h> + + +#ifdef FT_CONFIG_OPTION_USE_BZIP2 + +#define BZ_NO_STDIO /* Do not need FILE */ +#include <bzlib.h> + + +/***************************************************************************/ +/***************************************************************************/ +/***** *****/ +/***** B Z I P 2 M E M O R Y M A N A G E M E N T *****/ +/***** *****/ +/***************************************************************************/ +/***************************************************************************/ + + /* it is better to use FreeType memory routines instead of raw + 'malloc/free' */ + + typedef void* (*alloc_func)( void*, int, int ); + typedef void (*free_func) ( void*, void* ); + + + static void* + ft_bzip2_alloc( FT_Memory memory, + int items, + int size ) + { + FT_ULong sz = (FT_ULong)size * (FT_ULong)items; + FT_Error error; + FT_Pointer p = NULL; + + + FT_MEM_QALLOC( p, sz ); + return p; + } + + + static void + ft_bzip2_free( FT_Memory memory, + void* address ) + { + FT_MEM_FREE( address ); + } + + +/***************************************************************************/ +/***************************************************************************/ +/***** *****/ +/***** B Z I P 2 F I L E D E S C R I P T O R *****/ +/***** *****/ +/***************************************************************************/ +/***************************************************************************/ + +#define FT_BZIP2_BUFFER_SIZE 4096 + + typedef struct FT_BZip2FileRec_ + { + FT_Stream source; /* parent/source stream */ + FT_Stream stream; /* embedding stream */ + FT_Memory memory; /* memory allocator */ + bz_stream bzstream; /* bzlib input stream */ + + FT_Byte input[FT_BZIP2_BUFFER_SIZE]; /* input read buffer */ + + FT_Byte buffer[FT_BZIP2_BUFFER_SIZE]; /* output buffer */ + FT_ULong pos; /* position in output */ + FT_Byte* cursor; + FT_Byte* limit; + FT_Bool reset; /* reset before next read */ + + } FT_BZip2FileRec, *FT_BZip2File; + + + /* check and skip .bz2 header - we don't support `transparent' compression */ + static FT_Error + ft_bzip2_check_header( FT_Stream stream ) + { + FT_Error error = FT_Err_Ok; + FT_Byte head[4]; + + + if ( FT_STREAM_SEEK( 0 ) || + FT_STREAM_READ( head, 4 ) ) + goto Exit; + + /* head[0] && head[1] are the magic numbers; */ + /* head[2] is the version, and head[3] the blocksize */ + if ( head[0] != 0x42 || + head[1] != 0x5A || + head[2] != 0x68 ) /* only support bzip2 (huffman) */ + { + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + Exit: + return error; + } + + + static FT_Error + ft_bzip2_file_init( FT_BZip2File zip, + FT_Stream stream, + FT_Stream source ) + { + bz_stream* bzstream = &zip->bzstream; + FT_Error error = FT_Err_Ok; + + + zip->stream = stream; + zip->source = source; + zip->memory = stream->memory; + + zip->limit = zip->buffer + FT_BZIP2_BUFFER_SIZE; + zip->cursor = zip->limit; + zip->pos = 0; + zip->reset = 0; + + /* check .bz2 header */ + { + stream = source; + + error = ft_bzip2_check_header( stream ); + if ( error ) + goto Exit; + + if ( FT_STREAM_SEEK( 0 ) ) + goto Exit; + } + + /* initialize bzlib */ + bzstream->bzalloc = (alloc_func)ft_bzip2_alloc; + bzstream->bzfree = (free_func) ft_bzip2_free; + bzstream->opaque = zip->memory; + + bzstream->avail_in = 0; + bzstream->next_in = (char*)zip->buffer; + + if ( BZ2_bzDecompressInit( bzstream, 0, 0 ) != BZ_OK || + !bzstream->next_in ) + error = FT_THROW( Invalid_File_Format ); + + Exit: + return error; + } + + + static void + ft_bzip2_file_done( FT_BZip2File zip ) + { + bz_stream* bzstream = &zip->bzstream; + + + BZ2_bzDecompressEnd( bzstream ); + + /* clear the rest */ + bzstream->bzalloc = NULL; + bzstream->bzfree = NULL; + bzstream->opaque = NULL; + bzstream->next_in = NULL; + bzstream->next_out = NULL; + bzstream->avail_in = 0; + bzstream->avail_out = 0; + + zip->memory = NULL; + zip->source = NULL; + zip->stream = NULL; + } + + + static FT_Error + ft_bzip2_file_reset( FT_BZip2File zip ) + { + FT_Stream stream = zip->source; + FT_Error error; + + + if ( !FT_STREAM_SEEK( 0 ) ) + { + bz_stream* bzstream = &zip->bzstream; + + + BZ2_bzDecompressEnd( bzstream ); + + bzstream->avail_in = 0; + bzstream->next_in = (char*)zip->input; + bzstream->avail_out = 0; + bzstream->next_out = (char*)zip->buffer; + + zip->limit = zip->buffer + FT_BZIP2_BUFFER_SIZE; + zip->cursor = zip->limit; + zip->pos = 0; + zip->reset = 0; + + BZ2_bzDecompressInit( bzstream, 0, 0 ); + } + + return error; + } + + + static FT_Error + ft_bzip2_file_fill_input( FT_BZip2File zip ) + { + bz_stream* bzstream = &zip->bzstream; + FT_Stream stream = zip->source; + FT_ULong size; + + + if ( stream->read ) + { + size = stream->read( stream, stream->pos, zip->input, + FT_BZIP2_BUFFER_SIZE ); + if ( size == 0 ) + { + zip->limit = zip->cursor; + return FT_THROW( Invalid_Stream_Operation ); + } + } + else + { + size = stream->size - stream->pos; + if ( size > FT_BZIP2_BUFFER_SIZE ) + size = FT_BZIP2_BUFFER_SIZE; + + if ( size == 0 ) + { + zip->limit = zip->cursor; + return FT_THROW( Invalid_Stream_Operation ); + } + + FT_MEM_COPY( zip->input, stream->base + stream->pos, size ); + } + stream->pos += size; + + bzstream->next_in = (char*)zip->input; + bzstream->avail_in = size; + + return FT_Err_Ok; + } + + + static FT_Error + ft_bzip2_file_fill_output( FT_BZip2File zip ) + { + bz_stream* bzstream = &zip->bzstream; + FT_Error error = FT_Err_Ok; + + + zip->cursor = zip->buffer; + bzstream->next_out = (char*)zip->cursor; + bzstream->avail_out = FT_BZIP2_BUFFER_SIZE; + + while ( bzstream->avail_out > 0 ) + { + int err; + + + if ( bzstream->avail_in == 0 ) + { + error = ft_bzip2_file_fill_input( zip ); + if ( error ) + break; + } + + err = BZ2_bzDecompress( bzstream ); + + if ( err != BZ_OK ) + { + zip->reset = 1; + + if ( err == BZ_STREAM_END ) + { + zip->limit = (FT_Byte*)bzstream->next_out; + if ( zip->limit == zip->cursor ) + error = FT_THROW( Invalid_Stream_Operation ); + break; + } + else + { + zip->limit = zip->cursor; + error = FT_THROW( Invalid_Stream_Operation ); + break; + } + } + } + + return error; + } + + + /* fill output buffer; `count' must be <= FT_BZIP2_BUFFER_SIZE */ + static FT_Error + ft_bzip2_file_skip_output( FT_BZip2File zip, + FT_ULong count ) + { + FT_Error error = FT_Err_Ok; + + + for (;;) + { + FT_ULong delta = (FT_ULong)( zip->limit - zip->cursor ); + + + if ( delta >= count ) + delta = count; + + zip->cursor += delta; + zip->pos += delta; + + count -= delta; + if ( count == 0 ) + break; + + error = ft_bzip2_file_fill_output( zip ); + if ( error ) + break; + } + + return error; + } + + + static FT_ULong + ft_bzip2_file_io( FT_BZip2File zip, + FT_ULong pos, + FT_Byte* buffer, + FT_ULong count ) + { + FT_ULong result = 0; + FT_Error error; + + + /* Reset inflate stream if seeking backwards or bzip reported an error. */ + /* Yes, that is not too efficient, but it saves memory :-) */ + if ( pos < zip->pos || zip->reset ) + { + error = ft_bzip2_file_reset( zip ); + if ( error ) + goto Exit; + } + + /* skip unwanted bytes */ + if ( pos > zip->pos ) + { + error = ft_bzip2_file_skip_output( zip, (FT_ULong)( pos - zip->pos ) ); + if ( error ) + goto Exit; + } + + if ( count == 0 ) + goto Exit; + + /* now read the data */ + for (;;) + { + FT_ULong delta; + + + delta = (FT_ULong)( zip->limit - zip->cursor ); + if ( delta >= count ) + delta = count; + + FT_MEM_COPY( buffer, zip->cursor, delta ); + buffer += delta; + result += delta; + zip->cursor += delta; + zip->pos += delta; + + count -= delta; + if ( count == 0 ) + break; + + error = ft_bzip2_file_fill_output( zip ); + if ( error ) + break; + } + + Exit: + return result; + } + + +/***************************************************************************/ +/***************************************************************************/ +/***** *****/ +/***** B Z E M B E D D I N G S T R E A M *****/ +/***** *****/ +/***************************************************************************/ +/***************************************************************************/ + + static void + ft_bzip2_stream_close( FT_Stream stream ) + { + FT_BZip2File zip = (FT_BZip2File)stream->descriptor.pointer; + FT_Memory memory = stream->memory; + + + if ( zip ) + { + /* finalize bzip file descriptor */ + ft_bzip2_file_done( zip ); + + FT_FREE( zip ); + + stream->descriptor.pointer = NULL; + } + } + + + static unsigned long + ft_bzip2_stream_io( FT_Stream stream, + unsigned long offset, + unsigned char* buffer, + unsigned long count ) + { + FT_BZip2File zip = (FT_BZip2File)stream->descriptor.pointer; + + + return ft_bzip2_file_io( zip, offset, buffer, count ); + } + + + FT_EXPORT_DEF( FT_Error ) + FT_Stream_OpenBzip2( FT_Stream stream, + FT_Stream source ) + { + FT_Error error; + FT_Memory memory; + FT_BZip2File zip = NULL; + + + if ( !stream || !source ) + { + error = FT_THROW( Invalid_Stream_Handle ); + goto Exit; + } + + memory = source->memory; + + /* + * check the header right now; this prevents allocating unnecessary + * objects when we don't need them + */ + error = ft_bzip2_check_header( source ); + if ( error ) + goto Exit; + + FT_ZERO( stream ); + stream->memory = memory; + + if ( !FT_QNEW( zip ) ) + { + error = ft_bzip2_file_init( zip, stream, source ); + if ( error ) + { + FT_FREE( zip ); + goto Exit; + } + + stream->descriptor.pointer = zip; + } + + stream->size = 0x7FFFFFFFL; /* don't know the real size! */ + stream->pos = 0; + stream->base = NULL; + stream->read = ft_bzip2_stream_io; + stream->close = ft_bzip2_stream_close; + + Exit: + return error; + } + +#else /* !FT_CONFIG_OPTION_USE_BZIP2 */ + + FT_EXPORT_DEF( FT_Error ) + FT_Stream_OpenBzip2( FT_Stream stream, + FT_Stream source ) + { + FT_UNUSED( stream ); + FT_UNUSED( source ); + + return FT_THROW( Unimplemented_Feature ); + } + +#endif /* !FT_CONFIG_OPTION_USE_BZIP2 */ + + +/* END */ |