25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

306 lines
6.4 KiB

  1. /*
  2. * libcaca Colour ASCII-Art library
  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 "caca.h"
  29. #include "caca_internals.h"
  30. #if !defined __KERNEL__ && defined HAVE_ZLIB_H
  31. static int zipread(caca_file_t *, void *, unsigned int);
  32. #endif
  33. #if !defined __KERNEL__
  34. struct caca_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. caca_file_t *caca_file_open(char const *path, const char *mode)
  47. {
  48. #if defined __KERNEL__
  49. seterrno(ENOSYS);
  50. return NULL;
  51. #else
  52. caca_file_t *fp = malloc(sizeof(*fp));
  53. fp->readonly = !!strchr(mode, 'r');
  54. # if defined HAVE_ZLIB_H
  55. uint8_t buf[4];
  56. unsigned int skip_size = 0;
  57. fp->gz = gzopen(path, fp->readonly ? "rb" : "wb");
  58. if(!fp->gz)
  59. {
  60. free(fp);
  61. return NULL;
  62. }
  63. fp->eof = 0;
  64. fp->zip = 0;
  65. fp->total = 0;
  66. if(fp->readonly)
  67. {
  68. /* Parse ZIP file and go to start of first file */
  69. gzread(fp->gz, buf, 4);
  70. if(memcmp(buf, "PK\3\4", 4))
  71. {
  72. gzseek(fp->gz, 0, SEEK_SET);
  73. return fp;
  74. }
  75. fp->zip = 1;
  76. gzseek(fp->gz, 22, SEEK_CUR);
  77. gzread(fp->gz, buf, 2); /* Filename size */
  78. skip_size += (uint16_t)buf[0] | ((uint16_t)buf[1] << 8);
  79. gzread(fp->gz, buf, 2); /* Extra field size */
  80. skip_size += (uint16_t)buf[0] | ((uint16_t)buf[1] << 8);
  81. gzseek(fp->gz, skip_size, SEEK_CUR);
  82. /* Initialise inflate stream */
  83. fp->stream.total_out = 0;
  84. fp->stream.zalloc = NULL;
  85. fp->stream.zfree = NULL;
  86. fp->stream.opaque = NULL;
  87. fp->stream.next_in = NULL;
  88. fp->stream.avail_in = 0;
  89. if(inflateInit2(&fp->stream, -MAX_WBITS))
  90. {
  91. free(fp);
  92. gzclose(fp->gz);
  93. return NULL;
  94. }
  95. }
  96. # else
  97. fp->f = fopen(path, mode);
  98. if(!fp->f)
  99. {
  100. free(fp);
  101. return NULL;
  102. }
  103. # endif
  104. return fp;
  105. #endif
  106. }
  107. int caca_file_close(caca_file_t *fp)
  108. {
  109. #if defined __KERNEL__
  110. seterrno(ENOSYS);
  111. return 0;
  112. #elif defined HAVE_ZLIB_H
  113. gzFile gz = fp->gz;
  114. if(fp->zip)
  115. inflateEnd(&fp->stream);
  116. free(fp);
  117. return gzclose(gz);
  118. #else
  119. FILE *f = fp->f;
  120. free(fp);
  121. return fclose(f);
  122. #endif
  123. }
  124. uint64_t caca_file_tell(caca_file_t *fp)
  125. {
  126. #if defined __KERNEL__
  127. seterrno(ENOSYS);
  128. return 0;
  129. #elif defined HAVE_ZLIB_H
  130. if(fp->zip)
  131. return fp->total;
  132. return gztell(fp->gz);
  133. #else
  134. return ftell(fp->f);
  135. #endif
  136. }
  137. size_t caca_file_read(caca_file_t *fp, void *ptr, size_t size)
  138. {
  139. #if defined __KERNEL__
  140. seterrno(ENOSYS);
  141. return 0;
  142. #elif defined HAVE_ZLIB_H
  143. if(fp->zip)
  144. return zipread(fp, ptr, size);
  145. return gzread(fp->gz, ptr, size);
  146. #else
  147. return fread(ptr, 1, size, fp->f);
  148. #endif
  149. }
  150. size_t caca_file_write(caca_file_t *fp, const void *ptr, size_t size)
  151. {
  152. #if defined __KERNEL__
  153. seterrno(ENOSYS);
  154. return 0;
  155. #else
  156. if(fp->readonly)
  157. return 0;
  158. # if defined HAVE_ZLIB_H
  159. if(fp->zip)
  160. {
  161. /* FIXME: zip files are not supported */
  162. seterrno(ENOSYS);
  163. return 0;
  164. }
  165. return gzwrite(fp->gz, ptr, size);
  166. # else
  167. return fwrite(ptr, 1, size, fp->f);
  168. # endif
  169. #endif
  170. }
  171. char *caca_file_gets(caca_file_t *fp, char *s, int size)
  172. {
  173. #if defined __KERNEL__
  174. seterrno(ENOSYS);
  175. return NULL;
  176. #elif defined HAVE_ZLIB_H
  177. if(fp->zip)
  178. {
  179. int i;
  180. for(i = 0; i < size; i++)
  181. {
  182. int ret = zipread(fp, s + i, 1);
  183. if(ret < 0)
  184. return NULL;
  185. if(ret == 0 || s[i] == '\n')
  186. {
  187. if(i + 1 < size)
  188. s[i + 1] = '\0';
  189. return s;
  190. }
  191. }
  192. return s;
  193. }
  194. return gzgets(fp->gz, s, size);
  195. #else
  196. return fgets(s, size, fp->f);
  197. #endif
  198. }
  199. int caca_file_eof(caca_file_t *fp)
  200. {
  201. #if defined __KERNEL__
  202. return 1;
  203. #elif defined HAVE_ZLIB_H
  204. return fp->zip ? fp->eof : gzeof(fp->gz);
  205. #else
  206. return feof(fp->f);
  207. #endif
  208. }
  209. #if !defined __KERNEL__ && defined HAVE_ZLIB_H
  210. static int zipread(caca_file_t *fp, void *buf, unsigned int len)
  211. {
  212. unsigned int total_read = 0;
  213. if(len == 0)
  214. return 0;
  215. fp->stream.next_out = buf;
  216. fp->stream.avail_out = len;
  217. while(fp->stream.avail_out > 0)
  218. {
  219. unsigned int tmp;
  220. int ret = 0;
  221. if(fp->stream.avail_in == 0 && !gzeof(fp->gz))
  222. {
  223. int bytes_read;
  224. bytes_read = gzread(fp->gz, fp->read_buffer, READSIZE);
  225. if(bytes_read < 0)
  226. return -1;
  227. fp->stream.next_in = fp->read_buffer;
  228. fp->stream.avail_in = bytes_read;
  229. }
  230. tmp = fp->stream.total_out;
  231. ret = inflate(&fp->stream, Z_SYNC_FLUSH);
  232. total_read += fp->stream.total_out - tmp;
  233. if(ret == Z_STREAM_END)
  234. {
  235. fp->eof = 1;
  236. fp->total += total_read;
  237. return total_read;
  238. }
  239. if(ret != Z_OK)
  240. return ret;
  241. }
  242. fp->total += total_read;
  243. return total_read;
  244. }
  245. #endif
  246. /*
  247. * XXX: The following functions are aliases.
  248. */
  249. cucul_file_t *cucul_file_open(char const *, const char *)
  250. CACA_ALIAS(caca_file_open);
  251. int cucul_file_close(cucul_file_t *) CACA_ALIAS(caca_file_close);
  252. uint64_t cucul_file_tell(cucul_file_t *) CACA_ALIAS(caca_file_tell);
  253. size_t cucul_file_read(cucul_file_t *, void *, size_t)
  254. CACA_ALIAS(caca_file_read);
  255. size_t cucul_file_write(cucul_file_t *, const void *, size_t)
  256. CACA_ALIAS(caca_file_write);
  257. char * cucul_file_gets(cucul_file_t *, char *, int)
  258. CACA_ALIAS(caca_file_gets);
  259. int cucul_file_eof(cucul_file_t *) CACA_ALIAS(caca_file_eof);