1 /***************************************************************************/ 2 /* */ 3 /* ftsystem.c */ 4 /* */ 5 /* Amiga-specific FreeType low-level system interface (body). */ 6 /* */ 7 /* Copyright 1996-2018 by */ 8 /* David Turner, Robert Wilhelm, Werner Lemberg and Detlef Wrkner. */ 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 /* */ 20 /* This file contains the Amiga interface used by FreeType to access */ 21 /* low-level, i.e. memory management, i/o access as well as thread */ 22 /* synchronisation. */ 23 /* */ 24 /*************************************************************************/ 25 26 27 /*************************************************************************/ 28 /* */ 29 /* Maintained by Detlef Wrkner <TetiSoft (at) apg.lahn.de> */ 30 /* */ 31 /* Based on the original ftsystem.c, */ 32 /* modified to avoid fopen(), fclose(), fread(), fseek(), ftell(), */ 33 /* malloc(), realloc(), and free(). */ 34 /* */ 35 /* Those C library functions are often not thread-safe or cant be */ 36 /* used in a shared Amiga library. If that's not a problem for you, */ 37 /* you can of course use the default ftsystem.c with C library calls */ 38 /* instead. */ 39 /* */ 40 /* This implementation needs exec V39+ because it uses AllocPooled() etc */ 41 /* */ 42 /*************************************************************************/ 43 44 #define __NOLIBBASE__ 45 #define __NOGLOBALIFACE__ 46 #define __USE_INLINE__ 47 #include <proto/exec.h> 48 #include <dos/stdio.h> 49 #include <proto/dos.h> 50 #ifdef __amigaos4__ 51 extern struct ExecIFace *IExec; 52 extern struct DOSIFace *IDOS; 53 #else 54 extern struct Library *SysBase; 55 extern struct Library *DOSBase; 56 #endif 57 58 #define IOBUF_SIZE 512 59 60 /* structure that helps us to avoid 61 * useless calls of Seek() and Read() 62 */ 63 struct SysFile 64 { 65 BPTR file; 66 ULONG iobuf_start; 67 ULONG iobuf_end; 68 UBYTE iobuf[IOBUF_SIZE]; 69 }; 70 71 #ifndef __amigaos4__ 72 /* C implementation of AllocVecPooled (see autodoc exec/AllocPooled) */ 73 APTR 74 Alloc_VecPooled( APTR poolHeader, 75 ULONG memSize ) 76 { 77 ULONG newSize = memSize + sizeof ( ULONG ); 78 ULONG *mem = AllocPooled( poolHeader, newSize ); 79 80 if ( !mem ) 81 return NULL; 82 *mem = newSize; 83 return mem + 1; 84 } 85 86 /* C implementation of FreeVecPooled (see autodoc exec/AllocPooled) */ 87 void 88 Free_VecPooled( APTR poolHeader, 89 APTR memory ) 90 { 91 ULONG *realmem = (ULONG *)memory - 1; 92 93 FreePooled( poolHeader, realmem, *realmem ); 94 } 95 #endif 96 97 #include <ft2build.h> 98 #include FT_CONFIG_CONFIG_H 99 #include FT_INTERNAL_DEBUG_H 100 #include FT_SYSTEM_H 101 #include FT_ERRORS_H 102 #include FT_TYPES_H 103 104 #include <stdio.h> 105 #include <stdlib.h> 106 #include <string.h> 107 108 109 /*************************************************************************/ 110 /* */ 111 /* MEMORY MANAGEMENT INTERFACE */ 112 /* */ 113 /*************************************************************************/ 114 115 /*************************************************************************/ 116 /* */ 117 /* It is not necessary to do any error checking for the */ 118 /* allocation-related functions. This is done by the higher level */ 119 /* routines like ft_mem_alloc() or ft_mem_realloc(). */ 120 /* */ 121 /*************************************************************************/ 122 123 124 /*************************************************************************/ 125 /* */ 126 /* <Function> */ 127 /* ft_alloc */ 128 /* */ 129 /* <Description> */ 130 /* The memory allocation function. */ 131 /* */ 132 /* <Input> */ 133 /* memory :: A pointer to the memory object. */ 134 /* */ 135 /* size :: The requested size in bytes. */ 136 /* */ 137 /* <Return> */ 138 /* The address of newly allocated block. */ 139 /* */ 140 FT_CALLBACK_DEF( void* ) 141 ft_alloc( FT_Memory memory, 142 long size ) 143 { 144 #ifdef __amigaos4__ 145 return AllocVecPooled( memory->user, size ); 146 #else 147 return Alloc_VecPooled( memory->user, size ); 148 #endif 149 } 150 151 152 /*************************************************************************/ 153 /* */ 154 /* <Function> */ 155 /* ft_realloc */ 156 /* */ 157 /* <Description> */ 158 /* The memory reallocation function. */ 159 /* */ 160 /* <Input> */ 161 /* memory :: A pointer to the memory object. */ 162 /* */ 163 /* cur_size :: The current size of the allocated memory block. */ 164 /* */ 165 /* new_size :: The newly requested size in bytes. */ 166 /* */ 167 /* block :: The current address of the block in memory. */ 168 /* */ 169 /* <Return> */ 170 /* The address of the reallocated memory block. */ 171 /* */ 172 FT_CALLBACK_DEF( void* ) 173 ft_realloc( FT_Memory memory, 174 long cur_size, 175 long new_size, 176 void* block ) 177 { 178 void* new_block; 179 180 #ifdef __amigaos4__ 181 new_block = AllocVecPooled ( memory->user, new_size ); 182 #else 183 new_block = Alloc_VecPooled ( memory->user, new_size ); 184 #endif 185 if ( new_block != NULL ) 186 { 187 CopyMem ( block, new_block, 188 ( new_size > cur_size ) ? cur_size : new_size ); 189 #ifdef __amigaos4__ 190 FreeVecPooled ( memory->user, block ); 191 #else 192 Free_VecPooled ( memory->user, block ); 193 #endif 194 } 195 return new_block; 196 } 197 198 199 /*************************************************************************/ 200 /* */ 201 /* <Function> */ 202 /* ft_free */ 203 /* */ 204 /* <Description> */ 205 /* The memory release function. */ 206 /* */ 207 /* <Input> */ 208 /* memory :: A pointer to the memory object. */ 209 /* */ 210 /* block :: The address of block in memory to be freed. */ 211 /* */ 212 FT_CALLBACK_DEF( void ) 213 ft_free( FT_Memory memory, 214 void* block ) 215 { 216 #ifdef __amigaos4__ 217 FreeVecPooled( memory->user, block ); 218 #else 219 Free_VecPooled( memory->user, block ); 220 #endif 221 } 222 223 224 /*************************************************************************/ 225 /* */ 226 /* RESOURCE MANAGEMENT INTERFACE */ 227 /* */ 228 /*************************************************************************/ 229 230 231 /*************************************************************************/ 232 /* */ 233 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 234 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 235 /* messages during execution. */ 236 /* */ 237 #undef FT_COMPONENT 238 #define FT_COMPONENT trace_io 239 240 /* We use the macro STREAM_FILE for convenience to extract the */ 241 /* system-specific stream handle from a given FreeType stream object */ 242 #define STREAM_FILE( stream ) ( (struct SysFile *)stream->descriptor.pointer ) 243 244 245 /*************************************************************************/ 246 /* */ 247 /* <Function> */ 248 /* ft_amiga_stream_close */ 249 /* */ 250 /* <Description> */ 251 /* The function to close a stream. */ 252 /* */ 253 /* <Input> */ 254 /* stream :: A pointer to the stream object. */ 255 /* */ 256 FT_CALLBACK_DEF( void ) 257 ft_amiga_stream_close( FT_Stream stream ) 258 { 259 struct SysFile* sysfile; 260 261 sysfile = STREAM_FILE( stream ); 262 Close ( sysfile->file ); 263 FreeMem ( sysfile, sizeof ( struct SysFile )); 264 265 stream->descriptor.pointer = NULL; 266 stream->size = 0; 267 stream->base = 0; 268 } 269 270 271 /*************************************************************************/ 272 /* */ 273 /* <Function> */ 274 /* ft_amiga_stream_io */ 275 /* */ 276 /* <Description> */ 277 /* The function to open a stream. */ 278 /* */ 279 /* <Input> */ 280 /* stream :: A pointer to the stream object. */ 281 /* */ 282 /* offset :: The position in the data stream to start reading. */ 283 /* */ 284 /* buffer :: The address of buffer to store the read data. */ 285 /* */ 286 /* count :: The number of bytes to read from the stream. */ 287 /* */ 288 /* <Return> */ 289 /* The number of bytes actually read. */ 290 /* */ 291 FT_CALLBACK_DEF( unsigned long ) 292 ft_amiga_stream_io( FT_Stream stream, 293 unsigned long offset, 294 unsigned char* buffer, 295 unsigned long count ) 296 { 297 struct SysFile* sysfile; 298 unsigned long read_bytes; 299 300 if ( count != 0 ) 301 { 302 sysfile = STREAM_FILE( stream ); 303 304 /* handle the seek */ 305 if ( (offset < sysfile->iobuf_start) || (offset + count > sysfile->iobuf_end) ) 306 { 307 /* requested offset implies we need a buffer refill */ 308 if ( !sysfile->iobuf_end || offset != sysfile->iobuf_end ) 309 { 310 /* a physical seek is necessary */ 311 Seek( sysfile->file, offset, OFFSET_BEGINNING ); 312 } 313 sysfile->iobuf_start = offset; 314 sysfile->iobuf_end = 0; /* trigger a buffer refill */ 315 } 316 317 /* handle the read */ 318 if ( offset + count <= sysfile->iobuf_end ) 319 { 320 /* we have buffer and requested bytes are all inside our buffer */ 321 CopyMem( &sysfile->iobuf[offset - sysfile->iobuf_start], buffer, count ); 322 read_bytes = count; 323 } 324 else 325 { 326 /* (re)fill buffer */ 327 if ( count <= IOBUF_SIZE ) 328 { 329 /* requested bytes is a subset of the buffer */ 330 read_bytes = Read( sysfile->file, sysfile->iobuf, IOBUF_SIZE ); 331 if ( read_bytes == -1UL ) 332 { 333 /* error */ 334 read_bytes = 0; 335 } 336 else 337 { 338 sysfile->iobuf_end = offset + read_bytes; 339 CopyMem( sysfile->iobuf, buffer, count ); 340 if ( read_bytes > count ) 341 { 342 read_bytes = count; 343 } 344 } 345 } 346 else 347 { 348 /* we actually need more than our buffer can hold, so we decide 349 ** to do a single big read, and then copy the last IOBUF_SIZE 350 ** bytes of that to our internal buffer for later use */ 351 read_bytes = Read( sysfile->file, buffer, count ); 352 if ( read_bytes == -1UL ) 353 { 354 /* error */ 355 read_bytes = 0; 356 } 357 else 358 { 359 ULONG bufsize; 360 361 bufsize = ( read_bytes > IOBUF_SIZE ) ? IOBUF_SIZE : read_bytes; 362 sysfile->iobuf_end = offset + read_bytes; 363 sysfile->iobuf_start = sysfile->iobuf_end - bufsize; 364 CopyMem( &buffer[read_bytes - bufsize] , sysfile->iobuf, bufsize ); 365 } 366 } 367 } 368 } 369 else 370 { 371 read_bytes = 0; 372 } 373 374 return read_bytes; 375 } 376 377 378 /* documentation is in ftobjs.h */ 379 380 FT_BASE_DEF( FT_Error ) 381 FT_Stream_Open( FT_Stream stream, 382 const char* filepathname ) 383 { 384 struct FileInfoBlock* fib; 385 struct SysFile* sysfile; 386 387 388 if ( !stream ) 389 return FT_THROW( Invalid_Stream_Handle ); 390 391 #ifdef __amigaos4__ 392 sysfile = AllocMem ( sizeof (struct SysFile ), MEMF_SHARED ); 393 #else 394 sysfile = AllocMem ( sizeof (struct SysFile ), MEMF_PUBLIC ); 395 #endif 396 if ( !sysfile ) 397 { 398 FT_ERROR(( "FT_Stream_Open:" )); 399 FT_ERROR(( " could not open `%s'\n", filepathname )); 400 401 return FT_THROW( Cannot_Open_Resource ); 402 } 403 sysfile->file = Open( (STRPTR)filepathname, MODE_OLDFILE ); 404 if ( !sysfile->file ) 405 { 406 FreeMem ( sysfile, sizeof ( struct SysFile )); 407 FT_ERROR(( "FT_Stream_Open:" )); 408 FT_ERROR(( " could not open `%s'\n", filepathname )); 409 410 return FT_THROW( Cannot_Open_Resource ); 411 } 412 413 fib = AllocDosObject( DOS_FIB, NULL ); 414 if ( !fib ) 415 { 416 Close ( sysfile->file ); 417 FreeMem ( sysfile, sizeof ( struct SysFile )); 418 FT_ERROR(( "FT_Stream_Open:" )); 419 FT_ERROR(( " could not open `%s'\n", filepathname )); 420 421 return FT_THROW( Cannot_Open_Resource ); 422 } 423 if ( !( ExamineFH( sysfile->file, fib ) ) ) 424 { 425 FreeDosObject( DOS_FIB, fib ); 426 Close ( sysfile->file ); 427 FreeMem ( sysfile, sizeof ( struct SysFile )); 428 FT_ERROR(( "FT_Stream_Open:" )); 429 FT_ERROR(( " could not open `%s'\n", filepathname )); 430 431 return FT_THROW( Cannot_Open_Resource ); 432 } 433 stream->size = fib->fib_Size; 434 FreeDosObject( DOS_FIB, fib ); 435 436 stream->descriptor.pointer = (void *)sysfile; 437 stream->pathname.pointer = (char*)filepathname; 438 sysfile->iobuf_start = 0; 439 sysfile->iobuf_end = 0; 440 stream->pos = 0; 441 442 stream->read = ft_amiga_stream_io; 443 stream->close = ft_amiga_stream_close; 444 445 if ( !stream->size ) 446 { 447 ft_amiga_stream_close( stream ); 448 FT_ERROR(( "FT_Stream_Open:" )); 449 FT_ERROR(( " opened `%s' but zero-sized\n", filepathname )); 450 return FT_THROW( Cannot_Open_Stream ); 451 } 452 453 FT_TRACE1(( "FT_Stream_Open:" )); 454 FT_TRACE1(( " opened `%s' (%ld bytes) successfully\n", 455 filepathname, stream->size )); 456 457 return FT_Err_Ok; 458 } 459 460 461 #ifdef FT_DEBUG_MEMORY 462 463 extern FT_Int 464 ft_mem_debug_init( FT_Memory memory ); 465 466 extern void 467 ft_mem_debug_done( FT_Memory memory ); 468 469 #endif 470 471 472 /* documentation is in ftobjs.h */ 473 474 FT_BASE_DEF( FT_Memory ) 475 FT_New_Memory( void ) 476 { 477 FT_Memory memory; 478 479 480 #ifdef __amigaos4__ 481 memory = (FT_Memory)AllocVec( sizeof ( *memory ), MEMF_SHARED ); 482 #else 483 memory = (FT_Memory)AllocVec( sizeof ( *memory ), MEMF_PUBLIC ); 484 #endif 485 if ( memory ) 486 { 487 #ifdef __amigaos4__ 488 memory->user = CreatePool( MEMF_SHARED, 16384, 16384 ); 489 #else 490 memory->user = CreatePool( MEMF_PUBLIC, 16384, 16384 ); 491 #endif 492 if ( memory->user == NULL ) 493 { 494 FreeVec( memory ); 495 memory = NULL; 496 } 497 else 498 { 499 memory->alloc = ft_alloc; 500 memory->realloc = ft_realloc; 501 memory->free = ft_free; 502 #ifdef FT_DEBUG_MEMORY 503 ft_mem_debug_init( memory ); 504 #endif 505 } 506 } 507 508 return memory; 509 } 510 511 512 /* documentation is in ftobjs.h */ 513 514 FT_BASE_DEF( void ) 515 FT_Done_Memory( FT_Memory memory ) 516 { 517 #ifdef FT_DEBUG_MEMORY 518 ft_mem_debug_done( memory ); 519 #endif 520 521 DeletePool( memory->user ); 522 FreeVec( memory ); 523 } 524 525 /* 526 Local Variables: 527 coding: latin-1 528 End: 529 */ 530 /* END */ 531