/src/freetype/src/lzw/ftlzw.c

https://bitbucket.org/cabalistic/ogredeps/ · C · 413 lines · 240 code · 106 blank · 67 comment · 28 complexity · b90f0caadc3ce08077e98176fc217daa MD5 · raw file

  1. /***************************************************************************/
  2. /* */
  3. /* ftlzw.c */
  4. /* */
  5. /* FreeType support for .Z compressed files. */
  6. /* */
  7. /* This optional component relies on NetBSD's zopen(). It should mainly */
  8. /* be used to parse compressed PCF fonts, as found with many X11 server */
  9. /* distributions. */
  10. /* */
  11. /* Copyright 2004-2006, 2009, 2010, 2012 by */
  12. /* Albert Chin-A-Young. */
  13. /* */
  14. /* Based on code in src/gzip/ftgzip.c, Copyright 2004 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_LZW_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 LZW_Err_
  34. #define FT_ERR_BASE FT_Mod_Err_LZW
  35. #include FT_ERRORS_H
  36. #ifdef FT_CONFIG_OPTION_USE_LZW
  37. #ifdef FT_CONFIG_OPTION_PIC
  38. #error "lzw code does not support PIC yet"
  39. #endif
  40. #include "ftzopen.h"
  41. /***************************************************************************/
  42. /***************************************************************************/
  43. /***** *****/
  44. /***** M E M O R Y M A N A G E M E N T *****/
  45. /***** *****/
  46. /***************************************************************************/
  47. /***************************************************************************/
  48. /***************************************************************************/
  49. /***************************************************************************/
  50. /***** *****/
  51. /***** F I L E D E S C R I P T O R *****/
  52. /***** *****/
  53. /***************************************************************************/
  54. /***************************************************************************/
  55. #define FT_LZW_BUFFER_SIZE 4096
  56. typedef struct FT_LZWFileRec_
  57. {
  58. FT_Stream source; /* parent/source stream */
  59. FT_Stream stream; /* embedding stream */
  60. FT_Memory memory; /* memory allocator */
  61. FT_LzwStateRec lzw; /* lzw decompressor state */
  62. FT_Byte buffer[FT_LZW_BUFFER_SIZE]; /* output buffer */
  63. FT_ULong pos; /* position in output */
  64. FT_Byte* cursor;
  65. FT_Byte* limit;
  66. } FT_LZWFileRec, *FT_LZWFile;
  67. /* check and skip .Z header */
  68. static FT_Error
  69. ft_lzw_check_header( FT_Stream stream )
  70. {
  71. FT_Error error;
  72. FT_Byte head[2];
  73. if ( FT_STREAM_SEEK( 0 ) ||
  74. FT_STREAM_READ( head, 2 ) )
  75. goto Exit;
  76. /* head[0] && head[1] are the magic numbers */
  77. if ( head[0] != 0x1f ||
  78. head[1] != 0x9d )
  79. error = LZW_Err_Invalid_File_Format;
  80. Exit:
  81. return error;
  82. }
  83. static FT_Error
  84. ft_lzw_file_init( FT_LZWFile zip,
  85. FT_Stream stream,
  86. FT_Stream source )
  87. {
  88. FT_LzwState lzw = &zip->lzw;
  89. FT_Error error = LZW_Err_Ok;
  90. zip->stream = stream;
  91. zip->source = source;
  92. zip->memory = stream->memory;
  93. zip->limit = zip->buffer + FT_LZW_BUFFER_SIZE;
  94. zip->cursor = zip->limit;
  95. zip->pos = 0;
  96. /* check and skip .Z header */
  97. error = ft_lzw_check_header( source );
  98. if ( error )
  99. goto Exit;
  100. /* initialize internal lzw variable */
  101. ft_lzwstate_init( lzw, source );
  102. Exit:
  103. return error;
  104. }
  105. static void
  106. ft_lzw_file_done( FT_LZWFile zip )
  107. {
  108. /* clear the rest */
  109. ft_lzwstate_done( &zip->lzw );
  110. zip->memory = NULL;
  111. zip->source = NULL;
  112. zip->stream = NULL;
  113. }
  114. static FT_Error
  115. ft_lzw_file_reset( FT_LZWFile zip )
  116. {
  117. FT_Stream stream = zip->source;
  118. FT_Error error;
  119. if ( !FT_STREAM_SEEK( 0 ) )
  120. {
  121. ft_lzwstate_reset( &zip->lzw );
  122. zip->limit = zip->buffer + FT_LZW_BUFFER_SIZE;
  123. zip->cursor = zip->limit;
  124. zip->pos = 0;
  125. }
  126. return error;
  127. }
  128. static FT_Error
  129. ft_lzw_file_fill_output( FT_LZWFile zip )
  130. {
  131. FT_LzwState lzw = &zip->lzw;
  132. FT_ULong count;
  133. FT_Error error = LZW_Err_Ok;
  134. zip->cursor = zip->buffer;
  135. count = ft_lzwstate_io( lzw, zip->buffer, FT_LZW_BUFFER_SIZE );
  136. zip->limit = zip->cursor + count;
  137. if ( count == 0 )
  138. error = LZW_Err_Invalid_Stream_Operation;
  139. return error;
  140. }
  141. /* fill output buffer; `count' must be <= FT_LZW_BUFFER_SIZE */
  142. static FT_Error
  143. ft_lzw_file_skip_output( FT_LZWFile zip,
  144. FT_ULong count )
  145. {
  146. FT_Error error = LZW_Err_Ok;
  147. /* first, we skip what we can from the output buffer */
  148. {
  149. FT_ULong delta = (FT_ULong)( zip->limit - zip->cursor );
  150. if ( delta >= count )
  151. delta = count;
  152. zip->cursor += delta;
  153. zip->pos += delta;
  154. count -= delta;
  155. }
  156. /* next, we skip as many bytes remaining as possible */
  157. while ( count > 0 )
  158. {
  159. FT_ULong delta = FT_LZW_BUFFER_SIZE;
  160. FT_ULong numread;
  161. if ( delta > count )
  162. delta = count;
  163. numread = ft_lzwstate_io( &zip->lzw, NULL, delta );
  164. if ( numread < delta )
  165. {
  166. /* not enough bytes */
  167. error = LZW_Err_Invalid_Stream_Operation;
  168. break;
  169. }
  170. zip->pos += delta;
  171. count -= delta;
  172. }
  173. return error;
  174. }
  175. static FT_ULong
  176. ft_lzw_file_io( FT_LZWFile zip,
  177. FT_ULong pos,
  178. FT_Byte* buffer,
  179. FT_ULong count )
  180. {
  181. FT_ULong result = 0;
  182. FT_Error error;
  183. /* seeking backwards. */
  184. if ( pos < zip->pos )
  185. {
  186. /* If the new position is within the output buffer, simply */
  187. /* decrement pointers, otherwise we reset the stream completely! */
  188. if ( ( zip->pos - pos ) <= (FT_ULong)( zip->cursor - zip->buffer ) )
  189. {
  190. zip->cursor -= zip->pos - pos;
  191. zip->pos = pos;
  192. }
  193. else
  194. {
  195. error = ft_lzw_file_reset( zip );
  196. if ( error )
  197. goto Exit;
  198. }
  199. }
  200. /* skip unwanted bytes */
  201. if ( pos > zip->pos )
  202. {
  203. error = ft_lzw_file_skip_output( zip, (FT_ULong)( pos - zip->pos ) );
  204. if ( error )
  205. goto Exit;
  206. }
  207. if ( count == 0 )
  208. goto Exit;
  209. /* now read the data */
  210. for (;;)
  211. {
  212. FT_ULong delta;
  213. delta = (FT_ULong)( zip->limit - zip->cursor );
  214. if ( delta >= count )
  215. delta = count;
  216. FT_MEM_COPY( buffer + result, zip->cursor, delta );
  217. result += delta;
  218. zip->cursor += delta;
  219. zip->pos += delta;
  220. count -= delta;
  221. if ( count == 0 )
  222. break;
  223. error = ft_lzw_file_fill_output( zip );
  224. if ( error )
  225. break;
  226. }
  227. Exit:
  228. return result;
  229. }
  230. /***************************************************************************/
  231. /***************************************************************************/
  232. /***** *****/
  233. /***** L Z W E M B E D D I N G S T R E A M *****/
  234. /***** *****/
  235. /***************************************************************************/
  236. /***************************************************************************/
  237. static void
  238. ft_lzw_stream_close( FT_Stream stream )
  239. {
  240. FT_LZWFile zip = (FT_LZWFile)stream->descriptor.pointer;
  241. FT_Memory memory = stream->memory;
  242. if ( zip )
  243. {
  244. /* finalize lzw file descriptor */
  245. ft_lzw_file_done( zip );
  246. FT_FREE( zip );
  247. stream->descriptor.pointer = NULL;
  248. }
  249. }
  250. static FT_ULong
  251. ft_lzw_stream_io( FT_Stream stream,
  252. FT_ULong pos,
  253. FT_Byte* buffer,
  254. FT_ULong count )
  255. {
  256. FT_LZWFile zip = (FT_LZWFile)stream->descriptor.pointer;
  257. return ft_lzw_file_io( zip, pos, buffer, count );
  258. }
  259. FT_EXPORT_DEF( FT_Error )
  260. FT_Stream_OpenLZW( FT_Stream stream,
  261. FT_Stream source )
  262. {
  263. FT_Error error;
  264. FT_Memory memory = source->memory;
  265. FT_LZWFile zip = NULL;
  266. /*
  267. * Check the header right now; this prevents allocation of a huge
  268. * LZWFile object (400 KByte of heap memory) if not necessary.
  269. *
  270. * Did I mention that you should never use .Z compressed font
  271. * files?
  272. */
  273. error = ft_lzw_check_header( source );
  274. if ( error )
  275. goto Exit;
  276. FT_ZERO( stream );
  277. stream->memory = memory;
  278. if ( !FT_NEW( zip ) )
  279. {
  280. error = ft_lzw_file_init( zip, stream, source );
  281. if ( error )
  282. {
  283. FT_FREE( zip );
  284. goto Exit;
  285. }
  286. stream->descriptor.pointer = zip;
  287. }
  288. stream->size = 0x7FFFFFFFL; /* don't know the real size! */
  289. stream->pos = 0;
  290. stream->base = 0;
  291. stream->read = ft_lzw_stream_io;
  292. stream->close = ft_lzw_stream_close;
  293. Exit:
  294. return error;
  295. }
  296. #include "ftzopen.c"
  297. #else /* !FT_CONFIG_OPTION_USE_LZW */
  298. FT_EXPORT_DEF( FT_Error )
  299. FT_Stream_OpenLZW( FT_Stream stream,
  300. FT_Stream source )
  301. {
  302. FT_UNUSED( stream );
  303. FT_UNUSED( source );
  304. return LZW_Err_Unimplemented_Feature;
  305. }
  306. #endif /* !FT_CONFIG_OPTION_USE_LZW */
  307. /* END */