From 5d192ce275815e6f3eb8eb1015b02612180a8e56 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Tue, 24 May 2005 08:06:42 +0200 Subject: metro packages and parts --- Jamfile | 4 +- apps/samshow.c | 99 +++++++++++++++++++++++++ apps/samtiff.c | 23 ------ apps/samxml.c | 28 -------- apps/samzip.c | 37 ---------- include/samus/package.h | 12 ++++ include/samus/xml.h | 8 +-- include/samus/zip.h | 5 +- samus/sa_pack.c | 187 ++++++++++++++++++++++++++++++++++++++++++++++++ samus/sa_xml.c | 14 ++-- samus/sa_zip.c | 141 ++++++++++++++++++++---------------- 11 files changed, 391 insertions(+), 167 deletions(-) create mode 100644 apps/samshow.c delete mode 100644 apps/samtiff.c delete mode 100644 apps/samxml.c delete mode 100644 apps/samzip.c create mode 100644 include/samus/package.h create mode 100644 samus/sa_pack.c diff --git a/Jamfile b/Jamfile index f50ad08a..5e6d6cfa 100644 --- a/Jamfile +++ b/Jamfile @@ -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 \n"); + fprintf(stderr, "usage: samshow \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, "<>"); + 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, "<>"); - 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); } -- cgit v1.2.3