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 |
|
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* ) |
|
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* ) |
|
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 ) |
|
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 trace_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 ) |
|
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 ) |
|
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 ) |
|
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_Err_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_Err_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 */ |
|
272 /* freetype/ftsystem.h); `stat_buf.st_size', however, is usually */ |
|
273 /* typedef'd to off_t (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 ssize_t read_count; |
|
322 |
|
323 |
|
324 read_count = read( file, |
|
325 stream->base + total_read_count, |
|
326 stream->size - total_read_count ); |
|
327 |
|
328 if ( read_count <= 0 ) |
|
329 { |
|
330 if ( read_count == -1 && errno == EINTR ) |
|
331 continue; |
|
332 |
|
333 FT_ERROR(( "FT_Stream_Open:" )); |
|
334 FT_ERROR(( " error while `read'ing file `%s'\n", filepathname )); |
|
335 goto Fail_Read; |
|
336 } |
|
337 |
|
338 total_read_count += read_count; |
|
339 |
|
340 } while ( (unsigned long)total_read_count != stream->size ); |
|
341 |
|
342 stream->close = ft_close_stream_by_free; |
|
343 } |
|
344 |
|
345 close( file ); |
|
346 |
|
347 stream->descriptor.pointer = stream->base; |
|
348 stream->pathname.pointer = (char*)filepathname; |
|
349 |
|
350 stream->read = 0; |
|
351 |
|
352 FT_TRACE1(( "FT_Stream_Open:" )); |
|
353 FT_TRACE1(( " opened `%s' (%d bytes) successfully\n", |
|
354 filepathname, stream->size )); |
|
355 |
|
356 return FT_Err_Ok; |
|
357 |
|
358 Fail_Read: |
|
359 ft_free( NULL, stream->base ); |
|
360 |
|
361 Fail_Map: |
|
362 close( file ); |
|
363 |
|
364 stream->base = NULL; |
|
365 stream->size = 0; |
|
366 stream->pos = 0; |
|
367 |
|
368 return FT_Err_Cannot_Open_Stream; |
|
369 } |
|
370 |
|
371 |
|
372 #ifdef FT_DEBUG_MEMORY |
|
373 |
|
374 extern FT_Int |
|
375 ft_mem_debug_init( FT_Memory memory ); |
|
376 |
|
377 extern void |
|
378 ft_mem_debug_done( FT_Memory memory ); |
|
379 |
|
380 #endif |
|
381 |
|
382 |
|
383 /* documentation is in ftobjs.h */ |
|
384 |
|
385 FT_BASE_DEF( FT_Memory ) |
|
386 FT_New_Memory( void ) |
|
387 { |
|
388 FT_Memory memory; |
|
389 |
|
390 |
|
391 memory = (FT_Memory)malloc( sizeof ( *memory ) ); |
|
392 if ( memory ) |
|
393 { |
|
394 memory->user = 0; |
|
395 memory->alloc = ft_alloc; |
|
396 memory->realloc = ft_realloc; |
|
397 memory->free = ft_free; |
|
398 #ifdef FT_DEBUG_MEMORY |
|
399 ft_mem_debug_init( memory ); |
|
400 #endif |
|
401 } |
|
402 |
|
403 return memory; |
|
404 } |
|
405 |
|
406 |
|
407 /* documentation is in ftobjs.h */ |
|
408 |
|
409 FT_BASE_DEF( void ) |
|
410 FT_Done_Memory( FT_Memory memory ) |
|
411 { |
|
412 #ifdef FT_DEBUG_MEMORY |
|
413 ft_mem_debug_done( memory ); |
|
414 #endif |
|
415 memory->free( memory, memory ); |
|
416 } |
|
417 |
|
418 |
|
419 /* END */ |
|