1 /**************************************************************************** 2 * 3 * ftsystem.c 4 * 5 * Unix-specific FreeType low-level system interface (body). 6 * 7 * Copyright (C) 1996-2021 by 8 * David Turner, Robert Wilhelm, and Werner Lemberg. 9 * 10 * This file is part of the FreeType project, and may only be used, 11 * modified, and distributed under the terms of the FreeType project 12 * license, LICENSE.TXT. By continuing to use, modify, or distribute 13 * this file you indicate that you have read the license and 14 * understand and accept it fully. 15 * 16 */ 17 18 19 #include <ft2build.h> 20 /* we use our special ftconfig.h file, not the standard one */ 21 #include FT_CONFIG_CONFIG_H 22 #include <freetype/internal/ftdebug.h> 23 #include <freetype/ftsystem.h> 24 #include <freetype/fterrors.h> 25 #include <freetype/fttypes.h> 26 #include <freetype/internal/ftstream.h> 27 28 /* memory-mapping includes and definitions */ 29 #ifdef HAVE_UNISTD_H 30 #include <unistd.h> 31 #endif 32 33 #include <sys/mman.h> 34 #ifndef MAP_FILE 35 #define MAP_FILE 0x00 36 #endif 37 38 #ifdef MUNMAP_USES_VOIDP 39 #define MUNMAP_ARG_CAST void * 40 #else 41 #define MUNMAP_ARG_CAST char * 42 #endif 43 44 #ifdef NEED_MUNMAP_DECL 45 46 #ifdef __cplusplus 47 extern "C" 48 #else 49 extern 50 #endif 51 int 52 munmap( char* addr, 53 int len ); 54 55 #define MUNMAP_ARG_CAST char * 56 57 #endif /* NEED_DECLARATION_MUNMAP */ 58 59 60 #include <sys/types.h> 61 #include <sys/stat.h> 62 63 #ifdef HAVE_FCNTL_H 64 #include <fcntl.h> 65 #endif 66 67 #include <stdio.h> 68 #include <stdlib.h> 69 #include <string.h> 70 #include <errno.h> 71 72 73 /************************************************************************** 74 * 75 * MEMORY MANAGEMENT INTERFACE 76 * 77 */ 78 79 80 /************************************************************************** 81 * 82 * It is not necessary to do any error checking for the 83 * allocation-related functions. This will be done by the higher level 84 * routines like ft_mem_alloc() or ft_mem_realloc(). 85 * 86 */ 87 88 89 /************************************************************************** 90 * 91 * @Function: 92 * ft_alloc 93 * 94 * @Description: 95 * The memory allocation function. 96 * 97 * @Input: 98 * memory :: 99 * A pointer to the memory object. 100 * 101 * size :: 102 * The requested size in bytes. 103 * 104 * @Return: 105 * The address of newly allocated block. 106 */ 107 FT_CALLBACK_DEF( void* ) ft_alloc(FT_Memory memory,long size)108 ft_alloc( FT_Memory memory, 109 long size ) 110 { 111 FT_UNUSED( memory ); 112 113 return malloc( size ); 114 } 115 116 117 /************************************************************************** 118 * 119 * @Function: 120 * ft_realloc 121 * 122 * @Description: 123 * The memory reallocation function. 124 * 125 * @Input: 126 * memory :: 127 * A pointer to the memory object. 128 * 129 * cur_size :: 130 * The current size of the allocated memory block. 131 * 132 * new_size :: 133 * The newly requested size in bytes. 134 * 135 * block :: 136 * The current address of the block in memory. 137 * 138 * @Return: 139 * The address of the reallocated memory block. 140 */ 141 FT_CALLBACK_DEF( void* ) ft_realloc(FT_Memory memory,long cur_size,long new_size,void * block)142 ft_realloc( FT_Memory memory, 143 long cur_size, 144 long new_size, 145 void* block ) 146 { 147 FT_UNUSED( memory ); 148 FT_UNUSED( cur_size ); 149 150 return realloc( block, new_size ); 151 } 152 153 154 /************************************************************************** 155 * 156 * @Function: 157 * ft_free 158 * 159 * @Description: 160 * The memory release function. 161 * 162 * @Input: 163 * memory :: 164 * A pointer to the memory object. 165 * 166 * block :: 167 * The address of block in memory to be freed. 168 */ 169 FT_CALLBACK_DEF( void ) ft_free(FT_Memory memory,void * block)170 ft_free( FT_Memory memory, 171 void* block ) 172 { 173 FT_UNUSED( memory ); 174 175 free( block ); 176 } 177 178 179 /************************************************************************** 180 * 181 * RESOURCE MANAGEMENT INTERFACE 182 * 183 */ 184 185 186 /************************************************************************** 187 * 188 * The macro FT_COMPONENT is used in trace mode. It is an implicit 189 * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log 190 * messages during execution. 191 */ 192 #undef FT_COMPONENT 193 #define FT_COMPONENT io 194 195 /* We use the macro STREAM_FILE for convenience to extract the */ 196 /* system-specific stream handle from a given FreeType stream object */ 197 #define STREAM_FILE( stream ) ( (FILE*)stream->descriptor.pointer ) 198 199 200 /************************************************************************** 201 * 202 * @Function: 203 * ft_close_stream_by_munmap 204 * 205 * @Description: 206 * The function to close a stream which is opened by mmap. 207 * 208 * @Input: 209 * stream :: A pointer to the stream object. 210 */ 211 FT_CALLBACK_DEF( void ) ft_close_stream_by_munmap(FT_Stream stream)212 ft_close_stream_by_munmap( FT_Stream stream ) 213 { 214 munmap( (MUNMAP_ARG_CAST)stream->descriptor.pointer, stream->size ); 215 216 stream->descriptor.pointer = NULL; 217 stream->size = 0; 218 stream->base = NULL; 219 } 220 221 222 /************************************************************************** 223 * 224 * @Function: 225 * ft_close_stream_by_free 226 * 227 * @Description: 228 * The function to close a stream which is created by ft_alloc. 229 * 230 * @Input: 231 * stream :: A pointer to the stream object. 232 */ 233 FT_CALLBACK_DEF( void ) ft_close_stream_by_free(FT_Stream stream)234 ft_close_stream_by_free( FT_Stream stream ) 235 { 236 ft_free( stream->memory, stream->descriptor.pointer ); 237 238 stream->descriptor.pointer = NULL; 239 stream->size = 0; 240 stream->base = NULL; 241 } 242 243 244 /* documentation is in ftobjs.h */ 245 246 FT_BASE_DEF( FT_Error ) FT_Stream_Open(FT_Stream stream,const char * filepathname)247 FT_Stream_Open( FT_Stream stream, 248 const char* filepathname ) 249 { 250 int file; 251 struct stat stat_buf; 252 253 254 if ( !stream ) 255 return FT_THROW( Invalid_Stream_Handle ); 256 257 /* open the file */ 258 file = open( filepathname, O_RDONLY ); 259 if ( file < 0 ) 260 { 261 FT_ERROR(( "FT_Stream_Open:" )); 262 FT_ERROR(( " could not open `%s'\n", filepathname )); 263 return FT_THROW( Cannot_Open_Resource ); 264 } 265 266 /* Here we ensure that a "fork" will _not_ duplicate */ 267 /* our opened input streams on Unix. This is critical */ 268 /* since it avoids some (possible) access control */ 269 /* issues and cleans up the kernel file table a bit. */ 270 /* */ 271 #ifdef F_SETFD 272 #ifdef FD_CLOEXEC 273 (void)fcntl( file, F_SETFD, FD_CLOEXEC ); 274 #else 275 (void)fcntl( file, F_SETFD, 1 ); 276 #endif /* FD_CLOEXEC */ 277 #endif /* F_SETFD */ 278 279 if ( fstat( file, &stat_buf ) < 0 ) 280 { 281 FT_ERROR(( "FT_Stream_Open:" )); 282 FT_ERROR(( " could not `fstat' file `%s'\n", filepathname )); 283 goto Fail_Map; 284 } 285 286 /* XXX: TODO -- real 64bit platform support */ 287 /* */ 288 /* `stream->size' is typedef'd to unsigned long (in `ftsystem.h'); */ 289 /* `stat_buf.st_size', however, is usually typedef'd to off_t */ 290 /* (in sys/stat.h). */ 291 /* On some platforms, the former is 32bit and the latter is 64bit. */ 292 /* To avoid overflow caused by fonts in huge files larger than */ 293 /* 2GB, do a test. Temporary fix proposed by Sean McBride. */ 294 /* */ 295 if ( stat_buf.st_size > LONG_MAX ) 296 { 297 FT_ERROR(( "FT_Stream_Open: file is too big\n" )); 298 goto Fail_Map; 299 } 300 else if ( stat_buf.st_size == 0 ) 301 { 302 FT_ERROR(( "FT_Stream_Open: zero-length file\n" )); 303 goto Fail_Map; 304 } 305 306 /* This cast potentially truncates a 64bit to 32bit! */ 307 stream->size = (unsigned long)stat_buf.st_size; 308 stream->pos = 0; 309 stream->base = (unsigned char *)mmap( NULL, 310 stream->size, 311 PROT_READ, 312 MAP_FILE | MAP_PRIVATE, 313 file, 314 0 ); 315 316 if ( stream->base != MAP_FAILED ) 317 stream->close = ft_close_stream_by_munmap; 318 else 319 { 320 ssize_t total_read_count; 321 322 323 FT_ERROR(( "FT_Stream_Open:" )); 324 FT_ERROR(( " could not `mmap' file `%s'\n", filepathname )); 325 326 stream->base = (unsigned char*)ft_alloc( stream->memory, stream->size ); 327 328 if ( !stream->base ) 329 { 330 FT_ERROR(( "FT_Stream_Open:" )); 331 FT_ERROR(( " could not `alloc' memory\n" )); 332 goto Fail_Map; 333 } 334 335 total_read_count = 0; 336 do 337 { 338 ssize_t read_count; 339 340 341 read_count = read( file, 342 stream->base + total_read_count, 343 stream->size - total_read_count ); 344 345 if ( read_count <= 0 ) 346 { 347 if ( read_count == -1 && errno == EINTR ) 348 continue; 349 350 FT_ERROR(( "FT_Stream_Open:" )); 351 FT_ERROR(( " error while `read'ing file `%s'\n", filepathname )); 352 goto Fail_Read; 353 } 354 355 total_read_count += read_count; 356 357 } while ( (unsigned long)total_read_count != stream->size ); 358 359 stream->close = ft_close_stream_by_free; 360 } 361 362 close( file ); 363 364 stream->descriptor.pointer = stream->base; 365 stream->pathname.pointer = (char*)filepathname; 366 367 stream->read = NULL; 368 369 FT_TRACE1(( "FT_Stream_Open:" )); 370 FT_TRACE1(( " opened `%s' (%ld bytes) successfully\n", 371 filepathname, stream->size )); 372 373 return FT_Err_Ok; 374 375 Fail_Read: 376 ft_free( stream->memory, stream->base ); 377 378 Fail_Map: 379 close( file ); 380 381 stream->base = NULL; 382 stream->size = 0; 383 stream->pos = 0; 384 385 return FT_THROW( Cannot_Open_Stream ); 386 } 387 388 389 #ifdef FT_DEBUG_MEMORY 390 391 extern FT_Int 392 ft_mem_debug_init( FT_Memory memory ); 393 394 extern void 395 ft_mem_debug_done( FT_Memory memory ); 396 397 #endif 398 399 400 /* documentation is in ftobjs.h */ 401 402 FT_BASE_DEF( FT_Memory ) FT_New_Memory(void)403 FT_New_Memory( void ) 404 { 405 FT_Memory memory; 406 407 408 memory = (FT_Memory)malloc( sizeof ( *memory ) ); 409 if ( memory ) 410 { 411 memory->user = NULL; 412 memory->alloc = ft_alloc; 413 memory->realloc = ft_realloc; 414 memory->free = ft_free; 415 #ifdef FT_DEBUG_MEMORY 416 ft_mem_debug_init( memory ); 417 #endif 418 } 419 420 return memory; 421 } 422 423 424 /* documentation is in ftobjs.h */ 425 426 FT_BASE_DEF( void ) FT_Done_Memory(FT_Memory memory)427 FT_Done_Memory( FT_Memory memory ) 428 { 429 #ifdef FT_DEBUG_MEMORY 430 ft_mem_debug_done( memory ); 431 #endif 432 memory->free( memory, memory ); 433 } 434 435 436 /* END */ 437