/src/freetype/src/bzip2/ftbzip2.c

https://bitbucket.org/cabalistic/ogredeps/ · C · 511 lines · 322 code · 126 blank · 63 comment · 48 complexity · 63c695fd7d6af94e321e7ae7664b6571 MD5 · raw file

  1. /***************************************************************************/
  2. /* */
  3. /* ftbzip2.c */
  4. /* */
  5. /* FreeType support for .bz2 compressed files. */
  6. /* */
  7. /* This optional component relies on libbz2. It should mainly be used to */
  8. /* parse compressed PCF fonts, as found with many X11 server */
  9. /* distributions. */
  10. /* */
  11. /* Copyright 2010, 2012 by */
  12. /* Joel Klinghed. */
  13. /* */
  14. /* Based on src/gzip/ftgzip.c, Copyright 2002 - 2010 by */
  15. /* David Turner, Robert Wilhelm, and Werner Lemberg. */
  16. /* */
  17. /* This file is part of the FreeType project, and may only be used, */
  18. /* modified, and distributed under the terms of the FreeType project */
  19. /* license, LICENSE.TXT. By continuing to use, modify, or distribute */
  20. /* this file you indicate that you have read the license and */
  21. /* understand and accept it fully. */
  22. /* */
  23. /***************************************************************************/
  24. #include <ft2build.h>
  25. #include FT_INTERNAL_MEMORY_H
  26. #include FT_INTERNAL_STREAM_H
  27. #include FT_INTERNAL_DEBUG_H
  28. #include FT_BZIP2_H
  29. #include FT_CONFIG_STANDARD_LIBRARY_H
  30. #include FT_MODULE_ERRORS_H
  31. #undef __FTERRORS_H__
  32. #undef FT_ERR_PREFIX
  33. #define FT_ERR_PREFIX Bzip2_Err_
  34. #define FT_ERR_BASE FT_Mod_Err_Bzip2
  35. #include FT_ERRORS_H
  36. #ifdef FT_CONFIG_OPTION_USE_BZIP2
  37. #ifdef FT_CONFIG_OPTION_PIC
  38. #error "bzip2 code does not support PIC yet"
  39. #endif
  40. #define BZ_NO_STDIO /* Do not need FILE */
  41. #include <bzlib.h>
  42. /***************************************************************************/
  43. /***************************************************************************/
  44. /***** *****/
  45. /***** B Z I P 2 M E M O R Y M A N A G E M E N T *****/
  46. /***** *****/
  47. /***************************************************************************/
  48. /***************************************************************************/
  49. /* it is better to use FreeType memory routines instead of raw
  50. 'malloc/free' */
  51. typedef void *(* alloc_func)(void*, int, int);
  52. typedef void (* free_func)(void*, void*);
  53. static void*
  54. ft_bzip2_alloc( FT_Memory memory,
  55. int items,
  56. int size )
  57. {
  58. FT_ULong sz = (FT_ULong)size * items;
  59. FT_Error error;
  60. FT_Pointer p = NULL;
  61. (void)FT_ALLOC( p, sz );
  62. return p;
  63. }
  64. static void
  65. ft_bzip2_free( FT_Memory memory,
  66. void* address )
  67. {
  68. FT_MEM_FREE( address );
  69. }
  70. /***************************************************************************/
  71. /***************************************************************************/
  72. /***** *****/
  73. /***** B Z I P 2 F I L E D E S C R I P T O R *****/
  74. /***** *****/
  75. /***************************************************************************/
  76. /***************************************************************************/
  77. #define FT_BZIP2_BUFFER_SIZE 4096
  78. typedef struct FT_BZip2FileRec_
  79. {
  80. FT_Stream source; /* parent/source stream */
  81. FT_Stream stream; /* embedding stream */
  82. FT_Memory memory; /* memory allocator */
  83. bz_stream bzstream; /* bzlib input stream */
  84. FT_Byte input[FT_BZIP2_BUFFER_SIZE]; /* input read buffer */
  85. FT_Byte buffer[FT_BZIP2_BUFFER_SIZE]; /* output buffer */
  86. FT_ULong pos; /* position in output */
  87. FT_Byte* cursor;
  88. FT_Byte* limit;
  89. } FT_BZip2FileRec, *FT_BZip2File;
  90. /* check and skip .bz2 header - we don't support `transparent' compression */
  91. static FT_Error
  92. ft_bzip2_check_header( FT_Stream stream )
  93. {
  94. FT_Error error = Bzip2_Err_Ok;
  95. FT_Byte head[4];
  96. if ( FT_STREAM_SEEK( 0 ) ||
  97. FT_STREAM_READ( head, 4 ) )
  98. goto Exit;
  99. /* head[0] && head[1] are the magic numbers; */
  100. /* head[2] is the version, and head[3] the blocksize */
  101. if ( head[0] != 0x42 ||
  102. head[1] != 0x5a ||
  103. head[2] != 0x68 ) /* only support bzip2 (huffman) */
  104. {
  105. error = Bzip2_Err_Invalid_File_Format;
  106. goto Exit;
  107. }
  108. Exit:
  109. return error;
  110. }
  111. static FT_Error
  112. ft_bzip2_file_init( FT_BZip2File zip,
  113. FT_Stream stream,
  114. FT_Stream source )
  115. {
  116. bz_stream* bzstream = &zip->bzstream;
  117. FT_Error error = Bzip2_Err_Ok;
  118. zip->stream = stream;
  119. zip->source = source;
  120. zip->memory = stream->memory;
  121. zip->limit = zip->buffer + FT_BZIP2_BUFFER_SIZE;
  122. zip->cursor = zip->limit;
  123. zip->pos = 0;
  124. /* check .bz2 header */
  125. {
  126. stream = source;
  127. error = ft_bzip2_check_header( stream );
  128. if ( error )
  129. goto Exit;
  130. if ( FT_STREAM_SEEK( 0 ) )
  131. goto Exit;
  132. }
  133. /* initialize bzlib */
  134. bzstream->bzalloc = (alloc_func)ft_bzip2_alloc;
  135. bzstream->bzfree = (free_func) ft_bzip2_free;
  136. bzstream->opaque = zip->memory;
  137. bzstream->avail_in = 0;
  138. bzstream->next_in = (char*)zip->buffer;
  139. if ( BZ2_bzDecompressInit( bzstream, 0, 0 ) != BZ_OK ||
  140. bzstream->next_in == NULL )
  141. error = Bzip2_Err_Invalid_File_Format;
  142. Exit:
  143. return error;
  144. }
  145. static void
  146. ft_bzip2_file_done( FT_BZip2File zip )
  147. {
  148. bz_stream* bzstream = &zip->bzstream;
  149. BZ2_bzDecompressEnd( bzstream );
  150. /* clear the rest */
  151. bzstream->bzalloc = NULL;
  152. bzstream->bzfree = NULL;
  153. bzstream->opaque = NULL;
  154. bzstream->next_in = NULL;
  155. bzstream->next_out = NULL;
  156. bzstream->avail_in = 0;
  157. bzstream->avail_out = 0;
  158. zip->memory = NULL;
  159. zip->source = NULL;
  160. zip->stream = NULL;
  161. }
  162. static FT_Error
  163. ft_bzip2_file_reset( FT_BZip2File zip )
  164. {
  165. FT_Stream stream = zip->source;
  166. FT_Error error;
  167. if ( !FT_STREAM_SEEK( 0 ) )
  168. {
  169. bz_stream* bzstream = &zip->bzstream;
  170. BZ2_bzDecompressEnd( bzstream );
  171. bzstream->avail_in = 0;
  172. bzstream->next_in = (char*)zip->input;
  173. bzstream->avail_out = 0;
  174. bzstream->next_out = (char*)zip->buffer;
  175. zip->limit = zip->buffer + FT_BZIP2_BUFFER_SIZE;
  176. zip->cursor = zip->limit;
  177. zip->pos = 0;
  178. BZ2_bzDecompressInit( bzstream, 0, 0 );
  179. }
  180. return error;
  181. }
  182. static FT_Error
  183. ft_bzip2_file_fill_input( FT_BZip2File zip )
  184. {
  185. bz_stream* bzstream = &zip->bzstream;
  186. FT_Stream stream = zip->source;
  187. FT_ULong size;
  188. if ( stream->read )
  189. {
  190. size = stream->read( stream, stream->pos, zip->input,
  191. FT_BZIP2_BUFFER_SIZE );
  192. if ( size == 0 )
  193. return Bzip2_Err_Invalid_Stream_Operation;
  194. }
  195. else
  196. {
  197. size = stream->size - stream->pos;
  198. if ( size > FT_BZIP2_BUFFER_SIZE )
  199. size = FT_BZIP2_BUFFER_SIZE;
  200. if ( size == 0 )
  201. return Bzip2_Err_Invalid_Stream_Operation;
  202. FT_MEM_COPY( zip->input, stream->base + stream->pos, size );
  203. }
  204. stream->pos += size;
  205. bzstream->next_in = (char*)zip->input;
  206. bzstream->avail_in = size;
  207. return Bzip2_Err_Ok;
  208. }
  209. static FT_Error
  210. ft_bzip2_file_fill_output( FT_BZip2File zip )
  211. {
  212. bz_stream* bzstream = &zip->bzstream;
  213. FT_Error error = Bzip2_Err_Ok;
  214. zip->cursor = zip->buffer;
  215. bzstream->next_out = (char*)zip->cursor;
  216. bzstream->avail_out = FT_BZIP2_BUFFER_SIZE;
  217. while ( bzstream->avail_out > 0 )
  218. {
  219. int err;
  220. if ( bzstream->avail_in == 0 )
  221. {
  222. error = ft_bzip2_file_fill_input( zip );
  223. if ( error )
  224. break;
  225. }
  226. err = BZ2_bzDecompress( bzstream );
  227. if ( err == BZ_STREAM_END )
  228. {
  229. zip->limit = (FT_Byte*)bzstream->next_out;
  230. if ( zip->limit == zip->cursor )
  231. error = Bzip2_Err_Invalid_Stream_Operation;
  232. break;
  233. }
  234. else if ( err != BZ_OK )
  235. {
  236. error = Bzip2_Err_Invalid_Stream_Operation;
  237. break;
  238. }
  239. }
  240. return error;
  241. }
  242. /* fill output buffer; `count' must be <= FT_BZIP2_BUFFER_SIZE */
  243. static FT_Error
  244. ft_bzip2_file_skip_output( FT_BZip2File zip,
  245. FT_ULong count )
  246. {
  247. FT_Error error = Bzip2_Err_Ok;
  248. FT_ULong delta;
  249. for (;;)
  250. {
  251. delta = (FT_ULong)( zip->limit - zip->cursor );
  252. if ( delta >= count )
  253. delta = count;
  254. zip->cursor += delta;
  255. zip->pos += delta;
  256. count -= delta;
  257. if ( count == 0 )
  258. break;
  259. error = ft_bzip2_file_fill_output( zip );
  260. if ( error )
  261. break;
  262. }
  263. return error;
  264. }
  265. static FT_ULong
  266. ft_bzip2_file_io( FT_BZip2File zip,
  267. FT_ULong pos,
  268. FT_Byte* buffer,
  269. FT_ULong count )
  270. {
  271. FT_ULong result = 0;
  272. FT_Error error;
  273. /* Reset inflate stream if we're seeking backwards. */
  274. /* Yes, that is not too efficient, but it saves memory :-) */
  275. if ( pos < zip->pos )
  276. {
  277. error = ft_bzip2_file_reset( zip );
  278. if ( error )
  279. goto Exit;
  280. }
  281. /* skip unwanted bytes */
  282. if ( pos > zip->pos )
  283. {
  284. error = ft_bzip2_file_skip_output( zip, (FT_ULong)( pos - zip->pos ) );
  285. if ( error )
  286. goto Exit;
  287. }
  288. if ( count == 0 )
  289. goto Exit;
  290. /* now read the data */
  291. for (;;)
  292. {
  293. FT_ULong delta;
  294. delta = (FT_ULong)( zip->limit - zip->cursor );
  295. if ( delta >= count )
  296. delta = count;
  297. FT_MEM_COPY( buffer, zip->cursor, delta );
  298. buffer += delta;
  299. result += delta;
  300. zip->cursor += delta;
  301. zip->pos += delta;
  302. count -= delta;
  303. if ( count == 0 )
  304. break;
  305. error = ft_bzip2_file_fill_output( zip );
  306. if ( error )
  307. break;
  308. }
  309. Exit:
  310. return result;
  311. }
  312. /***************************************************************************/
  313. /***************************************************************************/
  314. /***** *****/
  315. /***** B Z E M B E D D I N G S T R E A M *****/
  316. /***** *****/
  317. /***************************************************************************/
  318. /***************************************************************************/
  319. static void
  320. ft_bzip2_stream_close( FT_Stream stream )
  321. {
  322. FT_BZip2File zip = (FT_BZip2File)stream->descriptor.pointer;
  323. FT_Memory memory = stream->memory;
  324. if ( zip )
  325. {
  326. /* finalize bzip file descriptor */
  327. ft_bzip2_file_done( zip );
  328. FT_FREE( zip );
  329. stream->descriptor.pointer = NULL;
  330. }
  331. }
  332. static FT_ULong
  333. ft_bzip2_stream_io( FT_Stream stream,
  334. FT_ULong pos,
  335. FT_Byte* buffer,
  336. FT_ULong count )
  337. {
  338. FT_BZip2File zip = (FT_BZip2File)stream->descriptor.pointer;
  339. return ft_bzip2_file_io( zip, pos, buffer, count );
  340. }
  341. FT_EXPORT_DEF( FT_Error )
  342. FT_Stream_OpenBzip2( FT_Stream stream,
  343. FT_Stream source )
  344. {
  345. FT_Error error;
  346. FT_Memory memory = source->memory;
  347. FT_BZip2File zip = NULL;
  348. /*
  349. * check the header right now; this prevents allocating unnecessary
  350. * objects when we don't need them
  351. */
  352. error = ft_bzip2_check_header( source );
  353. if ( error )
  354. goto Exit;
  355. FT_ZERO( stream );
  356. stream->memory = memory;
  357. if ( !FT_QNEW( zip ) )
  358. {
  359. error = ft_bzip2_file_init( zip, stream, source );
  360. if ( error )
  361. {
  362. FT_FREE( zip );
  363. goto Exit;
  364. }
  365. stream->descriptor.pointer = zip;
  366. }
  367. stream->size = 0x7FFFFFFFL; /* don't know the real size! */
  368. stream->pos = 0;
  369. stream->base = 0;
  370. stream->read = ft_bzip2_stream_io;
  371. stream->close = ft_bzip2_stream_close;
  372. Exit:
  373. return error;
  374. }
  375. #else /* !FT_CONFIG_OPTION_USE_BZIP2 */
  376. FT_EXPORT_DEF( FT_Error )
  377. FT_Stream_OpenBzip2( FT_Stream stream,
  378. FT_Stream source )
  379. {
  380. FT_UNUSED( stream );
  381. FT_UNUSED( source );
  382. return Bzip2_Err_Unimplemented_Feature;
  383. }
  384. #endif /* !FT_CONFIG_OPTION_USE_BZIP2 */
  385. /* END */