freetype2/src/base/ftsystem.c

339 lines
8.0 KiB
C
Raw Normal View History

/****************************************************************************
*
* ftsystem.c
*
* ANSI-specific FreeType low-level system interface (body).
*
2024-01-27 17:11:22 +01:00
* Copyright (C) 1996-2024 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* 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.
*
*/
/**************************************************************************
*
* This file contains the default interface used by FreeType to access
* low-level, i.e. memory management, i/o access as well as thread
* synchronisation. It can be replaced by user-specific routines if
* necessary.
*
*/
2000-12-08 17:17:16 +01:00
#include <ft2build.h>
#include FT_CONFIG_CONFIG_H
#include <freetype/internal/ftdebug.h>
#include <freetype/internal/ftstream.h>
#include <freetype/ftsystem.h>
#include <freetype/fterrors.h>
#include <freetype/fttypes.h>
/**************************************************************************
*
* MEMORY MANAGEMENT INTERFACE
*
*/
/**************************************************************************
*
* It is not necessary to do any error checking for the
* allocation-related functions. This will be done by the higher level
* routines like ft_mem_alloc() or ft_mem_realloc().
*
*/
/**************************************************************************
*
* @Function:
* ft_alloc
*
* @Description:
* The memory allocation function.
*
* @Input:
* memory ::
* A pointer to the memory object.
*
* size ::
* The requested size in bytes.
*
* @Return:
* The address of newly allocated block.
*/
FT_CALLBACK_DEF( void* )
ft_alloc( FT_Memory memory,
long size )
{
FT_UNUSED( memory );
return ft_smalloc( (size_t)size );
}
/**************************************************************************
*
* @Function:
* ft_realloc
*
* @Description:
* The memory reallocation function.
*
* @Input:
* memory ::
* A pointer to the memory object.
*
* cur_size ::
* The current size of the allocated memory block.
*
* new_size ::
* The newly requested size in bytes.
*
* block ::
* The current address of the block in memory.
*
* @Return:
* The address of the reallocated memory block.
*/
FT_CALLBACK_DEF( void* )
ft_realloc( FT_Memory memory,
long cur_size,
long new_size,
void* block )
{
FT_UNUSED( memory );
FT_UNUSED( cur_size );
return ft_srealloc( block, (size_t)new_size );
}
/**************************************************************************
*
* @Function:
* ft_free
*
* @Description:
* The memory release function.
*
* @Input:
* memory ::
* A pointer to the memory object.
*
* block ::
* The address of block in memory to be freed.
*/
FT_CALLBACK_DEF( void )
ft_free( FT_Memory memory,
void* block )
{
FT_UNUSED( memory );
ft_sfree( block );
}
/**************************************************************************
*
* RESOURCE MANAGEMENT INTERFACE
*
*/
#ifndef FT_CONFIG_OPTION_DISABLE_STREAM_SUPPORT
/**************************************************************************
*
* The macro FT_COMPONENT is used in trace mode. It is an implicit
* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
* messages during execution.
*/
2000-06-02 23:31:32 +02:00
#undef FT_COMPONENT
#define FT_COMPONENT io
2000-06-02 23:31:32 +02:00
/* We use the macro STREAM_FILE for convenience to extract the */
/* system-specific stream handle from a given FreeType stream object */
#define STREAM_FILE( stream ) ( (FT_FILE*)stream->descriptor.pointer )
/**************************************************************************
*
* @Function:
* ft_ansi_stream_close
*
* @Description:
* The function to close a stream.
*
* @Input:
* stream ::
* A pointer to the stream object.
*/
FT_CALLBACK_DEF( void )
ft_ansi_stream_close( FT_Stream stream )
{
ft_fclose( STREAM_FILE( stream ) );
2000-06-02 23:31:32 +02:00
stream->descriptor.pointer = NULL;
stream->size = 0;
2015-04-11 05:45:11 +02:00
stream->base = NULL;
}
/**************************************************************************
*
* @Function:
* ft_ansi_stream_io
*
* @Description:
* The function to open a stream.
*
* @Input:
* stream ::
* A pointer to the stream object.
*
* offset ::
* The position in the data stream to start reading.
*
* buffer ::
* The address of buffer to store the read data.
*
* count ::
* The number of bytes to read from the stream.
*
* @Return:
2023-04-26 13:15:57 +02:00
* The number of bytes actually read. If `count' is zero (that is,
* the function is used for seeking), a non-zero return value
* indicates an error.
*/
FT_CALLBACK_DEF( unsigned long )
ft_ansi_stream_io( FT_Stream stream,
unsigned long offset,
unsigned char* buffer,
unsigned long count )
{
FT_FILE* file;
2000-05-17 01:44:38 +02:00
* src/base/ftsystem.c (ft_ansi_stream_io): Avoid undefined behaviour. Also short-circuit on `offset` to avoid checking `count` a second time when `ft_ansi_stream_io` is used for reading. Per ISO/IEC 9899: If an argument to a function has an invalid value (such as a value outside the domain of the function, or a pointer outside the address space of the program, or a null pointer, or apointer to non-modifiable storage when the corresponding parameter is not const-qualified) or a type (after promotion) not expected by a function with variable number of arguments, the behavior is undefined. If a function argument is described as being an array, the pointer actually passed to the function shall have a value such that all address computations and accesses to objects (that would be valid if the pointer did point to the first element of such an array) are in fact valid. Per IEEE Std 1003.1: size_t fread(void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream); The `fread` function shall read into the array pointed to by `ptr` up to `nitems` elements whose size is specified by `size` in bytes, from the stream pointed to by `stream`. Since the first argument to `fread` is described as being an array, its behavior is undefined when that argument is a null pointer. Per the documentation on `ft_ansi_stream_io`: If `count' is zero (this is, the function is used for seeking), a non-zero return value indicates an error. Thus the intent is clear, and the call to `fread` can be skipped, avoiding undefined behaviour.
2023-02-24 17:48:48 +01:00
if ( offset > stream->size && !count )
return 1;
file = STREAM_FILE( stream );
if ( stream->pos != offset )
ft_fseek( file, (long)offset, SEEK_SET );
* src/base/ftsystem.c (ft_ansi_stream_io): Avoid undefined behaviour. Also short-circuit on `offset` to avoid checking `count` a second time when `ft_ansi_stream_io` is used for reading. Per ISO/IEC 9899: If an argument to a function has an invalid value (such as a value outside the domain of the function, or a pointer outside the address space of the program, or a null pointer, or apointer to non-modifiable storage when the corresponding parameter is not const-qualified) or a type (after promotion) not expected by a function with variable number of arguments, the behavior is undefined. If a function argument is described as being an array, the pointer actually passed to the function shall have a value such that all address computations and accesses to objects (that would be valid if the pointer did point to the first element of such an array) are in fact valid. Per IEEE Std 1003.1: size_t fread(void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream); The `fread` function shall read into the array pointed to by `ptr` up to `nitems` elements whose size is specified by `size` in bytes, from the stream pointed to by `stream`. Since the first argument to `fread` is described as being an array, its behavior is undefined when that argument is a null pointer. Per the documentation on `ft_ansi_stream_io`: If `count' is zero (this is, the function is used for seeking), a non-zero return value indicates an error. Thus the intent is clear, and the call to `fread` can be skipped, avoiding undefined behaviour.
2023-02-24 17:48:48 +01:00
/* Avoid calling `fread` with `buffer=NULL` and `count=0`, */
/* which is undefined behaviour. */
if ( !count )
return 0;
return (unsigned long)ft_fread( buffer, 1, count, file );
}
/* documentation is in ftstream.h */
FT_BASE_DEF( FT_Error )
FT_Stream_Open( FT_Stream stream,
const char* filepathname )
{
FT_FILE* file;
2000-05-17 01:44:38 +02:00
if ( !stream )
return FT_THROW( Invalid_Stream_Handle );
stream->descriptor.pointer = NULL;
stream->pathname.pointer = (char*)filepathname;
2015-04-11 05:45:11 +02:00
stream->base = NULL;
stream->pos = 0;
stream->read = NULL;
stream->close = NULL;
file = ft_fopen( filepathname, "rb" );
if ( !file )
2000-06-02 23:31:32 +02:00
{
FT_ERROR(( "FT_Stream_Open:"
" could not open `%s'\n", filepathname ));
2000-06-02 23:31:32 +02:00
return FT_THROW( Cannot_Open_Resource );
2000-06-02 23:31:32 +02:00
}
2000-05-17 01:44:38 +02:00
ft_fseek( file, 0, SEEK_END );
stream->size = (unsigned long)ft_ftell( file );
if ( !stream->size )
{
FT_ERROR(( "FT_Stream_Open:" ));
FT_ERROR(( " opened `%s' but zero-sized\n", filepathname ));
ft_fclose( file );
return FT_THROW( Cannot_Open_Stream );
}
ft_fseek( file, 0, SEEK_SET );
2000-05-17 01:44:38 +02:00
stream->descriptor.pointer = file;
stream->read = ft_ansi_stream_io;
stream->close = ft_ansi_stream_close;
FT_TRACE1(( "FT_Stream_Open:" ));
2020-08-28 06:26:38 +02:00
FT_TRACE1(( " opened `%s' (%ld bytes) successfully\n",
filepathname, stream->size ));
2000-06-02 23:31:32 +02:00
return FT_Err_Ok;
}
#endif /* !FT_CONFIG_OPTION_DISABLE_STREAM_SUPPORT */
#ifdef FT_DEBUG_MEMORY
extern FT_Int
ft_mem_debug_init( FT_Memory memory );
extern void
ft_mem_debug_done( FT_Memory memory );
#endif
/* documentation is in ftobjs.h */
FT_BASE_DEF( FT_Memory )
FT_New_Memory( void )
{
FT_Memory memory;
2000-05-17 01:44:38 +02:00
memory = (FT_Memory)ft_smalloc( sizeof ( *memory ) );
if ( memory )
{
2015-04-11 05:45:11 +02:00
memory->user = NULL;
memory->alloc = ft_alloc;
memory->realloc = ft_realloc;
memory->free = ft_free;
#ifdef FT_DEBUG_MEMORY
ft_mem_debug_init( memory );
#endif
}
return memory;
}
/* documentation is in ftobjs.h */
FT_BASE_DEF( void )
FT_Done_Memory( FT_Memory memory )
{
#ifdef FT_DEBUG_MEMORY
ft_mem_debug_done( memory );
#endif
ft_sfree( memory );
}
2000-07-28 01:29:08 +02:00
/* END */