diff options
author | Tor Andersson <tor@ghostscript.com> | 2005-05-24 08:06:42 +0200 |
---|---|---|
committer | Tor Andersson <tor@ghostscript.com> | 2005-05-24 08:06:42 +0200 |
commit | 5d192ce275815e6f3eb8eb1015b02612180a8e56 (patch) | |
tree | 713c49b9b4ab4ff77e8795ee8e6f969d2d9aab75 | |
parent | 04334c84b883840ec8bbe62d48e57df5f6408ca7 (diff) | |
download | mupdf-5d192ce275815e6f3eb8eb1015b02612180a8e56.tar.xz |
metro packages and parts
-rw-r--r-- | Jamfile | 4 | ||||
-rw-r--r-- | apps/samshow.c | 99 | ||||
-rw-r--r-- | apps/samtiff.c | 23 | ||||
-rw-r--r-- | apps/samxml.c | 28 | ||||
-rw-r--r-- | apps/samzip.c | 37 | ||||
-rw-r--r-- | include/samus/package.h | 12 | ||||
-rw-r--r-- | include/samus/xml.h | 8 | ||||
-rw-r--r-- | include/samus/zip.h | 5 | ||||
-rw-r--r-- | samus/sa_pack.c | 187 | ||||
-rw-r--r-- | samus/sa_xml.c | 14 | ||||
-rw-r--r-- | samus/sa_zip.c | 141 |
11 files changed, 391 insertions, 167 deletions
@@ -287,9 +287,7 @@ APPLIST = pdfdebug pdfmerge pdfselect - samzip - samxml - samtiff + samshow ; for APP in $(APPLIST) diff --git a/apps/samshow.c b/apps/samshow.c new file mode 100644 index 00000000..d84799a0 --- /dev/null +++ b/apps/samshow.c @@ -0,0 +1,99 @@ +#include "fitz.h" +#include "samus.h" + +int runzip(int argc, char **argv) +{ + fz_error *error; + fz_buffer *buf; + sa_zip *zip; + int i; + + error = sa_openzip(&zip, argv[1]); + if (error) + fz_abort(error); + + if (argc == 2) + sa_debugzip(zip); + + for (i = 2; i < argc; i++) + { + error = sa_openzipentry(zip, argv[i]); + if (error) + fz_abort(error); + error = fz_readfile(&buf, zip->file); + if (error) + fz_abort(error); + sa_closezipentry(zip); + + fwrite(buf->rp, 1, buf->wp - buf->rp, stdout); + + fz_dropbuffer(buf); + } + + sa_closezip(zip); + + return 0; +} + +int runxml(int argc, char **argv) +{ + fz_error *error; + fz_file *file; + sa_xmlparser *parser; + sa_xmlitem *item; + + error = fz_openfile(&file, argv[1], FZ_READ); + if (error) + fz_abort(error); + + error = sa_openxml(&parser, file, 0); + if (error) + fz_abort(error); + + item = sa_xmlnext(parser); + if (item) + sa_debugxml(item, 0); + + sa_closexml(parser); + fz_closefile(file); + + return 0; +} + +extern fz_error *sa_readtiff(fz_file *); + +int runtiff(int argc, char **argv) +{ + fz_error *error; + fz_file *file; + + error = fz_openfile(&file, argv[1], FZ_READ); + if (error) + fz_abort(error); + + error = sa_readtiff(file); + if (error) + fz_abort(error); + + fz_closefile(file); + + return 0; +} + +int main(int argc, char **argv) +{ + if (argc >= 2) + { + if (strstr(argv[1], "zip")) + return runzip(argc, argv); + if (strstr(argv[1], "xml")) + return runxml(argc, argv); + if (strstr(argv[1], "tif")) + return runtiff(argc, argv); + } + + fprintf(stderr, "usage: samshow <file>\n"); + fprintf(stderr, "usage: samshow <zipfile> <partname>\n"); + return 1; +} + diff --git a/apps/samtiff.c b/apps/samtiff.c deleted file mode 100644 index 80d3f051..00000000 --- a/apps/samtiff.c +++ /dev/null @@ -1,23 +0,0 @@ -#include "fitz.h" -#include "samus.h" - -extern fz_error *sa_readtiff(fz_file *); - -int main(int argc, char **argv) -{ - fz_error *error; - fz_file *file; - - error = fz_openfile(&file, argv[1], FZ_READ); - if (error) - fz_abort(error); - - error = sa_readtiff(file); - if (error) - fz_abort(error); - - fz_closefile(file); - - return 0; -} - diff --git a/apps/samxml.c b/apps/samxml.c deleted file mode 100644 index c42d8036..00000000 --- a/apps/samxml.c +++ /dev/null @@ -1,28 +0,0 @@ -#include "fitz.h" -#include "samus.h" - -int main(int argc, char **argv) -{ - fz_error *error; - fz_file *file; - sa_xmlparser *parser; - sa_xmlitem *item; - - error = fz_openfile(&file, argv[1], FZ_READ); - if (error) - fz_abort(error); - - error = sa_openxml(&parser, file, 0); - if (error) - fz_abort(error); - - item = sa_xmlnext(parser); - if (item) - sa_debugxml(item, 0); - - sa_closexml(parser); - fz_closefile(file); - - return 0; -} - diff --git a/apps/samzip.c b/apps/samzip.c deleted file mode 100644 index 8284108b..00000000 --- a/apps/samzip.c +++ /dev/null @@ -1,37 +0,0 @@ -#include "fitz.h" -#include "samus.h" - -int main(int argc, char **argv) -{ - fz_error *error; - fz_buffer *buf; - sa_zip *zip; - int i; - - error = sa_openzip(&zip, argv[1]); - if (error) - fz_abort(error); - - if (argc == 2) - sa_debugzip(zip); - - for (i = 2; i < argc; i++) - { - error = sa_openzipstream(zip, argv[i]); - if (error) - fz_abort(error); - error = fz_readfile(&buf, zip->file); - if (error) - fz_abort(error); - sa_closezipstream(zip); - - fwrite(buf->rp, 1, buf->wp - buf->rp, stdout); - - fz_dropbuffer(buf); - } - - sa_closezip(zip); - - return 0; -} - diff --git a/include/samus/package.h b/include/samus/package.h new file mode 100644 index 00000000..4c8512f7 --- /dev/null +++ b/include/samus/package.h @@ -0,0 +1,12 @@ +/* + * Metro Package and Parts + */ + +typedef struct sa_package_s sa_package; + +fz_error *sa_openpackage(sa_package **packp, char *filename); +char *sa_accesspart(sa_package *pack, char *partname); +fz_error *sa_openpart(fz_file **filep, sa_package *pack, char *partname); +void sa_closepart(sa_package *pack, fz_file *file); +void sa_closepackage(sa_package *pack); + diff --git a/include/samus/xml.h b/include/samus/xml.h index fa798cd3..56c19b0a 100644 --- a/include/samus/xml.h +++ b/include/samus/xml.h @@ -19,8 +19,8 @@ int sa_isxmlerror(sa_xmlitem *item); int sa_isxmltext(sa_xmlitem *item); int sa_isxmltag(sa_xmlitem *item); -char *sa_getxmlerror(sa_xmlitem *item); -char *sa_getxmlname(sa_xmlitem *item); -char *sa_getxmlatt(sa_xmlitem *item, char *att); -char *sa_getxmltext(sa_xmlitem *item); +char *sa_xmlerror(sa_xmlitem *item); +char *sa_xmlname(sa_xmlitem *item); +char *sa_xmlatt(sa_xmlitem *item, char *att); +char *sa_xmltext(sa_xmlitem *item); diff --git a/include/samus/zip.h b/include/samus/zip.h index 656fc731..2d3635f7 100644 --- a/include/samus/zip.h +++ b/include/samus/zip.h @@ -23,6 +23,7 @@ struct sa_zip_s fz_error *sa_openzip(sa_zip **zipp, char *filename); void sa_debugzip(sa_zip *zip); void sa_closezip(sa_zip *zip); -fz_error *sa_openzipstream(sa_zip *zip, char *name); -void sa_closezipstream(sa_zip *zip); +int sa_accesszipentry(sa_zip *zip, char *name); +fz_error *sa_openzipentry(sa_zip *zip, char *name); +void sa_closezipentry(sa_zip *zip); diff --git a/samus/sa_pack.c b/samus/sa_pack.c new file mode 100644 index 00000000..e1f910ba --- /dev/null +++ b/samus/sa_pack.c @@ -0,0 +1,187 @@ +/*
+ * Metro physical packages and parts, mapped to a zip archive.
+ */
+
+#include "fitz.h"
+#include "samus.h"
+
+struct sa_package_s
+{
+ sa_zip *zip;
+ fz_obj *defaults;
+ fz_obj *overrides;
+};
+
+static fz_error *
+readcontenttypes(sa_package *pack)
+{
+ fz_error *error;
+ sa_xmlparser *parser;
+ sa_xmlitem *item;
+ fz_obj *val;
+
+ error = fz_newdict(&pack->defaults, 8);
+ if (error)
+ return error;
+
+ error = fz_newdict(&pack->overrides, 8);
+ if (error)
+ return error;
+
+ error = sa_openzipentry(pack->zip, "[Content_Types].xml");
+ if (error)
+ return error;
+
+ error = sa_openxml(&parser, pack->zip->file, 0);
+ if (error)
+ goto cleanupzip;
+
+ item = sa_xmlnext(parser);
+ if (item && !strcmp(sa_xmlname(item), "Types"))
+ {
+ sa_xmldown(parser);
+ item = sa_xmlnext(parser);
+ while (item)
+ {
+ if (!strcmp(sa_xmlname(item), "Default"))
+ {
+ char *ext = sa_xmlatt(item, "Extension");
+ char *type = sa_xmlatt(item, "ContentType");
+ if (ext && type)
+ {
+ if (strstr(type, ';'))
+ strstr(type, ';')[0] = 0;
+ error = fz_newname(&val, type);
+ if (error)
+ goto cleanupxml;
+ error = fz_dictputs(pack->defaults, ext, val);
+ if (error)
+ goto cleanupval;
+ val = nil;
+ }
+ }
+
+ if (!strcmp(sa_xmlname(item), "Override"))
+ {
+ char *name = sa_xmlatt(item, "PartName");
+ char *type = sa_xmlatt(item, "ContentType");
+ if (name && type)
+ {
+ if (strstr(type, ';'))
+ strstr(type, ';')[0] = 0;
+ error = fz_newname(&val, type);
+ if (error)
+ goto cleanupxml;
+ error = fz_dictputs(pack->overrides, name, val);
+ if (error)
+ goto cleanupval;
+ val = nil;
+ }
+ }
+
+ item = sa_xmlnext(parser);
+ }
+ sa_xmlup(parser);
+ }
+
+ sa_closexml(parser);
+ sa_closezipentry(pack->zip);
+ return nil;
+
+cleanupval:
+ fz_dropobj(val);
+cleanupxml:
+ sa_closexml(parser);
+cleanupzip:
+ sa_closezipentry(pack->zip);
+ return error;
+}
+
+fz_error *
+sa_openpackage(sa_package **packp, char *filename)
+{
+ fz_error *error;
+ sa_package *pack;
+
+ pack = fz_malloc(sizeof(sa_package));
+ if (!pack)
+ return fz_outofmem;
+
+ pack->zip = nil;
+ pack->defaults = nil;
+ pack->overrides = nil;
+
+ error = sa_openzip(&pack->zip, filename);
+ if (error)
+ {
+ sa_closepackage(pack);
+ return error;
+ }
+
+ error = readcontenttypes(pack->zip);
+ if (error)
+ {
+ sa_closepackage(pack);
+ return error;
+ }
+
+ *packp = pack;
+ return nil;
+}
+
+void
+sa_closepackage(sa_package *pack)
+{
+ if (pack->zip) sa_closezip(pack->zip);
+ if (pack->defaults) fz_dropobj(pack->defaults);
+ if (pack->overrides) fz_dropobj(pack->overrides);
+ fz_free(pack);
+}
+
+/*
+ * Check access of a part, return either nil or its mime-type.
+ */
+char *
+sa_accesspart(sa_package *pack, char *partname)
+{
+ fz_obj *type;
+ char *ext;
+
+ if (sa_accesszipentry(pack->zip, partname))
+ {
+ type = fz_dictgets(pack->overrides, partname);
+ if (type)
+ return fz_toname(type);
+
+ ext = strrstr(partname, ".");
+ if (ext)
+ {
+ type = fz_dictgets(pack->defaults, ext + 1);
+ if (type)
+ return fz_toname(type);
+ }
+ }
+
+ return nil;
+}
+
+/*
+ * Open a part for reading. It is NOT safe to open more than one
+ * part at a time.
+ */
+fz_error *
+sa_openpart(fz_file **filep, sa_package *pack, char *partname)
+{
+ *filep = pack->zip->file;
+ return sa_openzipentry(pack->zip, partname);
+}
+
+/*
+ * Call this instead of fz_closefile()
+ * FIXME i gotto do something about this icky file API
+ */
+void sa_closepart(sa_package *pack, fz_file *file)
+{
+ sa_closezipentry(pack->zip);
+}
+
diff --git a/samus/sa_xml.c b/samus/sa_xml.c index 3dd4f02e..198ef6b2 100644 --- a/samus/sa_xml.c +++ b/samus/sa_xml.c @@ -255,7 +255,7 @@ sa_debugxml(sa_xmlitem *item, int level) indent(level); if (sa_isxmltext(item)) - printf("%s\n", sa_getxmltext(item)); + printf("%s\n", sa_xmltext(item)); else { printf("<%s", item->name); @@ -320,23 +320,23 @@ sa_xmlup(sa_xmlparser *sp) int sa_isxmlerror(sa_xmlitem *item) { - return item->name[0] == '!'; + return item && item->name[0] == '!'; } int sa_isxmltext(sa_xmlitem *item) { - return item->name[0] == '\0'; + return item && item->name[0] == '\0'; } int sa_isxmltag(sa_xmlitem *item) { - return item->name[0] != '\0' && item->name[0] != '!'; + return item && item->name[0] != '\0' && item->name[0] != '!'; } char * -sa_getxmlname(sa_xmlitem *item) +sa_xmlname(sa_xmlitem *item) { if (sa_isxmltag(item)) return item->name; @@ -344,7 +344,7 @@ sa_getxmlname(sa_xmlitem *item) } char * -sa_getxmlatt(sa_xmlitem *item, char *att) +sa_xmlatt(sa_xmlitem *item, char *att) { int i; if (sa_isxmltag(item)) @@ -357,7 +357,7 @@ sa_getxmlatt(sa_xmlitem *item, char *att) } char * -sa_getxmltext(sa_xmlitem *item) +sa_xmltext(sa_xmlitem *item) { if (sa_isxmltext(item)) return item->atts[1]; diff --git a/samus/sa_zip.c b/samus/sa_zip.c index d85974ac..a989f16d 100644 --- a/samus/sa_zip.c +++ b/samus/sa_zip.c @@ -4,6 +4,9 @@ * - no multi-disk * - only Store and Deflate * - ZIP64 format (long long sizes and offsets) [TODO] + * + * TODO for Metro compliance: compare file names by unescaping %XX + * and then converting to upper-case NFC. */ #include "fitz.h" @@ -196,11 +199,20 @@ sa_debugzip(sa_zip *zip) } } +int +sa_accesszipentry(sa_zip *zip, char *name) +{ + int i; + for (i = 0; i < zip->len; i++) + if (!strcmp(name, zip->table[i].name)) + return 1; + return 0; +} + /* * Seek and push decoding filter to read an individual file in the zip archive. */ -fz_error * -sa_openzipstream(sa_zip *zip, char *name) +static fz_error *reallyopenzipentry(sa_zip *zip, int idx) { fz_error *error; fz_filter *filter; @@ -209,70 +221,73 @@ sa_openzipstream(sa_zip *zip, char *name) unsigned csize, usize; unsigned namesize, metasize; int t; + + t = fz_seek(zip->file, zip->table[idx].offset, 0); + if (t < 0) + return fz_ferror(zip->file); + + sign = read4(zip->file); + if (sign != 0x04034b50) + return fz_throw("ioerror: unknown zip signature"); + + version = read2(zip->file); + general = read2(zip->file); + method = read2(zip->file); + (void) read2(zip->file); /* time */ + (void) read2(zip->file); /* date */ + (void) read4(zip->file); /* crc-32 */ + csize = read4(zip->file); + usize = read4(zip->file); + namesize = read2(zip->file); + metasize = read2(zip->file); + + if ((version & 0xff) > 45) + return fz_throw("ioerror: unsupported zip version"); + + if (general & 0x0001) + return fz_throw("ioerror: encrypted zip entry"); + + fz_seek(zip->file, namesize + metasize, 1); + + switch (method) + { + case 0: + error = fz_newnullfilter(&filter, csize); + if (error) + return error; + break; + + case 8: + error = fz_packobj(&obj, "<</ZIP true>>"); + if (error) + return error; + error = fz_newflated(&filter, obj); + fz_dropobj(obj); + if (error) + return error; + break; + + default: + return fz_throw("ioerror: unsupported compression method"); + break; + } + + error = fz_pushfilter(zip->file, filter); + fz_dropfilter(filter); + if (error) + return error; + + return nil; +} + +fz_error * +sa_openzipentry(sa_zip *zip, char *name) +{ int i; for (i = 0; i < zip->len; i++) - { if (!strcmp(name, zip->table[i].name)) - { - t = fz_seek(zip->file, zip->table[i].offset, 0); - if (t < 0) - return fz_ferror(zip->file); - - sign = read4(zip->file); - if (sign != 0x04034b50) - return fz_throw("ioerror: unknown zip signature"); - - version = read2(zip->file); - general = read2(zip->file); - method = read2(zip->file); - (void) read2(zip->file); /* time */ - (void) read2(zip->file); /* date */ - (void) read4(zip->file); /* crc-32 */ - csize = read4(zip->file); - usize = read4(zip->file); - namesize = read2(zip->file); - metasize = read2(zip->file); - - if ((version & 0xff) > 45) - return fz_throw("ioerror: unsupported zip version"); - - if (general & 0x0001) - return fz_throw("ioerror: encrypted zip entry"); - - fz_seek(zip->file, namesize + metasize, 1); - - switch (method) - { - case 0: - error = fz_newnullfilter(&filter, csize); - if (error) - return error; - break; - - case 8: - error = fz_packobj(&obj, "<</ZIP true>>"); - if (error) - return error; - error = fz_newflated(&filter, obj); - fz_dropobj(obj); - if (error) - return error; - break; - - default: - return fz_throw("ioerror: unsupported compression method"); - break; - } - - error = fz_pushfilter(zip->file, filter); - fz_dropfilter(filter); - if (error) - return error; - - return nil; - } - } + return reallyopenzipentry(zip, i); return fz_throw("ioerror: file not found in zip: '%s'", name); } @@ -281,7 +296,7 @@ sa_openzipstream(sa_zip *zip, char *name) * Pop decompression filter and clean up after reading a file in the archive. */ void -sa_closezipstream(sa_zip *zip) +sa_closezipentry(sa_zip *zip) { fz_popfilter(zip->file); } |