You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

277 lines
5.6 KiB

  1. /*
  2. * libcucul Canvas for ultrafast compositing of Unicode letters
  3. * Copyright (c) 2006-2007 Sam Hocevar <sam@zoy.org>
  4. * All Rights Reserved
  5. *
  6. * $Id$
  7. *
  8. * This library is free software. It comes without any warranty, to
  9. * the extent permitted by applicable law. You can redistribute it
  10. * and/or modify it under the terms of the Do What The Fuck You Want
  11. * To Public License, Version 2, as published by Sam Hocevar. See
  12. * http://sam.zoy.org/wtfpl/COPYING for more details.
  13. */
  14. /*
  15. * This file contains functions for compressed file I/O.
  16. */
  17. #include "config.h"
  18. #if !defined __KERNEL__
  19. # include <stdio.h>
  20. # include <stdlib.h>
  21. # include <string.h>
  22. # if defined HAVE_ZLIB_H
  23. # include <zlib.h>
  24. # define READSIZE 128 /* Read buffer size */
  25. # define WRITESIZE 128 /* Inflate buffer size */
  26. # endif
  27. #endif
  28. #include "cucul.h"
  29. #include "cucul_internals.h"
  30. #if !defined __KERNEL__ && defined HAVE_ZLIB_H
  31. static int zipread(cucul_file_t *, void *, unsigned int);
  32. #endif
  33. #if !defined __KERNEL__
  34. struct cucul_file
  35. {
  36. # if defined HAVE_ZLIB_H
  37. uint8_t read_buffer[READSIZE];
  38. z_stream stream;
  39. gzFile gz;
  40. int eof, zip, total;
  41. # endif
  42. FILE *f;
  43. int readonly;
  44. };
  45. #endif
  46. cucul_file_t *cucul_file_open(char const *path, const char *mode)
  47. {
  48. #if defined __KERNEL__
  49. return NULL;
  50. #else
  51. cucul_file_t *fp = malloc(sizeof(*fp));
  52. fp->readonly = strchr(mode, 'r');
  53. # if defined HAVE_ZLIB_H
  54. uint8_t buf[4];
  55. unsigned int skip_size = 0;
  56. fp->gz = gzopen(path, fp->readonly ? "rb" : "wb");
  57. if(!fp->gz)
  58. {
  59. free(fp);
  60. return NULL;
  61. }
  62. fp->eof = 0;
  63. fp->zip = 0;
  64. fp->total = 0;
  65. if(fp->readonly)
  66. {
  67. /* Parse ZIP file and go to start of first file */
  68. gzread(fp->gz, buf, 4);
  69. if(memcmp(buf, "PK\3\4", 4))
  70. {
  71. gzseek(fp->gz, 0, SEEK_SET);
  72. return fp;
  73. }
  74. fp->zip = 1;
  75. gzseek(fp->gz, 22, SEEK_CUR);
  76. gzread(fp->gz, buf, 2); /* Filename size */
  77. skip_size += (uint16_t)buf[0] | ((uint16_t)buf[1] << 8);
  78. gzread(fp->gz, buf, 2); /* Extra field size */
  79. skip_size += (uint16_t)buf[0] | ((uint16_t)buf[1] << 8);
  80. gzseek(fp->gz, skip_size, SEEK_CUR);
  81. /* Initialise inflate stream */
  82. fp->stream.total_out = 0;
  83. fp->stream.zalloc = NULL;
  84. fp->stream.zfree = NULL;
  85. fp->stream.opaque = NULL;
  86. fp->stream.next_in = NULL;
  87. fp->stream.avail_in = 0;
  88. if(inflateInit2(&fp->stream, -MAX_WBITS))
  89. {
  90. free(fp);
  91. gzclose(fp->gz);
  92. return NULL;
  93. }
  94. }
  95. # else
  96. fp->f = fopen(path, fmode);
  97. if(!fp->f)
  98. {
  99. free(fp);
  100. return NULL;
  101. }
  102. # endif
  103. return fp;
  104. #endif
  105. }
  106. int cucul_file_close(cucul_file_t *fp)
  107. {
  108. #if defined __KERNEL__
  109. return 0;
  110. #elif defined HAVE_ZLIB_H
  111. gzFile gz = fp->gz;
  112. if(fp->zip)
  113. inflateEnd(&fp->stream);
  114. free(fp);
  115. return gzclose(gz);
  116. #else
  117. FILE *f = fp->f;
  118. free(fp);
  119. return fclose(f);
  120. #endif
  121. }
  122. uint64_t cucul_file_tell(cucul_file_t *fp)
  123. {
  124. #if defined __KERNEL__
  125. return 0;
  126. #elif defined HAVE_ZLIB_H
  127. if(fp->zip)
  128. return fp->total;
  129. return gztell(fp->gz);
  130. #else
  131. return ftell(fp->f);
  132. #endif
  133. }
  134. size_t cucul_file_read(cucul_file_t *fp, void *ptr, size_t size)
  135. {
  136. #if defined __KERNEL__
  137. return 0;
  138. #elif defined HAVE_ZLIB_H
  139. if(fp->zip)
  140. return zipread(fp, ptr, size);
  141. return gzread(fp->gz, ptr, size);
  142. #else
  143. return fread(ptr, 1, size, fp->f);
  144. #endif
  145. }
  146. size_t cucul_file_write(cucul_file_t *fp, const void *ptr, size_t size)
  147. {
  148. if(fp->readonly)
  149. return 0;
  150. #if defined __KERNEL__
  151. return 0;
  152. #elif defined HAVE_ZLIB_H
  153. /* FIXME: zip files are not supported */
  154. return gzwrite(fp->gz, ptr, size);
  155. #else
  156. return fwrite(ptr, 1, size, fp->f);
  157. #endif
  158. }
  159. char *cucul_file_gets(cucul_file_t *fp, char *s, int size)
  160. {
  161. #if defined __KERNEL__
  162. return NULL;
  163. #elif defined HAVE_ZLIB_H
  164. if(fp->zip)
  165. {
  166. int i;
  167. for(i = 0; i < size; i++)
  168. {
  169. int ret = zipread(fp, s + i, 1);
  170. if(ret < 0)
  171. return NULL;
  172. if(ret == 0 || s[i] == '\n')
  173. {
  174. if(i + 1 < size)
  175. s[i + 1] = '\0';
  176. return s;
  177. }
  178. }
  179. return s;
  180. }
  181. return gzgets(fp->gz, s, size);
  182. #else
  183. return fgets(s, size, fp->f);
  184. #endif
  185. }
  186. int cucul_file_eof(cucul_file_t *fp)
  187. {
  188. #if defined __KERNEL__
  189. return 1;
  190. #elif defined HAVE_ZLIB_H
  191. return fp->zip ? fp->eof : gzeof(fp->gz);
  192. #else
  193. return feof(fp->f);
  194. #endif
  195. }
  196. #if !defined __KERNEL__ && defined HAVE_ZLIB_H
  197. static int zipread(cucul_file_t *fp, void *buf, unsigned int len)
  198. {
  199. unsigned int total_read = 0;
  200. if(len == 0)
  201. return 0;
  202. fp->stream.next_out = buf;
  203. fp->stream.avail_out = len;
  204. while(fp->stream.avail_out > 0)
  205. {
  206. unsigned int tmp;
  207. int ret = 0;
  208. if(fp->stream.avail_in == 0 && !gzeof(fp->gz))
  209. {
  210. int bytes_read;
  211. bytes_read = gzread(fp->gz, fp->read_buffer, READSIZE);
  212. if(bytes_read < 0)
  213. return -1;
  214. fp->stream.next_in = fp->read_buffer;
  215. fp->stream.avail_in = bytes_read;
  216. }
  217. tmp = fp->stream.total_out;
  218. ret = inflate(&fp->stream, Z_SYNC_FLUSH);
  219. total_read += fp->stream.total_out - tmp;
  220. if(ret == Z_STREAM_END)
  221. {
  222. fp->eof = 1;
  223. fp->total += total_read;
  224. return total_read;
  225. }
  226. if(ret != Z_OK)
  227. return ret;
  228. }
  229. fp->total += total_read;
  230. return total_read;
  231. }
  232. #endif