summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Andersson <tor@ghostscript.com>2005-05-24 08:06:42 +0200
committerTor Andersson <tor@ghostscript.com>2005-05-24 08:06:42 +0200
commit5d192ce275815e6f3eb8eb1015b02612180a8e56 (patch)
tree713c49b9b4ab4ff77e8795ee8e6f969d2d9aab75
parent04334c84b883840ec8bbe62d48e57df5f6408ca7 (diff)
downloadmupdf-5d192ce275815e6f3eb8eb1015b02612180a8e56.tar.xz
metro packages and parts
-rw-r--r--Jamfile4
-rw-r--r--apps/samshow.c99
-rw-r--r--apps/samtiff.c23
-rw-r--r--apps/samxml.c28
-rw-r--r--apps/samzip.c37
-rw-r--r--include/samus/package.h12
-rw-r--r--include/samus/xml.h8
-rw-r--r--include/samus/zip.h5
-rw-r--r--samus/sa_pack.c187
-rw-r--r--samus/sa_xml.c14
-rw-r--r--samus/sa_zip.c141
11 files changed, 391 insertions, 167 deletions
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 <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);
}