home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / pdflb302.zip / pdf / pdflib-3.0.2 / pdflib / p_hyper.c < prev    next >
C/C++ Source or Header  |  2000-08-21  |  13KB  |  459 lines

  1. /*---------------------------------------------------------------------------*
  2.  |        PDFlib - A library for dynamically generating PDF documents        |
  3.  +---------------------------------------------------------------------------+
  4.  |        Copyright (c) 1997-2000 Thomas Merz. All rights reserved.          |
  5.  +---------------------------------------------------------------------------+
  6.  |    This software is NOT in the public domain.  It can be used under two   |
  7.  |    substantially different licensing terms:                               |
  8.  |                                                                           |
  9.  |    The commercial license is available for a fee, and allows you to       |
  10.  |    - ship a commercial product based on PDFlib                            |
  11.  |    - implement commercial Web services with PDFlib                        |
  12.  |    - distribute (free or commercial) software when the source code is     |
  13.  |      not made available                                                   |
  14.  |    Details can be found in the file PDFlib-license.pdf.                   |
  15.  |                                                                           |
  16.  |    The "Aladdin Free Public License" doesn't require any license fee,     |
  17.  |    and allows you to                                                      |
  18.  |    - develop and distribute PDFlib-based software for which the complete  |
  19.  |      source code is made available                                        |
  20.  |    - redistribute PDFlib non-commercially under certain conditions        |
  21.  |    - redistribute PDFlib on digital media for a fee if the complete       |
  22.  |      contents of the media are freely redistributable                     |
  23.  |    Details can be found in the file aladdin-license.pdf.                  |
  24.  |                                                                           |
  25.  |    These conditions extend to ports to other programming languages.       |
  26.  |    PDFlib is distributed with no warranty of any kind. Commercial users,  |
  27.  |    however, will receive warranty and support statements in writing.      |
  28.  *---------------------------------------------------------------------------*/
  29.  
  30. /* p_hyper.c
  31.  *
  32.  * PDFlib routines for hypertext stuff: bookmarks, document info, transitions
  33.  *
  34.  */
  35.  
  36. #include <stdlib.h>
  37. #include <string.h>
  38. #include <time.h>
  39.  
  40. #include "p_intern.h"
  41.  
  42. /* We can't work with pointers in the outline objects because
  43.  * the complete outline block may be reallocated. Therefore we use
  44.  * this simple mechanism for achieving indirection.
  45.  */
  46. #define COUNT(index)    (p->outlines[index].count)
  47. #define OPEN(index)    (p->outlines[index].open)
  48. #define LAST(index)    (p->outlines[index].last)
  49. #define PARENT(index)    (p->outlines[index].parent)
  50. #define FIRST(index)    (p->outlines[index].first)
  51. #define SELF(index)    (p->outlines[index].self)
  52. #define PREV(index)    (p->outlines[index].prev)
  53. #define NEXT(index)    (p->outlines[index].next)
  54.  
  55. void
  56. pdf_init_outlines(PDF *p)
  57. {
  58.     p->outline_count    = 0;
  59. }
  60.  
  61. /* Free outline entries */
  62. void
  63. pdf_cleanup_outlines(PDF *p)
  64. {
  65.     int i;
  66.  
  67.     if (!p->outlines || p->outline_count == 0)
  68.     return;
  69.  
  70.     /* outlines[0] is the outline root object */
  71.     for (i = 0; i <= p->outline_count; i++)
  72.     if (p->outlines[i].text)
  73.         p->free(p, p->outlines[i].text);
  74.  
  75.     p->free(p, (void*) p->outlines);
  76.  
  77.     p->outlines = NULL;
  78. }
  79.  
  80. static void
  81. pdf_write_outline_dict(PDF *p, int entry)
  82. {
  83.     pdf_desttype type;
  84.     long page;
  85.  
  86.     pdf_begin_obj(p, SELF(entry));    /* outline object */
  87.     pdf_begin_dict(p);
  88.  
  89.     pdf_printf(p, "/Parent %ld 0 R\n", SELF(PARENT(entry)));
  90.  
  91.     type = p->outlines[entry].dest.type;
  92.     page = p->pages[p->outlines[entry].dest.page];
  93.  
  94.     /* outline destination */
  95.     if (type == retain) {
  96.     pdf_printf(p, "/Dest[%ld 0 R/XYZ null null 0]\n", page);
  97.     } else if (type == fitpage) {
  98.     pdf_printf(p, "/Dest[%ld 0 R/Fit]\n", page);
  99.     } else if (type == fitwidth) {
  100.     pdf_printf(p, "/Dest[%ld 0 R/FitH 2000]\n", page);
  101.     } else if (type == fitheight) {
  102.     pdf_printf(p, "/Dest[%ld 0 R/FitV 0]\n", page);
  103.     } else if (type == fitbbox) {
  104.     pdf_printf(p, "/Dest[%ld 0 R/FitB]\n", page);
  105.     } else
  106.     pdf_error(p, PDF_SystemError, "Unknown outline destination type");
  107.  
  108.     pdf_puts(p, "/Title");    /* outline text */
  109.     pdf_quote_string(p, p->outlines[entry].text);
  110.     pdf_putc(p, PDF_NEWLINE);
  111.  
  112.     if (PREV(entry))
  113.     pdf_printf(p, "/Prev %ld 0 R\n", PREV(entry));
  114.     if (NEXT(entry))
  115.     pdf_printf(p, "/Next %ld 0 R\n", NEXT(entry));
  116.  
  117.     if (FIRST(entry)) {
  118.     pdf_printf(p, "/First %ld 0 R\n", SELF(FIRST(entry)));
  119.     pdf_printf(p, "/Last %ld 0 R\n", SELF(LAST(entry)));
  120.     }
  121.     if (COUNT(entry)) {
  122.     if (OPEN(entry))
  123.         pdf_printf(p, "/Count %d\n", COUNT(entry));    /* open */
  124.     else
  125.         pdf_printf(p, "/Count %d\n", -COUNT(entry));/* closed */
  126.     }
  127.  
  128.     pdf_end_dict(p);
  129.     pdf_end_obj(p);            /* outline object */
  130. }
  131.  
  132. void
  133. pdf_write_outlines(PDF *p)
  134. {
  135.     int i;
  136.  
  137.     if (p->outline_count == 0)        /* no outlines: return */
  138.     return;
  139.  
  140.     pdf_begin_obj(p, p->outlines[0].self);    /* root outline object */
  141.     pdf_begin_dict(p);
  142.  
  143.     if (p->outlines[0].count != 0)
  144.     pdf_printf(p, "/Count %d\n", COUNT(0));
  145.     pdf_printf(p, "/First %ld 0 R\n", SELF(FIRST(0)));
  146.     pdf_printf(p, "/Last %ld 0 R\n", SELF(LAST(0)));
  147.  
  148.     pdf_end_dict(p);
  149.     pdf_end_obj(p);                /* root outline object */
  150.  
  151.     for (i = 1; i <= p->outline_count; i++)
  152.     pdf_write_outline_dict(p, i);
  153. }
  154.  
  155. PDFLIB_API int PDFLIB_CALL
  156. PDF_add_bookmark(PDF *p, const char *text, int parent, int open)
  157. {
  158.     pdf_outline *self;            /* newly created outline */
  159.  
  160.     if (PDF_SANITY_CHECK_FAILED(p))
  161.     return 0;
  162.  
  163.     if (text == NULL || *text == '\0')
  164.     pdf_error(p, PDF_ValueError, "Null bookmark text");
  165.  
  166.     if (p->state != pdf_state_page_description)
  167.     pdf_error(p, PDF_RuntimeError,
  168.         "Wrong order of function calls (PDF_add_bookmark)");
  169.  
  170.     if (parent < 0 || parent > p->outline_count)
  171.     pdf_error(p, PDF_ValueError,
  172.         "Bad parent id %d for subordinate bookmark", parent);
  173.  
  174.     /* create the root outline object */
  175.     if (p->outline_count == 0) {
  176.     p->outlines = (pdf_outline *) p->calloc(p, 
  177.         sizeof(pdf_outline) * OUTLINE_CHUNKSIZE, "PDF_add_bookmark");
  178.     p->outline_capacity = OUTLINE_CHUNKSIZE;
  179.  
  180.     /* populate the root outline object */
  181.     p->outlines[0].self    = pdf_alloc_id(p);
  182.     p->outlines[0].count    = 0;
  183.     p->outlines[0].parent    = 0;
  184.     p->outlines[0].open    = 1;
  185.  
  186.     /* set the open mode show bookmarks if we have at least one,
  187.      * and the client didn't already set his own open mode.
  188.      */
  189.     if (p->open_mode == open_auto)
  190.         p->open_mode = open_bookmarks;
  191.     }
  192.  
  193.     /*
  194.      * It's crucial to increase p->outline_count only after 
  195.      * successfully having realloc()ed. Otherwise the error handler
  196.      * may try to free too much if the realloc goes wrong.
  197.      */
  198.     if (p->outline_count+1 >= p->outline_capacity) { /* used up all space */
  199.     p->outlines = (pdf_outline *) p->realloc(p, p->outlines,
  200.             sizeof(pdf_outline) * 2 * p->outline_capacity,
  201.             "PDF_add_bookmark");
  202.     p->outline_capacity *= 2;
  203.     }
  204.  
  205.     p->outline_count++;
  206.  
  207.     self = &p->outlines[p->outline_count];
  208.  
  209.     /*
  210.      * If the error handler pops in in pdf_strdup below, we don't
  211.      * want to have the cleanup function try to free self->text.
  212.      */
  213.     self->text        = NULL;
  214.  
  215.     self->text        = pdf_strdup(p, text);
  216. #ifdef PDFLIB_EBCDIC
  217.     if (!pdf_is_unicode(self->text))
  218.         pdf_make_ascii(self->text);
  219. #endif
  220.     self->dest.page    = p->current_page;
  221.     self->dest.type    = p->bookmark_dest;
  222.     self->self        = pdf_alloc_id(p);
  223.     self->first        = 0;
  224.     self->last        = 0;
  225.     self->prev        = 0;
  226.     self->next        = 0;
  227.     self->count        = 0;
  228.     self->open        = open;
  229.     self->parent    = parent;
  230.  
  231.     /* insert new outline at the end of the chain or start a new chain */
  232.     if (FIRST(parent) == 0) {
  233.     FIRST(parent) = p->outline_count;
  234.     } else {
  235.     self->prev = SELF(LAST(parent));
  236.     NEXT(LAST(parent))= self->self;
  237.     }
  238.  
  239.     /* insert new outline as last child of parent in all cases */
  240.     LAST(parent) = p->outline_count;
  241.  
  242.     /* increase the number of open sub-entries for all relevant ancestors */
  243.     do {
  244.     COUNT(parent)++;
  245.     } while (OPEN(parent) && (parent = PARENT(parent)) != 0);
  246.  
  247.     return (p->outline_count);        /* caller may use this as handle */
  248. }
  249.  
  250. void
  251. pdf_init_info(PDF *p)
  252. {
  253.     p->Keywords        = NULL;
  254.     p->Subject        = NULL;
  255.     p->Title        = NULL;
  256.     p->Creator        = NULL;
  257.     p->Author        = NULL;
  258.     p->userkey        = NULL;
  259.     p->userval        = NULL;
  260.  
  261.     p->info_id        = pdf_alloc_id(p);    /* Info object */
  262. }
  263.  
  264. /* Set Info dictionary entries */
  265. PDFLIB_API void PDFLIB_CALL
  266. PDF_set_info(PDF *p, const char *key, const char *val)
  267. {
  268.     char *key_buf, *val_buf;
  269.  
  270.     if (PDF_SANITY_CHECK_FAILED(p))
  271.     return;
  272.  
  273.     if (key == NULL || !*key || val == NULL || !*val) {
  274.     pdf_error(p, PDF_NonfatalError, "Empty key or value in PDF_set_info");
  275.     return;
  276.     }
  277.  
  278.     /* this is needed in all cases */
  279.     val_buf = pdf_strdup(p, val);
  280.     key_buf = pdf_strdup(p, key);
  281.  
  282. #ifdef PDFLIB_EBCDIC
  283.     if (!pdf_is_unicode(val_buf))
  284.     pdf_make_ascii(val_buf);
  285.  
  286.     /* key_buf must only be converted below after the comparisons are done */
  287. #endif
  288.  
  289.     if (!strcmp(key_buf, "Keywords")) {
  290.     p->Keywords = val_buf;
  291.     } else if (!strcmp(key_buf, "Subject")) {
  292.     p->Subject = val_buf;
  293.     } else if (!strcmp(key_buf, "Title")) {
  294.     p->Title = val_buf;
  295.     } else if (!strcmp(key_buf, "Creator")) {
  296.     p->Creator = val_buf;
  297.     } else if (!strcmp(key_buf, "Author")) {
  298.     p->Author = val_buf;
  299.     } else {
  300.     /* user-defined keyword */
  301.     p->userval = val_buf;
  302.     p->userkey = key_buf;
  303.     return;
  304.     }
  305.  
  306.     p->free(p, key_buf);
  307. }
  308.  
  309. void
  310. pdf_write_info(PDF *p)
  311. {
  312.     time_t    timer;
  313.     struct tm    ltime;
  314.  
  315.     pdf_begin_obj(p, p->info_id);    /* Info object */
  316.  
  317.     pdf_begin_dict(p);
  318.  
  319.     /*
  320.      * Although it would be syntactically correct, we must not remove
  321.      * the space characters after the dictionary keys since this
  322.      * would break the PDF properties feature in Windows Explorer.
  323.      */
  324.  
  325.     if (p->Keywords) {
  326.     pdf_puts(p, "/Keywords ");
  327.     pdf_quote_string(p, p->Keywords);
  328.     pdf_putc(p, PDF_NEWLINE);
  329.     }
  330.     if (p->Subject) {
  331.     pdf_puts(p, "/Subject ");
  332.     pdf_quote_string(p, p->Subject);
  333.     pdf_putc(p, PDF_NEWLINE);
  334.     }
  335.     if (p->Title) {
  336.     pdf_puts(p, "/Title ");
  337.     pdf_quote_string(p, p->Title);
  338.     pdf_putc(p, PDF_NEWLINE);
  339.     }
  340.     if (p->Creator) {
  341.     pdf_puts(p, "/Creator ");
  342.     pdf_quote_string(p, p->Creator);
  343.     pdf_putc(p, PDF_NEWLINE);
  344.     }
  345.     if (p->Author) {
  346.     pdf_puts(p, "/Author ");
  347.     pdf_quote_string(p, p->Author);
  348.     pdf_putc(p, PDF_NEWLINE);
  349.     }
  350.     if (p->userval) {
  351.     pdf_printf(p, "/%s ", p->userkey);
  352.     pdf_quote_string(p, p->userval);
  353.     pdf_putc(p, PDF_NEWLINE);
  354.     }
  355.  
  356.     time(&timer);
  357.     ltime = *localtime(&timer);
  358.     pdf_printf(p, "/CreationDate (D:%04d%02d%02d%02d%02d%02d)\n",
  359.         ltime.tm_year + 1900, ltime.tm_mon + 1, ltime.tm_mday,
  360.         ltime.tm_hour, ltime.tm_min, ltime.tm_sec);
  361.  
  362.     /*
  363.      * If you change the /Producer entry your license to use
  364.      * PDFlib will be void!
  365.      */
  366.  
  367.     if (p->binding)
  368.     pdf_printf(p, "/Producer (PDFlib %s \\(%s/%s\\))\n",
  369.         PDFLIB_VERSIONSTRING, p->binding, PDF_PLATFORM);
  370.     else
  371.     pdf_printf(p, "/Producer (PDFlib %s \\(%s\\))\n",
  372.         PDFLIB_VERSIONSTRING, PDF_PLATFORM);
  373.  
  374.     pdf_end_dict(p);
  375.     pdf_end_obj(p);            /* Info object */
  376. }
  377.  
  378. void
  379. pdf_cleanup_info(PDF *p)
  380. {
  381.     /* Free Info dictionary entries */
  382.     if (p->Keywords) {
  383.     p->free(p, p->Keywords);
  384.     p->Keywords = NULL;
  385.     }
  386.     if (p->Subject) {
  387.     p->free(p, p->Subject);
  388.     p->Subject = NULL;
  389.     }
  390.     if (p->Title) {
  391.     p->free(p, p->Title);
  392.     p->Title = NULL;
  393.     }
  394.     if (p->Creator) {
  395.     p->free(p, p->Creator);
  396.     p->Creator = NULL;
  397.     }
  398.     if (p->Author) {
  399.     p->free(p, p->Author);
  400.     p->Author = NULL;
  401.     }
  402.     if (p->userkey) {
  403.     p->free(p, p->userkey);
  404.     p->userkey = NULL;
  405.     }
  406.     if (p->userval) {
  407.     p->free(p, p->userval);
  408.     p->userval = NULL;
  409.     }
  410. }
  411.  
  412. /* Page transition effects */
  413.  
  414. void
  415. pdf_init_transition(PDF *p)
  416. {
  417.     p->transition = trans_none;
  418.     p->duration = 0;
  419. }
  420.  
  421. /* set page display duration for current and future pages */
  422. void
  423. pdf_set_duration(PDF *p, float t)
  424. {
  425.     if (PDF_SANITY_CHECK_FAILED(p))
  426.     return;
  427.  
  428.     p->duration = t;
  429. }
  430.  
  431. /* set transition mode for current and future pages */
  432. void
  433. pdf_set_transition(PDF *p, const char *type)
  434. {
  435.     if (PDF_SANITY_CHECK_FAILED(p))
  436.     return;
  437.  
  438.     if (type == NULL || *type == '\0')
  439.     p->transition = trans_none;
  440.     else if (!strcmp(type, "none"))
  441.     p->transition = trans_none;
  442.     else if (!strcmp(type, "split"))
  443.     p->transition = trans_split;
  444.     else if (!strcmp(type, "blinds"))
  445.     p->transition = trans_blinds;
  446.     else if (!strcmp(type, "box"))
  447.     p->transition = trans_box;
  448.     else if (!strcmp(type, "wipe"))
  449.     p->transition = trans_wipe;
  450.     else if (!strcmp(type, "dissolve"))
  451.     p->transition = trans_dissolve;
  452.     else if (!strcmp(type, "glitter"))
  453.     p->transition = trans_glitter;
  454.     else if (!strcmp(type, "replace"))
  455.     p->transition = trans_replace;
  456.     else
  457.     pdf_error(p, PDF_ValueError, "Unknown page transition type '%s'", type);
  458. }
  459.