Coverage Report

Created: 2025-01-28 06:17

/src/mupdf/source/xps/xps-zip.c
Line
Count
Source (jump to first uncovered line)
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
23
#include "mupdf/fitz.h"
24
#include "xps-imp.h"
25
26
#include <string.h>
27
28
static void xps_init_document(fz_context *ctx, xps_document *doc);
29
30
static xps_part *
31
xps_new_part(fz_context *ctx, xps_document *doc, char *name, fz_buffer *data)
32
0
{
33
0
  xps_part *part = NULL;
34
35
0
  fz_var(part);
36
37
0
  fz_try(ctx)
38
0
  {
39
0
    part = fz_malloc_struct(ctx, xps_part);
40
0
    part->name = fz_strdup(ctx, name);
41
0
    part->data = data; /* take ownership of buffer */
42
0
  }
43
0
  fz_catch(ctx)
44
0
  {
45
0
    fz_drop_buffer(ctx, data);
46
0
    fz_free(ctx, part);
47
0
    fz_rethrow(ctx);
48
0
  }
49
50
0
  return part;
51
0
}
52
53
void
54
xps_drop_part(fz_context *ctx, xps_document *doc, xps_part *part)
55
0
{
56
0
  fz_free(ctx, part->name);
57
0
  fz_drop_buffer(ctx, part->data);
58
0
  fz_free(ctx, part);
59
0
}
60
61
xps_part *
62
xps_read_part(fz_context *ctx, xps_document *doc, char *partname)
63
0
{
64
0
  fz_archive *zip = doc->zip;
65
0
  fz_buffer *buf = NULL;
66
0
  fz_buffer *tmp = NULL;
67
0
  char path[2048];
68
0
  int count;
69
0
  char *name;
70
0
  int seen_last;
71
72
0
  fz_var(buf);
73
0
  fz_var(tmp);
74
75
0
  name = partname;
76
0
  if (name[0] == '/')
77
0
    name ++;
78
79
0
  fz_try(ctx)
80
0
  {
81
    /* All in one piece */
82
0
    if (fz_has_archive_entry(ctx, zip, name))
83
0
    {
84
0
      buf = fz_read_archive_entry(ctx, zip, name);
85
0
    }
86
87
    /* Assemble all the pieces */
88
0
    else
89
0
    {
90
0
      buf = fz_new_buffer(ctx, 512);
91
0
      seen_last = 0;
92
0
      for (count = 0; !seen_last; ++count)
93
0
      {
94
0
        fz_snprintf(path, sizeof path, "%s/[%d].piece", name, count);
95
0
        if (fz_has_archive_entry(ctx, zip, path))
96
0
        {
97
0
          tmp = fz_read_archive_entry(ctx, zip, path);
98
0
          fz_append_buffer(ctx, buf, tmp);
99
0
          fz_drop_buffer(ctx, tmp);
100
0
          tmp = NULL;
101
0
        }
102
0
        else
103
0
        {
104
0
          fz_snprintf(path, sizeof path, "%s/[%d].last.piece", name, count);
105
0
          if (fz_has_archive_entry(ctx, zip, path))
106
0
          {
107
0
            tmp = fz_read_archive_entry(ctx, zip, path);
108
0
            fz_append_buffer(ctx, buf, tmp);
109
0
            fz_drop_buffer(ctx, tmp);
110
0
            tmp = NULL;
111
0
            seen_last = 1;
112
0
          }
113
0
          else
114
0
            fz_throw(ctx, FZ_ERROR_FORMAT, "cannot find all pieces for part '%s'", partname);
115
0
        }
116
0
      }
117
0
    }
118
119
0
  }
120
0
  fz_catch(ctx)
121
0
  {
122
0
    fz_drop_buffer(ctx, tmp);
123
0
    fz_drop_buffer(ctx, buf);
124
0
    fz_rethrow(ctx);
125
0
  }
126
127
0
  return xps_new_part(ctx, doc, partname, buf);
128
0
}
129
130
int
131
xps_has_part(fz_context *ctx, xps_document *doc, char *name)
132
0
{
133
0
  char buf[2048];
134
0
  if (name[0] == '/')
135
0
    name++;
136
0
  if (fz_has_archive_entry(ctx, doc->zip, name))
137
0
    return 1;
138
0
  fz_snprintf(buf, sizeof buf, "%s/[0].piece", name);
139
0
  if (fz_has_archive_entry(ctx, doc->zip, buf))
140
0
    return 1;
141
0
  fz_snprintf(buf, sizeof buf, "%s/[0].last.piece", name);
142
0
  if (fz_has_archive_entry(ctx, doc->zip, buf))
143
0
    return 1;
144
0
  return 0;
145
0
}
146
147
fz_document *
148
xps_open_document_with_directory(fz_context *ctx, fz_archive *dir)
149
0
{
150
0
  xps_document *doc;
151
152
0
  doc = fz_malloc_struct(ctx, xps_document);
153
0
  xps_init_document(ctx, doc);
154
155
0
  fz_try(ctx)
156
0
  {
157
0
    doc->zip = fz_keep_archive(ctx, dir);
158
0
    xps_read_page_list(ctx, doc);
159
0
  }
160
0
  fz_catch(ctx)
161
0
  {
162
0
    fz_drop_document(ctx, &doc->super);
163
0
    fz_rethrow(ctx);
164
0
  }
165
166
0
  return (fz_document*)doc;
167
0
}
168
169
fz_document *
170
xps_open_document_with_stream(fz_context *ctx, fz_stream *file)
171
0
{
172
0
  xps_document *doc;
173
174
0
  doc = fz_malloc_struct(ctx, xps_document);
175
0
  xps_init_document(ctx, doc);
176
177
0
  fz_try(ctx)
178
0
  {
179
0
    doc->zip = fz_open_zip_archive_with_stream(ctx, file);
180
0
    xps_read_page_list(ctx, doc);
181
0
  }
182
0
  fz_catch(ctx)
183
0
  {
184
0
    fz_drop_document(ctx, &doc->super);
185
0
    fz_rethrow(ctx);
186
0
  }
187
188
0
  return (fz_document*)doc;
189
0
}
190
191
fz_document *
192
xps_open_document(fz_context *ctx, const char *filename)
193
0
{
194
0
  fz_stream *file;
195
0
  fz_document *doc = NULL;
196
197
0
  if (fz_is_directory(ctx, filename))
198
0
  {
199
0
    fz_archive *dir = fz_open_directory(ctx, filename);
200
201
0
    fz_try(ctx)
202
0
      doc = xps_open_document_with_directory(ctx, dir);
203
0
    fz_always(ctx)
204
0
      fz_drop_archive(ctx, dir);
205
0
    fz_catch(ctx)
206
0
      fz_rethrow(ctx);
207
208
0
    return doc;
209
0
  }
210
211
0
  file = fz_open_file(ctx, filename);
212
213
0
  fz_try(ctx)
214
0
    doc = xps_open_document_with_stream(ctx, file);
215
0
  fz_always(ctx)
216
0
    fz_drop_stream(ctx, file);
217
0
  fz_catch(ctx)
218
0
    fz_rethrow(ctx);
219
220
0
  return (fz_document*)doc;
221
0
}
222
223
static void
224
xps_drop_document(fz_context *ctx, fz_document *doc_)
225
0
{
226
0
  xps_document *doc = (xps_document*)doc_;
227
0
  xps_font_cache *font, *next;
228
229
0
  if (doc->zip)
230
0
    fz_drop_archive(ctx, doc->zip);
231
232
0
  font = doc->font_table;
233
0
  while (font)
234
0
  {
235
0
    next = font->next;
236
0
    fz_drop_font(ctx, font->font);
237
0
    fz_free(ctx, font->name);
238
0
    fz_free(ctx, font);
239
0
    font = next;
240
0
  }
241
242
0
  xps_drop_page_list(ctx, doc);
243
244
0
  fz_free(ctx, doc->start_part);
245
0
}
246
247
static int
248
xps_lookup_metadata(fz_context *ctx, fz_document *doc_, const char *key, char *buf, size_t size)
249
0
{
250
0
  if (!strcmp(key, FZ_META_FORMAT))
251
0
    return 1 + (int)fz_strlcpy(buf, "XPS", size);
252
0
  return -1;
253
0
}
254
255
static void
256
xps_init_document(fz_context *ctx, xps_document *doc)
257
0
{
258
0
  doc->super.refs = 1;
259
0
  doc->super.drop_document = xps_drop_document;
260
0
  doc->super.load_outline = xps_load_outline;
261
0
  doc->super.resolve_link_dest = xps_lookup_link_target;
262
0
  doc->super.count_pages = xps_count_pages;
263
0
  doc->super.load_page = xps_load_page;
264
0
  doc->super.lookup_metadata = xps_lookup_metadata;
265
0
}