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