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.
 
 
 
 
 
 

214 lines
4.3 KiB

  1. /*
  2. * TOIlet The Other Implementation’s letters
  3. * Copyright (c) 2006 Sam Hocevar <sam@zoy.org>
  4. * All Rights Reserved
  5. *
  6. * $Id$
  7. *
  8. * This program 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. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <stdint.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. #include "io.h"
  28. #if defined HAVE_ZLIB_H
  29. static int zipread(TOIFILE *, void *, unsigned int);
  30. #endif
  31. struct toifile
  32. {
  33. #if defined HAVE_ZLIB_H
  34. unsigned char read_buffer[READSIZE];
  35. z_stream stream;
  36. gzFile gz;
  37. int eof, zip;
  38. #endif
  39. FILE *f;
  40. };
  41. TOIFILE *toiopen(char const *path, const char *mode)
  42. {
  43. TOIFILE *toif = malloc(sizeof(*toif));
  44. #if defined HAVE_ZLIB_H
  45. uint8_t buf[4];
  46. unsigned int skip_size = 0;
  47. toif->gz = gzopen(path, "rb");
  48. if(!toif->gz)
  49. {
  50. free(toif);
  51. return NULL;
  52. }
  53. toif->eof = 0;
  54. toif->zip = 0;
  55. /* Parse ZIP file and go to start of first file */
  56. gzread(toif->gz, buf, 4);
  57. if(memcmp(buf, "PK\3\4", 4))
  58. {
  59. gzseek(toif->gz, 0, SEEK_SET);
  60. return toif;
  61. }
  62. toif->zip = 1;
  63. gzseek(toif->gz, 22, SEEK_CUR);
  64. gzread(toif->gz, buf, 2); /* Filename size */
  65. skip_size += (uint16_t)buf[0] | ((uint16_t)buf[1] << 8);
  66. gzread(toif->gz, buf, 2); /* Extra field size */
  67. skip_size += (uint16_t)buf[0] | ((uint16_t)buf[1] << 8);
  68. gzseek(toif->gz, skip_size, SEEK_CUR);
  69. /* Initialise inflate stream */
  70. toif->stream.total_out = 0;
  71. toif->stream.zalloc = NULL;
  72. toif->stream.zfree = NULL;
  73. toif->stream.opaque = NULL;
  74. toif->stream.next_in = NULL;
  75. toif->stream.avail_in = 0;
  76. if(inflateInit2(&toif->stream, -MAX_WBITS))
  77. {
  78. free(toif);
  79. gzclose(toif->gz);
  80. return NULL;
  81. }
  82. #else
  83. toif->f = fopen(path, mode);
  84. if(!toif->f)
  85. {
  86. free(toif);
  87. return NULL;
  88. }
  89. #endif
  90. return toif;
  91. }
  92. int toiclose(TOIFILE *toif)
  93. {
  94. #if defined HAVE_ZLIB_H
  95. gzFile gz = toif->gz;
  96. if(toif->zip)
  97. inflateEnd(&toif->stream);
  98. free(toif);
  99. return gzclose(gz);
  100. #else
  101. FILE *f = toif->f;
  102. free(toif);
  103. return fclose(f);
  104. #endif
  105. }
  106. int toieof(TOIFILE *toif)
  107. {
  108. #if defined HAVE_ZLIB_H
  109. return toif->zip ? toif->eof : gzeof(toif->gz);
  110. #else
  111. return feof(toif->f);
  112. #endif
  113. }
  114. char *toigets(char *s, int size, TOIFILE *toif)
  115. {
  116. #if defined HAVE_ZLIB_H
  117. if(toif->zip)
  118. {
  119. int i;
  120. for(i = 0; i < size; i++)
  121. {
  122. int ret = zipread(toif, s + i, 1);
  123. if(ret < 0)
  124. return NULL;
  125. if(ret == 0 || s[i] == '\n')
  126. {
  127. if(i + 1 < size)
  128. s[i + 1] = '\0';
  129. return s;
  130. }
  131. }
  132. return s;
  133. }
  134. return gzgets(toif->gz, s, size);
  135. #else
  136. return fgets(s, size, toif->f);
  137. #endif
  138. }
  139. #if defined HAVE_ZLIB_H
  140. static int zipread(TOIFILE *toif, void *buf, unsigned int len)
  141. {
  142. unsigned int total_read = 0;
  143. if(len == 0)
  144. return 0;
  145. toif->stream.next_out = buf;
  146. toif->stream.avail_out = len;
  147. while(toif->stream.avail_out > 0)
  148. {
  149. unsigned int tmp;
  150. int ret = 0;
  151. if(toif->stream.avail_in == 0 && !gzeof(toif->gz))
  152. {
  153. int bytes_read;
  154. bytes_read = gzread(toif->gz, toif->read_buffer, READSIZE);
  155. if(bytes_read < 0)
  156. return -1;
  157. toif->stream.next_in = toif->read_buffer;
  158. toif->stream.avail_in = bytes_read;
  159. }
  160. tmp = toif->stream.total_out;
  161. ret = inflate(&toif->stream, Z_SYNC_FLUSH);
  162. total_read += toif->stream.total_out - tmp;
  163. if(ret == Z_STREAM_END)
  164. {
  165. toif->eof = 1;
  166. return total_read;
  167. }
  168. if(ret != Z_OK)
  169. return ret;
  170. }
  171. return total_read;
  172. }
  173. #endif