1 /***************************************************************************/ 2 /* */ 3 /* ftsystem.c */ 4 /* */ 5 /* Unix-specific FreeType low-level system interface (body). */ 6 /* */ 7 /* Copyright (C) 1996-2020 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 /* <Function> */ 83 /* ft_alloc */ 84 /* */ 85 /* <Description> */ 86 /* The memory allocation function. */ 87 /* */ 88 /* <Input> */ 89 /* memory :: A pointer to the memory object. */ 90 /* */ 91 /* size :: The requested size in bytes. */ 92 /* */ 93 /* <Return> */ 94 /* The address of newly allocated block. */ 95 /* */ 96 FT_CALLBACK_DEF( void* ) ft_alloc(FT_Memory memory,long size)97 ft_alloc( FT_Memory memory, 98 long size ) 99 { 100 FT_UNUSED( memory ); 101 102 return malloc( size ); 103 } 104 105 106 /*************************************************************************/ 107 /* */ 108 /* <Function> */ 109 /* ft_realloc */ 110 /* */ 111 /* <Description> */ 112 /* The memory reallocation function. */ 113 /* */ 114 /* <Input> */ 115 /* memory :: A pointer to the memory object. */ 116 /* */ 117 /* cur_size :: The current size of the allocated memory block. */ 118 /* */ 119 /* new_size :: The newly requested size in bytes. */ 120 /* */ 121 /* block :: The current address of the block in memory. */ 122 /* */ 123 /* <Return> */ 124 /* The address of the reallocated memory block. */ 125 /* */ 126 FT_CALLBACK_DEF( void* ) ft_realloc(FT_Memory memory,long cur_size,long new_size,void * block)127 ft_realloc( FT_Memory memory, 128 long cur_size, 129 long new_size, 130 void* block ) 131 { 132 FT_UNUSED( memory ); 133 FT_UNUSED( cur_size ); 134 135 return realloc( block, new_size ); 136 } 137 138 139 /*************************************************************************/ 140 /* */ 141 /* <Function> */ 142 /* ft_free */ 143 /* */ 144 /* <Description> */ 145 /* The memory release function. */ 146 /* */ 147 /* <Input> */ 148 /* memory :: A pointer to the memory object. */ 149 /* */ 150 /* block :: The address of block in memory to be freed. */ 151 /* */ 152 FT_CALLBACK_DEF( void ) ft_free(FT_Memory memory,void * block)153 ft_free( FT_Memory memory, 154 void* block ) 155 { 156 FT_UNUSED( memory ); 157 158 free( block ); 159 } 160 161 162 /*************************************************************************/ 163 /* */ 164 /* RESOURCE MANAGEMENT INTERFACE */ 165 /* */ 166 /*************************************************************************/ 167 168 169 /*************************************************************************/ 170 /* */ 171 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 172 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 173 /* messages during execution. */ 174 /* */ 175 #undef FT_COMPONENT 176 #define FT_COMPONENT io 177 178 /* We use the macro STREAM_FILE for convenience to extract the */ 179 /* system-specific stream handle from a given FreeType stream object */ 180 #define STREAM_FILE( stream ) ( (FILE*)stream->descriptor.pointer ) 181 182 183 /*************************************************************************/ 184 /* */ 185 /* <Function> */ 186 /* ft_close_stream_by_munmap */ 187 /* */ 188 /* <Description> */ 189 /* The function to close a stream which is opened by mmap. */ 190 /* */ 191 /* <Input> */ 192 /* stream :: A pointer to the stream object. */ 193 /* */ 194 FT_CALLBACK_DEF( void ) ft_close_stream_by_munmap(FT_Stream stream)195 ft_close_stream_by_munmap( FT_Stream stream ) 196 { 197 munmap( (MUNMAP_ARG_CAST)stream->descriptor.pointer, stream->size ); 198 199 stream->descriptor.pointer = NULL; 200 stream->size = 0; 201 stream->base = 0; 202 } 203 204 205 /*************************************************************************/ 206 /* */ 207 /* <Function> */ 208 /* ft_close_stream_by_free */ 209 /* */ 210 /* <Description> */ 211 /* The function to close a stream which is created by ft_alloc. */ 212 /* */ 213 /* <Input> */ 214 /* stream :: A pointer to the stream object. */ 215 /* */ 216 FT_CALLBACK_DEF( void ) ft_close_stream_by_free(FT_Stream stream)217 ft_close_stream_by_free( FT_Stream stream ) 218 { 219 ft_free( NULL, stream->descriptor.pointer ); 220 221 stream->descriptor.pointer = NULL; 222 stream->size = 0; 223 stream->base = 0; 224 } 225 226 227 /* documentation is in ftobjs.h */ 228 229 FT_BASE_DEF( FT_Error ) FT_Stream_Open(FT_Stream stream,const char * filepathname)230 FT_Stream_Open( FT_Stream stream, 231 const char* filepathname ) 232 { 233 int file; 234 struct stat stat_buf; 235 236 237 if ( !stream ) 238 return FT_THROW( Invalid_Stream_Handle ); 239 240 /* open the file */ 241 file = open( filepathname, O_RDONLY ); 242 if ( file < 0 ) 243 { 244 FT_ERROR(( "FT_Stream_Open:" )); 245 FT_ERROR(( " could not open `%s'\n", filepathname )); 246 return FT_THROW( Cannot_Open_Resource ); 247 } 248 249 /* Here we ensure that a "fork" will _not_ duplicate */ 250 /* our opened input streams on Unix. This is critical */ 251 /* since it avoids some (possible) access control */ 252 /* issues and cleans up the kernel file table a bit. */ 253 /* */ 254 #ifdef F_SETFD 255 #ifdef FD_CLOEXEC 256 (void)fcntl( file, F_SETFD, FD_CLOEXEC ); 257 #else 258 (void)fcntl( file, F_SETFD, 1 ); 259 #endif /* FD_CLOEXEC */ 260 #endif /* F_SETFD */ 261 262 if ( fstat( file, &stat_buf ) < 0 ) 263 { 264 FT_ERROR(( "FT_Stream_Open:" )); 265 FT_ERROR(( " could not `fstat' file `%s'\n", filepathname )); 266 goto Fail_Map; 267 } 268 269 /* XXX: TODO -- real 64bit platform support */ 270 /* */ 271 /* `stream->size' is typedef'd to unsigned long (in `ftsystem.h'); */ 272 /* `stat_buf.st_size', however, is usually typedef'd to off_t */ 273 /* (in sys/stat.h). */ 274 /* On some platforms, the former is 32bit and the latter is 64bit. */ 275 /* To avoid overflow caused by fonts in huge files larger than */ 276 /* 2GB, do a test. Temporary fix proposed by Sean McBride. */ 277 /* */ 278 if ( stat_buf.st_size > LONG_MAX ) 279 { 280 FT_ERROR(( "FT_Stream_Open: file is too big\n" )); 281 goto Fail_Map; 282 } 283 else if ( stat_buf.st_size == 0 ) 284 { 285 FT_ERROR(( "FT_Stream_Open: zero-length file\n" )); 286 goto Fail_Map; 287 } 288 289 /* This cast potentially truncates a 64bit to 32bit! */ 290 stream->size = (unsigned long)stat_buf.st_size; 291 stream->pos = 0; 292 stream->base = (unsigned char *)mmap( NULL, 293 stream->size, 294 PROT_READ, 295 MAP_FILE | MAP_PRIVATE, 296 file, 297 0 ); 298 299 /* on some RTOS, mmap might return 0 */ 300 if ( (long)stream->base != -1 && stream->base != NULL ) 301 stream->close = ft_close_stream_by_munmap; 302 else 303 { 304 ssize_t total_read_count; 305 306 307 FT_ERROR(( "FT_Stream_Open:" )); 308 FT_ERROR(( " could not `mmap' file `%s'\n", filepathname )); 309 310 stream->base = (unsigned char*)ft_alloc( NULL, stream->size ); 311 312 if ( !stream->base ) 313 { 314 FT_ERROR(( "FT_Stream_Open:" )); 315 FT_ERROR(( " could not `alloc' memory\n" )); 316 goto Fail_Map; 317 } 318 319 total_read_count = 0; 320 do 321 { 322 ssize_t read_count; 323 324 325 read_count = read( file, 326 stream->base + total_read_count, 327 stream->size - total_read_count ); 328 329 if ( read_count <= 0 ) 330 { 331 if ( read_count == -1 && errno == EINTR ) 332 continue; 333 334 FT_ERROR(( "FT_Stream_Open:" )); 335 FT_ERROR(( " error while `read'ing file `%s'\n", filepathname )); 336 goto Fail_Read; 337 } 338 339 total_read_count += read_count; 340 341 } while ( (unsigned long)total_read_count != stream->size ); 342 343 stream->close = ft_close_stream_by_free; 344 } 345 346 close( file ); 347 348 stream->descriptor.pointer = stream->base; 349 stream->pathname.pointer = (char*)filepathname; 350 351 stream->read = 0; 352 353 FT_TRACE1(( "FT_Stream_Open:" )); 354 FT_TRACE1(( " opened `%s' (%ld bytes) successfully\n", 355 filepathname, stream->size )); 356 357 return FT_Err_Ok; 358 359 Fail_Read: 360 ft_free( NULL, stream->base ); 361 362 Fail_Map: 363 close( file ); 364 365 stream->base = NULL; 366 stream->size = 0; 367 stream->pos = 0; 368 369 return FT_THROW( Cannot_Open_Stream ); 370 } 371 372 373 #ifdef FT_DEBUG_MEMORY 374 375 extern FT_Int 376 ft_mem_debug_init( FT_Memory memory ); 377 378 extern void 379 ft_mem_debug_done( FT_Memory memory ); 380 381 #endif 382 383 384 /* documentation is in ftobjs.h */ 385 386 FT_BASE_DEF( FT_Memory ) FT_New_Memory(void)387 FT_New_Memory( void ) 388 { 389 FT_Memory memory; 390 391 392 memory = (FT_Memory)malloc( sizeof ( *memory ) ); 393 if ( memory ) 394 { 395 memory->user = 0; 396 memory->alloc = ft_alloc; 397 memory->realloc = ft_realloc; 398 memory->free = ft_free; 399 #ifdef FT_DEBUG_MEMORY 400 ft_mem_debug_init( memory ); 401 #endif 402 } 403 404 return memory; 405 } 406 407 408 /* documentation is in ftobjs.h */ 409 410 FT_BASE_DEF( void ) FT_Done_Memory(FT_Memory memory)411 FT_Done_Memory( FT_Memory memory ) 412 { 413 #ifdef FT_DEBUG_MEMORY 414 ft_mem_debug_done( memory ); 415 #endif 416 memory->free( memory, memory ); 417 } 418 419 420 /* END */ 421