Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. #include "fitz.h"
  2. #include "muxps.h"
  3.  
  4. /*
  5.  * The FixedDocumentSequence and FixedDocument parts determine
  6.  * which parts correspond to actual pages, and the page order.
  7.  */
  8.  
  9. void
  10. xps_debug_page_list(xps_context *ctx)
  11. {
  12.         xps_document *fixdoc = ctx->first_fixdoc;
  13.         xps_page *page = ctx->first_page;
  14.  
  15.         if (ctx->start_part)
  16.                 printf("start part %s\n", ctx->start_part);
  17.  
  18.         while (fixdoc)
  19.         {
  20.                 printf("fixdoc %s\n", fixdoc->name);
  21.                 fixdoc = fixdoc->next;
  22.         }
  23.  
  24.         while (page)
  25.         {
  26.                 printf("page %s w=%d h=%d\n", page->name, page->width, page->height);
  27.                 page = page->next;
  28.         }
  29. }
  30.  
  31. static void
  32. xps_add_fixed_document(xps_context *ctx, char *name)
  33. {
  34.         xps_document *fixdoc;
  35.  
  36.         /* Check for duplicates first */
  37.         for (fixdoc = ctx->first_fixdoc; fixdoc; fixdoc = fixdoc->next)
  38.                 if (!strcmp(fixdoc->name, name))
  39.                         return;
  40.  
  41.         fixdoc = fz_malloc(sizeof(xps_document));
  42.         fixdoc->name = fz_strdup(name);
  43.         fixdoc->next = NULL;
  44.  
  45.         if (!ctx->first_fixdoc)
  46.         {
  47.                 ctx->first_fixdoc = fixdoc;
  48.                 ctx->last_fixdoc = fixdoc;
  49.         }
  50.         else
  51.         {
  52.                 ctx->last_fixdoc->next = fixdoc;
  53.                 ctx->last_fixdoc = fixdoc;
  54.         }
  55. }
  56.  
  57. static void
  58. xps_add_fixed_page(xps_context *ctx, char *name, int width, int height)
  59. {
  60.         xps_page *page;
  61.  
  62.         /* Check for duplicates first */
  63.         for (page = ctx->first_page; page; page = page->next)
  64.                 if (!strcmp(page->name, name))
  65.                         return;
  66.  
  67.         page = fz_malloc(sizeof(xps_page));
  68.         page->name = fz_strdup(name);
  69.         page->width = width;
  70.         page->height = height;
  71.         page->root = NULL;
  72.         page->next = NULL;
  73.  
  74.         if (!ctx->first_page)
  75.         {
  76.                 ctx->first_page = page;
  77.                 ctx->last_page = page;
  78.         }
  79.         else
  80.         {
  81.                 ctx->last_page->next = page;
  82.                 ctx->last_page = page;
  83.         }
  84. }
  85.  
  86. static void
  87. xps_free_fixed_pages(xps_context *ctx)
  88. {
  89.         xps_page *page = ctx->first_page;
  90.         while (page)
  91.         {
  92.                 xps_page *next = page->next;
  93.                 xps_free_page(ctx, page);
  94.                 fz_free(page->name);
  95.                 fz_free(page);
  96.                 page = next;
  97.         }
  98.         ctx->first_page = NULL;
  99.         ctx->last_page = NULL;
  100. }
  101.  
  102. static void
  103. xps_free_fixed_documents(xps_context *ctx)
  104. {
  105.         xps_document *doc = ctx->first_fixdoc;
  106.         while (doc)
  107.         {
  108.                 xps_document *next = doc->next;
  109.                 fz_free(doc->name);
  110.                 fz_free(doc);
  111.                 doc = next;
  112.         }
  113.         ctx->first_fixdoc = NULL;
  114.         ctx->last_fixdoc = NULL;
  115. }
  116.  
  117. void
  118. xps_free_page_list(xps_context *ctx)
  119. {
  120.         xps_free_fixed_documents(ctx);
  121.         xps_free_fixed_pages(ctx);
  122. }
  123.  
  124. /*
  125.  * Parse the fixed document sequence structure and _rels/.rels to find the start part.
  126.  */
  127.  
  128. static void
  129. xps_parse_metadata_imp(xps_context *ctx, xml_element *item)
  130. {
  131.         while (item)
  132.         {
  133.                 xps_parse_metadata_imp(ctx, xml_down(item));
  134.  
  135.                 if (!strcmp(xml_tag(item), "Relationship"))
  136.                 {
  137.                         char *target = xml_att(item, "Target");
  138.                         char *type = xml_att(item, "Type");
  139.                         if (target && type)
  140.                         {
  141.                                 char tgtbuf[1024];
  142.                                 xps_absolute_path(tgtbuf, ctx->base_uri, target, sizeof tgtbuf);
  143.                                 if (!strcmp(type, REL_START_PART))
  144.                                         ctx->start_part = fz_strdup(tgtbuf);
  145.                         }
  146.                 }
  147.  
  148.                 if (!strcmp(xml_tag(item), "DocumentReference"))
  149.                 {
  150.                         char *source = xml_att(item, "Source");
  151.                         if (source)
  152.                         {
  153.                                 char srcbuf[1024];
  154.                                 xps_absolute_path(srcbuf, ctx->base_uri, source, sizeof srcbuf);
  155.                                 xps_add_fixed_document(ctx, srcbuf);
  156.                         }
  157.                 }
  158.  
  159.                 if (!strcmp(xml_tag(item), "PageContent"))
  160.                 {
  161.                         char *source = xml_att(item, "Source");
  162.                         char *width_att = xml_att(item, "Width");
  163.                         char *height_att = xml_att(item, "Height");
  164.                         int width = width_att ? atoi(width_att) : 0;
  165.                         int height = height_att ? atoi(height_att) : 0;
  166.                         if (source)
  167.                         {
  168.                                 char srcbuf[1024];
  169.                                 xps_absolute_path(srcbuf, ctx->base_uri, source, sizeof srcbuf);
  170.                                 xps_add_fixed_page(ctx, srcbuf, width, height);
  171.                         }
  172.                 }
  173.  
  174.                 item = xml_next(item);
  175.         }
  176. }
  177.  
  178. static int
  179. xps_parse_metadata(xps_context *ctx, xps_part *part)
  180. {
  181.         xml_element *root;
  182.         char buf[1024];
  183.         char *s;
  184.  
  185.         /* Save directory name part */
  186.         fz_strlcpy(buf, part->name, sizeof buf);
  187.         s = strrchr(buf, '/');
  188.         if (s)
  189.                 s[0] = 0;
  190.  
  191.         /* _rels parts are voodoo: their URI references are from
  192.          * the part they are associated with, not the actual _rels
  193.          * part being parsed.
  194.          */
  195.         s = strstr(buf, "/_rels");
  196.         if (s)
  197.                 *s = 0;
  198.  
  199.         ctx->base_uri = buf;
  200.         ctx->part_uri = part->name;
  201.  
  202.         root = xml_parse_document(part->data, part->size);
  203.         if (!root)
  204.                 return fz_rethrow(-1, "cannot parse metadata part '%s'", part->name);
  205.  
  206.         xps_parse_metadata_imp(ctx, root);
  207.  
  208.         xml_free_element(root);
  209.  
  210.         ctx->base_uri = NULL;
  211.         ctx->part_uri = NULL;
  212.  
  213.         return fz_okay;
  214. }
  215.  
  216. static int
  217. xps_read_and_process_metadata_part(xps_context *ctx, char *name)
  218. {
  219.         xps_part *part;
  220.         int code;
  221.  
  222.         part = xps_read_part(ctx, name);
  223.         if (!part)
  224.                 return fz_rethrow(-1, "cannot read zip part '%s'", name);
  225.  
  226.         code = xps_parse_metadata(ctx, part);
  227.         if (code)
  228.                 return fz_rethrow(code, "cannot process metadata part '%s'", name);
  229.  
  230.         xps_free_part(ctx, part);
  231.  
  232.         return fz_okay;
  233. }
  234.  
  235. int
  236. xps_read_page_list(xps_context *ctx)
  237. {
  238.         xps_document *doc;
  239.         int code;
  240.  
  241.         code = xps_read_and_process_metadata_part(ctx, "/_rels/.rels");
  242.         if (code)
  243.                 return fz_rethrow(code, "cannot process root relationship part");
  244.  
  245.         if (!ctx->start_part)
  246.                 return fz_throw("cannot find fixed document sequence start part");
  247.  
  248.         code = xps_read_and_process_metadata_part(ctx, ctx->start_part);
  249.         if (code)
  250.                 return fz_rethrow(code, "cannot process FixedDocumentSequence part");
  251.  
  252.         for (doc = ctx->first_fixdoc; doc; doc = doc->next)
  253.         {
  254.                 code = xps_read_and_process_metadata_part(ctx, doc->name);
  255.                 if (code)
  256.                         return fz_rethrow(code, "cannot process FixedDocument part");
  257.         }
  258.  
  259.         return fz_okay;
  260. }
  261.  
  262. int
  263. xps_count_pages(xps_context *ctx)
  264. {
  265.         xps_page *page;
  266.         int n = 0;
  267.         for (page = ctx->first_page; page; page = page->next)
  268.                 n ++;
  269.         return n;
  270. }
  271.  
  272. static int
  273. xps_load_fixed_page(xps_context *ctx, xps_page *page)
  274. {
  275.         xps_part *part;
  276.         xml_element *root;
  277.         char *width_att;
  278.         char *height_att;
  279.  
  280.         part = xps_read_part(ctx, page->name);
  281.         if (!part)
  282.                 return fz_rethrow(-1, "cannot read zip part '%s'", page->name);
  283.  
  284.         root = xml_parse_document(part->data, part->size);
  285.         if (!root)
  286.                 return fz_rethrow(-1, "cannot parse xml part '%s'", page->name);
  287.  
  288.         xps_free_part(ctx, part);
  289.  
  290.         if (strcmp(xml_tag(root), "FixedPage"))
  291.                 return fz_throw("expected FixedPage element (found %s)", xml_tag(root));
  292.  
  293.         width_att = xml_att(root, "Width");
  294.         if (!width_att)
  295.                 return fz_throw("FixedPage missing required attribute: Width");
  296.  
  297.         height_att = xml_att(root, "Height");
  298.         if (!height_att)
  299.                 return fz_throw("FixedPage missing required attribute: Height");
  300.  
  301.         page->width = atoi(width_att);
  302.         page->height = atoi(height_att);
  303.         page->root = root;
  304.  
  305.         return 0;
  306. }
  307.  
  308. int
  309. xps_load_page(xps_page **pagep, xps_context *ctx, int number)
  310. {
  311.         xps_page *page;
  312.         int code;
  313.         int n = 0;
  314.  
  315.         for (page = ctx->first_page; page; page = page->next)
  316.         {
  317.                 if (n == number)
  318.                 {
  319.                         if (!page->root)
  320.                         {
  321.                                 code = xps_load_fixed_page(ctx, page);
  322.                                 if (code)
  323.                                         return fz_rethrow(code, "cannot load page %d", number + 1);
  324.                         }
  325.                         *pagep = page;
  326.                         return fz_okay;
  327.                 }
  328.                 n ++;
  329.         }
  330.  
  331.         return fz_throw("cannot find page %d", number + 1);
  332. }
  333.  
  334. void
  335. xps_free_page(xps_context *ctx, xps_page *page)
  336. {
  337.         /* only free the XML contents */
  338.         if (page->root)
  339.                 xml_free_element(page->root);
  340.         page->root = NULL;
  341. }
  342.