diff options
author | Tor Andersson <tor.andersson@artifex.com> | 2013-06-19 15:29:44 +0200 |
---|---|---|
committer | Tor Andersson <tor.andersson@artifex.com> | 2013-06-20 16:45:35 +0200 |
commit | 0a927854a10e1e6b9770a81e2e1d9f3093631757 (patch) | |
tree | 3d65d820d9fdba2d0d394d99c36290c851b78ca0 /xps/xps_zip.c | |
parent | 1ae8f19179c5f0f8c6352b3c7855465325d5449a (diff) | |
download | mupdf-0a927854a10e1e6b9770a81e2e1d9f3093631757.tar.xz |
Rearrange source files.
Diffstat (limited to 'xps/xps_zip.c')
-rw-r--r-- | xps/xps_zip.c | 697 |
1 files changed, 0 insertions, 697 deletions
diff --git a/xps/xps_zip.c b/xps/xps_zip.c deleted file mode 100644 index 70b643af..00000000 --- a/xps/xps_zip.c +++ /dev/null @@ -1,697 +0,0 @@ -#include "mupdf/xps.h" - -#include <zlib.h> - -#define ZIP_LOCAL_FILE_SIG 0x04034b50 -#define ZIP_DATA_DESC_SIG 0x08074b50 -#define ZIP_CENTRAL_DIRECTORY_SIG 0x02014b50 -#define ZIP_END_OF_CENTRAL_DIRECTORY_SIG 0x06054b50 - -#define ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_SIG 0x07064b50 -#define ZIP64_END_OF_CENTRAL_DIRECTORY_SIG 0x06064b50 -#define ZIP64_EXTRA_FIELD_SIG 0x0001 - -static void xps_init_document(xps_document *doc); - -xps_part * -xps_new_part(xps_document *doc, char *name, int size) -{ - xps_part *part; - - part = fz_malloc(doc->ctx, sizeof(xps_part)); - part->name = fz_strdup(doc->ctx, name); - part->size = size; - part->data = fz_malloc(doc->ctx, size + 1); - part->data[size] = 0; /* null-terminate for xml parser */ - - return part; -} - -void -xps_free_part(xps_document *doc, xps_part *part) -{ - fz_free(doc->ctx, part->name); - fz_free(doc->ctx, part->data); - fz_free(doc->ctx, part); -} - -static inline int getshort(fz_stream *file) -{ - int a = fz_read_byte(file); - int b = fz_read_byte(file); - return a | b << 8; -} - -static inline int getlong(fz_stream *file) -{ - int a = fz_read_byte(file); - int b = fz_read_byte(file); - int c = fz_read_byte(file); - int d = fz_read_byte(file); - return a | b << 8 | c << 16 | d << 24; -} - -static inline int getlong64(fz_stream *file) -{ - int a = getlong(file); - int b = getlong(file); - return b != 0 ? -1 : a; -} - -static void * -xps_zip_alloc_items(xps_document *doc, int items, int size) -{ - return fz_malloc_array(doc->ctx, items, size); -} - -static void -xps_zip_free(xps_document *doc, void *ptr) -{ - fz_free(doc->ctx, ptr); -} - -static int -xps_compare_entries(const void *a0, const void *b0) -{ - xps_entry *a = (xps_entry*) a0; - xps_entry *b = (xps_entry*) b0; - return xps_strcasecmp(a->name, b->name); -} - -static xps_entry * -xps_lookup_zip_entry(xps_document *doc, char *name) -{ - int l = 0; - int r = doc->zip_count - 1; - while (l <= r) - { - int m = (l + r) >> 1; - int c = xps_strcasecmp(name, doc->zip_table[m].name); - if (c < 0) - r = m - 1; - else if (c > 0) - l = m + 1; - else - return &doc->zip_table[m]; - } - return NULL; -} - -static void -xps_read_zip_entry(xps_document *doc, xps_entry *ent, unsigned char *outbuf) -{ - z_stream stream; - unsigned char *inbuf; - int sig; - int method; - int namelength, extralength; - int code; - fz_context *ctx = doc->ctx; - - fz_seek(doc->file, ent->offset, 0); - - sig = getlong(doc->file); - if (sig != ZIP_LOCAL_FILE_SIG) - { - fz_throw(doc->ctx, FZ_ERROR_GENERIC, "wrong zip local file signature (0x%x)", sig); - } - - (void) getshort(doc->file); /* version */ - (void) getshort(doc->file); /* general */ - method = getshort(doc->file); - (void) getshort(doc->file); /* file time */ - (void) getshort(doc->file); /* file date */ - (void) getlong(doc->file); /* crc-32 */ - (void) getlong(doc->file); /* csize */ - (void) getlong(doc->file); /* usize */ - namelength = getshort(doc->file); - extralength = getshort(doc->file); - - fz_seek(doc->file, namelength + extralength, 1); - - if (method == 0) - { - fz_read(doc->file, outbuf, ent->usize); - } - else if (method == 8) - { - inbuf = fz_malloc(ctx, ent->csize); - - fz_read(doc->file, inbuf, ent->csize); - - memset(&stream, 0, sizeof(z_stream)); - stream.zalloc = (alloc_func) xps_zip_alloc_items; - stream.zfree = (free_func) xps_zip_free; - stream.opaque = doc; - stream.next_in = inbuf; - stream.avail_in = ent->csize; - stream.next_out = outbuf; - stream.avail_out = ent->usize; - - code = inflateInit2(&stream, -15); - if (code != Z_OK) - { - fz_free(ctx, inbuf); - fz_throw(ctx, FZ_ERROR_GENERIC, "zlib inflateInit2 error: %s", stream.msg); - } - code = inflate(&stream, Z_FINISH); - if (code != Z_STREAM_END) - { - inflateEnd(&stream); - fz_free(ctx, inbuf); - fz_throw(ctx, FZ_ERROR_GENERIC, "zlib inflate error: %s", stream.msg); - } - code = inflateEnd(&stream); - if (code != Z_OK) - { - fz_free(ctx, inbuf); - fz_throw(ctx, FZ_ERROR_GENERIC, "zlib inflateEnd error: %s", stream.msg); - } - - fz_free(ctx, inbuf); - } - else - { - fz_throw(ctx, FZ_ERROR_GENERIC, "unknown compression method (%d)", method); - } -} - -/* - * Read the central directory in a zip file. - */ - -static void -xps_read_zip_dir(xps_document *doc, int start_offset) -{ - int sig; - int offset, count; - int namesize, metasize, commentsize; - int i; - - fz_seek(doc->file, start_offset, 0); - - sig = getlong(doc->file); - if (sig != ZIP_END_OF_CENTRAL_DIRECTORY_SIG) - fz_throw(doc->ctx, FZ_ERROR_GENERIC, "wrong zip end of central directory signature (0x%x)", sig); - - (void) getshort(doc->file); /* this disk */ - (void) getshort(doc->file); /* start disk */ - (void) getshort(doc->file); /* entries in this disk */ - count = getshort(doc->file); /* entries in central directory disk */ - (void) getlong(doc->file); /* size of central directory */ - offset = getlong(doc->file); /* offset to central directory */ - - /* ZIP64 */ - if (count == 0xFFFF) - { - fz_seek(doc->file, start_offset - 20, 0); - - sig = getlong(doc->file); - if (sig != ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_SIG) - fz_throw(doc->ctx, FZ_ERROR_GENERIC, "wrong zip64 end of central directory locator signature (0x%x)", sig); - - (void) getlong(doc->file); /* start disk */ - offset = getlong64(doc->file); /* offset to end of central directory record */ - if (offset < 0) - fz_throw(doc->ctx, FZ_ERROR_GENERIC, "zip64 files larger than 2 GB aren't supported"); - - fz_seek(doc->file, offset, 0); - - sig = getlong(doc->file); - if (sig != ZIP64_END_OF_CENTRAL_DIRECTORY_SIG) - fz_throw(doc->ctx, FZ_ERROR_GENERIC, "wrong zip64 end of central directory signature (0x%x)", sig); - - (void) getlong64(doc->file); /* size of record */ - (void) getshort(doc->file); /* version made by */ - (void) getshort(doc->file); /* version to extract */ - (void) getlong(doc->file); /* disk number */ - (void) getlong(doc->file); /* disk number start */ - count = getlong64(doc->file); /* entries in central directory disk */ - (void) getlong64(doc->file); /* entries in central directory */ - (void) getlong64(doc->file); /* size of central directory */ - offset = getlong64(doc->file); /* offset to central directory */ - - if (count < 0 || offset < 0) - fz_throw(doc->ctx, FZ_ERROR_GENERIC, "zip64 files larger than 2 GB aren't supported"); - } - - doc->zip_table = fz_malloc_array(doc->ctx, count, sizeof(xps_entry)); - memset(doc->zip_table, 0, count * sizeof(xps_entry)); - doc->zip_count = count; - - fz_seek(doc->file, offset, 0); - - for (i = 0; i < count; i++) - { - sig = getlong(doc->file); - if (sig != ZIP_CENTRAL_DIRECTORY_SIG) - fz_throw(doc->ctx, FZ_ERROR_GENERIC, "wrong zip central directory signature (0x%x)", sig); - - (void) getshort(doc->file); /* version made by */ - (void) getshort(doc->file); /* version to extract */ - (void) getshort(doc->file); /* general */ - (void) getshort(doc->file); /* method */ - (void) getshort(doc->file); /* last mod file time */ - (void) getshort(doc->file); /* last mod file date */ - (void) getlong(doc->file); /* crc-32 */ - doc->zip_table[i].csize = getlong(doc->file); - doc->zip_table[i].usize = getlong(doc->file); - namesize = getshort(doc->file); - metasize = getshort(doc->file); - commentsize = getshort(doc->file); - (void) getshort(doc->file); /* disk number start */ - (void) getshort(doc->file); /* int file atts */ - (void) getlong(doc->file); /* ext file atts */ - doc->zip_table[i].offset = getlong(doc->file); - - doc->zip_table[i].name = fz_malloc(doc->ctx, namesize + 1); - fz_read(doc->file, (unsigned char*)doc->zip_table[i].name, namesize); - doc->zip_table[i].name[namesize] = 0; - - while (metasize > 0) - { - int type = getshort(doc->file); - int size = getshort(doc->file); - if (type == ZIP64_EXTRA_FIELD_SIG) - { - doc->zip_table[i].usize = getlong64(doc->file); - doc->zip_table[i].csize = getlong64(doc->file); - doc->zip_table[i].offset = getlong64(doc->file); - fz_seek(doc->file, -24, 1); - } - fz_seek(doc->file, size, 1); - metasize -= 4 + size; - } - if (doc->zip_table[i].usize < 0 || doc->zip_table[i].csize < 0 || doc->zip_table[i].offset < 0) - fz_throw(doc->ctx, FZ_ERROR_GENERIC, "zip64 files larger than 2 GB aren't supported"); - - fz_seek(doc->file, commentsize, 1); - } - - qsort(doc->zip_table, count, sizeof(xps_entry), xps_compare_entries); -} - -static void -xps_find_and_read_zip_dir(xps_document *doc) -{ - unsigned char buf[512]; - int file_size, back, maxback; - int i, n; - fz_context *ctx = doc->ctx; - - fz_seek(doc->file, 0, SEEK_END); - file_size = fz_tell(doc->file); - - maxback = fz_mini(file_size, 0xFFFF + sizeof buf); - back = fz_mini(maxback, sizeof buf); - - while (back < maxback) - { - fz_seek(doc->file, file_size - back, 0); - n = fz_read(doc->file, buf, sizeof buf); - for (i = n - 4; i > 0; i--) - { - if (!memcmp(buf + i, "PK\5\6", 4)) - { - xps_read_zip_dir(doc, file_size - back + i); - return; - } - } - - back += sizeof buf - 4; - } - - fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find end of central directory"); -} - -/* - * Read and interleave split parts from a ZIP file. - */ -static xps_part * -xps_read_zip_part(xps_document *doc, char *partname) -{ - char buf[2048]; - xps_entry *ent; - xps_part *part; - int count, size, offset, i; - char *name; - int seen_last = 0; - - name = partname; - if (name[0] == '/') - name ++; - - /* All in one piece */ - ent = xps_lookup_zip_entry(doc, name); - if (ent) - { - part = xps_new_part(doc, partname, ent->usize); - fz_try(doc->ctx) - { - xps_read_zip_entry(doc, ent, part->data); - } - fz_catch(doc->ctx) - { - xps_free_part(doc, part); - fz_rethrow(doc->ctx); - } - return part; - } - - /* Count the number of pieces and their total size */ - count = 0; - size = 0; - while (!seen_last) - { - sprintf(buf, "%s/[%d].piece", name, count); - ent = xps_lookup_zip_entry(doc, buf); - if (!ent) - { - sprintf(buf, "%s/[%d].last.piece", name, count); - ent = xps_lookup_zip_entry(doc, buf); - seen_last = (ent != NULL); - } - if (!ent) - break; - count ++; - size += ent->usize; - } - if (!seen_last) - fz_throw(doc->ctx, FZ_ERROR_GENERIC, "cannot find all pieces for part '%s'", partname); - - /* Inflate the pieces */ - if (count) - { - part = xps_new_part(doc, partname, size); - offset = 0; - for (i = 0; i < count; i++) - { - if (i < count - 1) - sprintf(buf, "%s/[%d].piece", name, i); - else - sprintf(buf, "%s/[%d].last.piece", name, i); - ent = xps_lookup_zip_entry(doc, buf); - fz_try(doc->ctx) - { - xps_read_zip_entry(doc, ent, part->data + offset); - } - fz_catch(doc->ctx) - { - xps_free_part(doc, part); - fz_rethrow(doc->ctx); - } - offset += ent->usize; - } - return part; - } - - fz_throw(doc->ctx, FZ_ERROR_GENERIC, "cannot find part '%s'", partname); - return NULL; -} - -static int -xps_has_zip_part(xps_document *doc, char *name) -{ - char buf[2048]; - if (name[0] == '/') - name++; - if (xps_lookup_zip_entry(doc, name)) - return 1; - sprintf(buf, "%s/[0].piece", name); - if (xps_lookup_zip_entry(doc, buf)) - return 1; - sprintf(buf, "%s/[0].last.piece", name); - if (xps_lookup_zip_entry(doc, buf)) - return 1; - return 0; -} - -/* - * Read and interleave split parts from files in the directory. - */ -static xps_part * -xps_read_dir_part(xps_document *doc, char *name) -{ - char buf[2048]; - xps_part *part; - FILE *file; - int count, size, offset, i, n; - int seen_last = 0; - - fz_strlcpy(buf, doc->directory, sizeof buf); - fz_strlcat(buf, name, sizeof buf); - - /* All in one piece */ - file = fopen(buf, "rb"); - if (file) - { - fseek(file, 0, SEEK_END); - size = ftell(file); - fseek(file, 0, SEEK_SET); - part = xps_new_part(doc, name, size); - fread(part->data, 1, size, file); - fclose(file); - return part; - } - - /* Count the number of pieces and their total size */ - count = 0; - size = 0; - while (!seen_last) - { - sprintf(buf, "%s%s/[%d].piece", doc->directory, name, count); - file = fopen(buf, "rb"); - if (!file) - { - sprintf(buf, "%s%s/[%d].last.piece", doc->directory, name, count); - file = fopen(buf, "rb"); - seen_last = (file != NULL); - } - if (!file) - break; - count ++; - fseek(file, 0, SEEK_END); - size += ftell(file); - fclose(file); - } - if (!seen_last) - fz_throw(doc->ctx, FZ_ERROR_GENERIC, "cannot find all pieces for part '%s'", name); - - /* Inflate the pieces */ - if (count) - { - part = xps_new_part(doc, name, size); - offset = 0; - for (i = 0; i < count; i++) - { - if (i < count - 1) - sprintf(buf, "%s%s/[%d].piece", doc->directory, name, i); - else - sprintf(buf, "%s%s/[%d].last.piece", doc->directory, name, i); - file = fopen(buf, "rb"); - if (!file) - { - xps_free_part(doc, part); - fz_throw(doc->ctx, FZ_ERROR_GENERIC, "cannot open file '%s'", buf); - } - n = fread(part->data + offset, 1, size - offset, file); - offset += n; - fclose(file); - } - return part; - } - - fz_throw(doc->ctx, FZ_ERROR_GENERIC, "cannot find part '%s'", name); - return NULL; -} - -static int -file_exists(xps_document *doc, char *name) -{ - char buf[2048]; - FILE *file; - fz_strlcpy(buf, doc->directory, sizeof buf); - fz_strlcat(buf, name, sizeof buf); - file = fopen(buf, "rb"); - if (file) - { - fclose(file); - return 1; - } - return 0; -} - -static int -xps_has_dir_part(xps_document *doc, char *name) -{ - char buf[2048]; - if (file_exists(doc, name)) - return 1; - sprintf(buf, "%s/[0].piece", name); - if (file_exists(doc, buf)) - return 1; - sprintf(buf, "%s/[0].last.piece", name); - if (file_exists(doc, buf)) - return 1; - return 0; -} - -xps_part * -xps_read_part(xps_document *doc, char *partname) -{ - if (doc->directory) - return xps_read_dir_part(doc, partname); - return xps_read_zip_part(doc, partname); -} - -int -xps_has_part(xps_document *doc, char *partname) -{ - if (doc->directory) - return xps_has_dir_part(doc, partname); - return xps_has_zip_part(doc, partname); -} - -static xps_document * -xps_open_document_with_directory(fz_context *ctx, const char *directory) -{ - xps_document *doc; - - doc = fz_malloc_struct(ctx, xps_document); - xps_init_document(doc); - doc->ctx = ctx; - doc->directory = fz_strdup(ctx, directory); - - fz_try(ctx) - { - xps_read_page_list(doc); - } - fz_catch(ctx) - { - xps_close_document(doc); - fz_rethrow(ctx); - } - - return doc; -} - -xps_document * -xps_open_document_with_stream(fz_context *ctx, fz_stream *file) -{ - xps_document *doc; - - doc = fz_malloc_struct(ctx, xps_document); - xps_init_document(doc); - doc->ctx = ctx; - doc->file = fz_keep_stream(file); - - fz_try(ctx) - { - xps_find_and_read_zip_dir(doc); - xps_read_page_list(doc); - } - fz_catch(ctx) - { - xps_close_document(doc); - fz_rethrow(ctx); - } - - return doc; -} - -xps_document * -xps_open_document(fz_context *ctx, const char *filename) -{ - char buf[2048]; - fz_stream *file; - char *p; - xps_document *doc; - - if (strstr(filename, "/_rels/.rels") || strstr(filename, "\\_rels\\.rels")) - { - fz_strlcpy(buf, filename, sizeof buf); - p = strstr(buf, "/_rels/.rels"); - if (!p) - p = strstr(buf, "\\_rels\\.rels"); - *p = 0; - return xps_open_document_with_directory(ctx, buf); - } - - file = fz_open_file(ctx, filename); - if (!file) - fz_throw(ctx, FZ_ERROR_GENERIC, "cannot open file '%s': %s", filename, strerror(errno)); - - fz_try(ctx) - { - doc = xps_open_document_with_stream(ctx, file); - } - fz_always(ctx) - { - fz_close(file); - } - fz_catch(ctx) - { - fz_rethrow_message(ctx, "cannot load document '%s'", filename); - } - return doc; -} - -void -xps_close_document(xps_document *doc) -{ - xps_font_cache *font, *next; - int i; - - if (!doc) - return; - - if (doc->file) - fz_close(doc->file); - - for (i = 0; i < doc->zip_count; i++) - fz_free(doc->ctx, doc->zip_table[i].name); - fz_free(doc->ctx, doc->zip_table); - - font = doc->font_table; - while (font) - { - next = font->next; - fz_drop_font(doc->ctx, font->font); - fz_free(doc->ctx, font->name); - fz_free(doc->ctx, font); - font = next; - } - - xps_free_page_list(doc); - - fz_free(doc->ctx, doc->start_part); - fz_free(doc->ctx, doc->directory); - fz_free(doc->ctx, doc); -} - -static int -xps_meta(xps_document *doc, int key, void *ptr, int size) -{ - switch (key) - { - case FZ_META_FORMAT_INFO: - sprintf((char *)ptr, "XPS"); - return FZ_META_OK; - default: - return FZ_META_UNKNOWN_KEY; - } -} - -static void -xps_init_document(xps_document *doc) -{ - doc->super.close = (void*)xps_close_document; - doc->super.load_outline = (void*)xps_load_outline; - doc->super.count_pages = (void*)xps_count_pages; - doc->super.load_page = (void*)xps_load_page; - doc->super.load_links = (void*)xps_load_links; - doc->super.bound_page = (void*)xps_bound_page; - doc->super.run_page_contents = (void*)xps_run_page; - doc->super.free_page = (void*)xps_free_page; - doc->super.meta = (void*)xps_meta; -} |