xps-zip.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. // Copyright (C) 2004-2024 Artifex Software, Inc.
  2. //
  3. // This file is part of MuPDF.
  4. //
  5. // MuPDF is free software: you can redistribute it and/or modify it under the
  6. // terms of the GNU Affero General Public License as published by the Free
  7. // Software Foundation, either version 3 of the License, or (at your option)
  8. // any later version.
  9. //
  10. // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY
  11. // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  12. // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
  13. // details.
  14. //
  15. // You should have received a copy of the GNU Affero General Public License
  16. // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>
  17. //
  18. // Alternative licensing terms are available from the licensor.
  19. // For commercial licensing, see <https://www.artifex.com/> or contact
  20. // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
  21. // CA 94129, USA, for further information.
  22. #include "mupdf/fitz.h"
  23. #include "xps-imp.h"
  24. #include <string.h>
  25. static void xps_init_document(fz_context *ctx, xps_document *doc);
  26. static xps_part *
  27. xps_new_part(fz_context *ctx, xps_document *doc, char *name, fz_buffer *data)
  28. {
  29. xps_part *part = NULL;
  30. fz_var(part);
  31. fz_try(ctx)
  32. {
  33. part = fz_malloc_struct(ctx, xps_part);
  34. part->name = fz_strdup(ctx, name);
  35. part->data = data; /* take ownership of buffer */
  36. }
  37. fz_catch(ctx)
  38. {
  39. fz_drop_buffer(ctx, data);
  40. fz_free(ctx, part);
  41. fz_rethrow(ctx);
  42. }
  43. return part;
  44. }
  45. void
  46. xps_drop_part(fz_context *ctx, xps_document *doc, xps_part *part)
  47. {
  48. fz_free(ctx, part->name);
  49. fz_drop_buffer(ctx, part->data);
  50. fz_free(ctx, part);
  51. }
  52. xps_part *
  53. xps_read_part(fz_context *ctx, xps_document *doc, char *partname)
  54. {
  55. fz_archive *zip = doc->zip;
  56. fz_buffer *buf = NULL;
  57. fz_buffer *tmp = NULL;
  58. char path[2048];
  59. int count;
  60. char *name;
  61. int seen_last;
  62. fz_var(buf);
  63. fz_var(tmp);
  64. name = partname;
  65. if (name[0] == '/')
  66. name ++;
  67. fz_try(ctx)
  68. {
  69. /* All in one piece */
  70. if (fz_has_archive_entry(ctx, zip, name))
  71. {
  72. buf = fz_read_archive_entry(ctx, zip, name);
  73. }
  74. /* Assemble all the pieces */
  75. else
  76. {
  77. buf = fz_new_buffer(ctx, 512);
  78. seen_last = 0;
  79. for (count = 0; !seen_last; ++count)
  80. {
  81. fz_snprintf(path, sizeof path, "%s/[%d].piece", name, count);
  82. if (fz_has_archive_entry(ctx, zip, path))
  83. {
  84. tmp = fz_read_archive_entry(ctx, zip, path);
  85. fz_append_buffer(ctx, buf, tmp);
  86. fz_drop_buffer(ctx, tmp);
  87. tmp = NULL;
  88. }
  89. else
  90. {
  91. fz_snprintf(path, sizeof path, "%s/[%d].last.piece", name, count);
  92. if (fz_has_archive_entry(ctx, zip, path))
  93. {
  94. tmp = fz_read_archive_entry(ctx, zip, path);
  95. fz_append_buffer(ctx, buf, tmp);
  96. fz_drop_buffer(ctx, tmp);
  97. tmp = NULL;
  98. seen_last = 1;
  99. }
  100. else
  101. fz_throw(ctx, FZ_ERROR_FORMAT, "cannot find all pieces for part '%s'", partname);
  102. }
  103. }
  104. }
  105. }
  106. fz_catch(ctx)
  107. {
  108. fz_drop_buffer(ctx, tmp);
  109. fz_drop_buffer(ctx, buf);
  110. fz_rethrow(ctx);
  111. }
  112. return xps_new_part(ctx, doc, partname, buf);
  113. }
  114. int
  115. xps_has_part(fz_context *ctx, xps_document *doc, char *name)
  116. {
  117. char buf[2048];
  118. if (name[0] == '/')
  119. name++;
  120. if (fz_has_archive_entry(ctx, doc->zip, name))
  121. return 1;
  122. fz_snprintf(buf, sizeof buf, "%s/[0].piece", name);
  123. if (fz_has_archive_entry(ctx, doc->zip, buf))
  124. return 1;
  125. fz_snprintf(buf, sizeof buf, "%s/[0].last.piece", name);
  126. if (fz_has_archive_entry(ctx, doc->zip, buf))
  127. return 1;
  128. return 0;
  129. }
  130. fz_document *
  131. xps_open_document_with_directory(fz_context *ctx, fz_archive *dir)
  132. {
  133. xps_document *doc;
  134. doc = fz_malloc_struct(ctx, xps_document);
  135. xps_init_document(ctx, doc);
  136. fz_try(ctx)
  137. {
  138. doc->zip = fz_keep_archive(ctx, dir);
  139. xps_read_page_list(ctx, doc);
  140. }
  141. fz_catch(ctx)
  142. {
  143. fz_drop_document(ctx, &doc->super);
  144. fz_rethrow(ctx);
  145. }
  146. return (fz_document*)doc;
  147. }
  148. fz_document *
  149. xps_open_document_with_stream(fz_context *ctx, fz_stream *file)
  150. {
  151. xps_document *doc;
  152. doc = fz_malloc_struct(ctx, xps_document);
  153. xps_init_document(ctx, doc);
  154. fz_try(ctx)
  155. {
  156. doc->zip = fz_open_zip_archive_with_stream(ctx, file);
  157. xps_read_page_list(ctx, doc);
  158. }
  159. fz_catch(ctx)
  160. {
  161. fz_drop_document(ctx, &doc->super);
  162. fz_rethrow(ctx);
  163. }
  164. return (fz_document*)doc;
  165. }
  166. fz_document *
  167. xps_open_document(fz_context *ctx, const char *filename)
  168. {
  169. fz_stream *file;
  170. fz_document *doc = NULL;
  171. if (fz_is_directory(ctx, filename))
  172. {
  173. fz_archive *dir = fz_open_directory(ctx, filename);
  174. fz_try(ctx)
  175. doc = xps_open_document_with_directory(ctx, dir);
  176. fz_always(ctx)
  177. fz_drop_archive(ctx, dir);
  178. fz_catch(ctx)
  179. fz_rethrow(ctx);
  180. return doc;
  181. }
  182. file = fz_open_file(ctx, filename);
  183. fz_try(ctx)
  184. doc = xps_open_document_with_stream(ctx, file);
  185. fz_always(ctx)
  186. fz_drop_stream(ctx, file);
  187. fz_catch(ctx)
  188. fz_rethrow(ctx);
  189. return (fz_document*)doc;
  190. }
  191. static void
  192. xps_drop_document(fz_context *ctx, fz_document *doc_)
  193. {
  194. xps_document *doc = (xps_document*)doc_;
  195. xps_font_cache *font, *next;
  196. if (doc->zip)
  197. fz_drop_archive(ctx, doc->zip);
  198. font = doc->font_table;
  199. while (font)
  200. {
  201. next = font->next;
  202. fz_drop_font(ctx, font->font);
  203. fz_free(ctx, font->name);
  204. fz_free(ctx, font);
  205. font = next;
  206. }
  207. xps_drop_page_list(ctx, doc);
  208. fz_free(ctx, doc->start_part);
  209. }
  210. static int
  211. xps_lookup_metadata(fz_context *ctx, fz_document *doc_, const char *key, char *buf, size_t size)
  212. {
  213. if (!strcmp(key, FZ_META_FORMAT))
  214. return 1 + (int)fz_strlcpy(buf, "XPS", size);
  215. return -1;
  216. }
  217. static void
  218. xps_init_document(fz_context *ctx, xps_document *doc)
  219. {
  220. doc->super.refs = 1;
  221. doc->super.drop_document = xps_drop_document;
  222. doc->super.load_outline = xps_load_outline;
  223. doc->super.resolve_link_dest = xps_lookup_link_target;
  224. doc->super.count_pages = xps_count_pages;
  225. doc->super.load_page = xps_load_page;
  226. doc->super.lookup_metadata = xps_lookup_metadata;
  227. }