home *** CD-ROM | disk | FTP | other *** search
/ ftp.cs.arizona.edu / ftp.cs.arizona.edu.tar / ftp.cs.arizona.edu / icon / historic / v941.tgz / icon.v941src.tar / icon.v941src / src / xpm / parse.c < prev    next >
C/C++ Source or Header  |  2000-07-29  |  14KB  |  538 lines

  1. /* Copyright 1990-92 GROUPE BULL -- See license conditions in file COPYRIGHT */
  2. /*****************************************************************************\
  3. * parse.c:                                                                    *
  4. *                                                                             *
  5. *  XPM library                                                                *
  6. *  Parse an XPM file or array and store the found informations                *
  7. *  in an an xpmInternAttrib structure which is returned.                      *
  8. *                                                                             *
  9. *  Developed by Arnaud Le Hors                                                *
  10. \*****************************************************************************/
  11.  
  12.  
  13. #include "xpmP.h"
  14. #ifdef VMS
  15. #include "sys$library:ctype.h"
  16. #else
  17. #include <ctype.h>
  18. #endif
  19.  
  20. LFUNC(ParseValues, int, (xpmData *data, unsigned int *width,
  21.              unsigned int *height, unsigned int *ncolors,
  22.              unsigned int *cpp,  unsigned int *x_hotspot,
  23.              unsigned int *y_hotspot, unsigned int *hotspot,
  24.              unsigned int *extensions));
  25.  
  26. LFUNC(ParseColors, int, (xpmData *data, unsigned int ncolors, unsigned int cpp,
  27.              char ****colorTablePtr, xpmHashTable *hashtable));
  28.  
  29. LFUNC(ParsePixels, int, (xpmData *data, unsigned int width, 
  30.              unsigned int height, unsigned int ncolors,
  31.              unsigned int cpp, char ***colorTable,
  32.              xpmHashTable *hashtable, unsigned int **pixels));
  33.  
  34. LFUNC(ParseExtensions, int, (xpmData *data, XpmExtension **extensions,
  35.                  unsigned int *nextensions));
  36.  
  37. char *xpmColorKeys[] =
  38. {
  39.  "s",                    /* key #1: symbol */
  40.  "m",                    /* key #2: mono visual */
  41.  "g4",                    /* key #3: 4 grays visual */
  42.  "g",                    /* key #4: gray visual */
  43.  "c",                    /* key #5: color visual */
  44. };
  45.  
  46.  
  47. /* function call in case of error, frees only locally allocated variables */
  48. #undef RETURN
  49. #define RETURN(status) \
  50.   { if (colorTable) xpmFreeColorTable(colorTable, ncolors); \
  51.     if (pixelindex) free(pixelindex); \
  52.     if (hints_cmt)  free(hints_cmt); \
  53.     if (colors_cmt) free(colors_cmt); \
  54.     if (pixels_cmt) free(pixels_cmt); \
  55.     return(status); }
  56.  
  57. /*
  58.  * This function parses an Xpm file or data and store the found informations
  59.  * in an an xpmInternAttrib structure which is returned.
  60.  */
  61. int
  62. xpmParseData(data, attrib_return, attributes)
  63.     xpmData *data;
  64.     xpmInternAttrib *attrib_return;
  65.     XpmAttributes *attributes;
  66. {
  67.     /* variables to return */
  68.     unsigned int width, height, ncolors, cpp;
  69.     unsigned int x_hotspot, y_hotspot, hotspot = 0, extensions = 0;
  70.     char ***colorTable = NULL;
  71.     unsigned int *pixelindex = NULL;
  72.     char *hints_cmt = NULL;
  73.     char *colors_cmt = NULL;
  74.     char *pixels_cmt = NULL;
  75.  
  76.     int ErrorStatus;
  77.     xpmHashTable hashtable;
  78.  
  79.     /*
  80.      * read values
  81.      */
  82.     ErrorStatus = ParseValues(data, &width, &height, &ncolors, &cpp,
  83.                   &x_hotspot, &y_hotspot, &hotspot, &extensions);
  84.     if (ErrorStatus != XpmSuccess)
  85.     return(ErrorStatus);
  86.  
  87.     /*
  88.      * store the hints comment line 
  89.      */
  90.     if (attributes && (attributes->valuemask & XpmReturnInfos))
  91.     xpmGetCmt(data, &hints_cmt);
  92.  
  93.     /*
  94.      * init the hastable
  95.      */
  96.     if (USE_HASHTABLE) {
  97.     ErrorStatus = xpmHashTableInit(&hashtable);
  98.     if (ErrorStatus != XpmSuccess)
  99.         return(ErrorStatus);
  100.     }
  101.     
  102.     /*
  103.      * read colors 
  104.      */
  105.     ErrorStatus = ParseColors(data, ncolors, cpp, &colorTable, &hashtable);
  106.     if (ErrorStatus != XpmSuccess)
  107.     RETURN(ErrorStatus);
  108.  
  109.     /*
  110.      * store the colors comment line 
  111.      */
  112.     if (attributes && (attributes->valuemask & XpmReturnInfos))
  113.     xpmGetCmt(data, &colors_cmt);
  114.  
  115.     /*
  116.      * read pixels and index them on color number 
  117.      */
  118.     ErrorStatus = ParsePixels(data, width, height, ncolors, cpp, colorTable,
  119.                   &hashtable, &pixelindex);
  120.  
  121.     /*
  122.      * free the hastable
  123.      */
  124.     if (USE_HASHTABLE)
  125.     xpmHashTableFree(&hashtable);
  126.     
  127.     if (ErrorStatus != XpmSuccess)
  128.     RETURN(ErrorStatus);
  129.  
  130.     /*
  131.      * store the pixels comment line 
  132.      */
  133.     if (attributes && (attributes->valuemask & XpmReturnInfos))
  134.     xpmGetCmt(data, &pixels_cmt);
  135.  
  136.     /*
  137.      * parse extensions
  138.      */
  139.     if (attributes && (attributes->valuemask & XpmReturnExtensions)) 
  140.     if (extensions) {
  141.         ErrorStatus = ParseExtensions(data, &attributes->extensions,
  142.                       &attributes->nextensions);
  143.         if (ErrorStatus != XpmSuccess)
  144.         RETURN(ErrorStatus);
  145.     } else {
  146.         attributes->extensions = NULL;
  147.         attributes->nextensions = 0;
  148.     }
  149.  
  150.     /*
  151.      * store found informations in the xpmInternAttrib structure 
  152.      */
  153.     attrib_return->width = width;
  154.     attrib_return->height = height;
  155.     attrib_return->cpp = cpp;
  156.     attrib_return->ncolors = ncolors;
  157.     attrib_return->colorTable = colorTable;
  158.     attrib_return->pixelindex = pixelindex;
  159.  
  160.     if (attributes) {
  161.     if (attributes->valuemask & XpmReturnInfos) {
  162.         attributes->hints_cmt = hints_cmt;
  163.         attributes->colors_cmt = colors_cmt;
  164.         attributes->pixels_cmt = pixels_cmt;
  165.     }
  166.     if (hotspot) {
  167.         attributes->x_hotspot = x_hotspot;
  168.         attributes->y_hotspot = y_hotspot;
  169.         attributes->valuemask |= XpmHotspot;
  170.     }
  171.     }
  172.     return (XpmSuccess);
  173. }
  174.  
  175. static int
  176. ParseValues(data, width, height, ncolors, cpp,
  177.         x_hotspot, y_hotspot, hotspot, extensions)
  178.     xpmData *data;
  179.     unsigned int *width, *height, *ncolors, *cpp;
  180.     unsigned int *x_hotspot, *y_hotspot,  *hotspot;
  181.     unsigned int *extensions;
  182. {
  183.     unsigned int l;
  184.     char buf[BUFSIZ];
  185.  
  186.     /*
  187.      * read values: width, height, ncolors, chars_per_pixel 
  188.      */
  189.     if (!(xpmNextUI(data, width) && xpmNextUI(data, height)
  190.       && xpmNextUI(data, ncolors) && xpmNextUI(data, cpp)))
  191.     return(XpmFileInvalid);
  192.  
  193.     /*
  194.      * read optional information (hotspot and/or XPMEXT) if any 
  195.      */
  196.     l = xpmNextWord(data, buf);
  197.     if (l) {
  198.     *extensions = l == 6 && !strncmp("XPMEXT", buf, 6);
  199.     if (*extensions)
  200.         *hotspot = xpmNextUI(data, x_hotspot)
  201.         && xpmNextUI(data, y_hotspot);
  202.     else {
  203.         *hotspot = atoui(buf, l, x_hotspot) && xpmNextUI(data, y_hotspot);
  204.         l = xpmNextWord(data, buf);
  205.         *extensions = l == 6 && !strncmp("XPMEXT", buf, 6);
  206.     }
  207.     }
  208.     return (XpmSuccess);
  209. }
  210.  
  211. static int
  212. ParseColors(data, ncolors, cpp, colorTablePtr, hashtable)
  213.     xpmData *data;
  214.     unsigned int ncolors;
  215.     unsigned int cpp;
  216.     char ****colorTablePtr;        /* Jee, that's something! */
  217.     xpmHashTable *hashtable;
  218. {
  219.     unsigned int key, l, a, b;
  220.     unsigned int curkey;        /* current color key */
  221.     unsigned int lastwaskey;        /* key read */
  222.     char buf[BUFSIZ];
  223.     char curbuf[BUFSIZ];        /* current buffer */
  224.     char ***ct, **cts, **sptr, *s;
  225.     char ***colorTable;
  226.     int ErrorStatus;
  227.  
  228.     colorTable = (char ***) calloc(ncolors, sizeof(char **));
  229.     if (!colorTable)
  230.     return(XpmNoMemory);
  231.  
  232.     for (a = 0, ct = colorTable; a < ncolors; a++, ct++) {
  233.     xpmNextString(data);        /* skip the line */
  234.     cts = *ct = (char **) calloc((NKEYS + 1), sizeof(char *));
  235.     if (!cts) {
  236.         xpmFreeColorTable(colorTable, ncolors);
  237.         return(XpmNoMemory);
  238.     }
  239.  
  240.     /*
  241.      * read pixel value 
  242.      */
  243.     *cts = (char *) malloc(cpp + 1); /* + 1 for null terminated */
  244.     if (!*cts) {
  245.         xpmFreeColorTable(colorTable, ncolors);
  246.         return(XpmNoMemory);
  247.     }
  248.     for (b = 0, s = *cts; b < cpp; b++, s++)
  249.         *s = xpmGetC(data);
  250.     *s = '\0';
  251.  
  252.     /*
  253.      * store the string in the hashtable with its color index number
  254.      */
  255.     if (USE_HASHTABLE) {
  256.         ErrorStatus = xpmHashIntern(hashtable, *cts, HashAtomData((long)a));
  257.         if (ErrorStatus != XpmSuccess) {
  258.         xpmFreeColorTable(colorTable, ncolors);
  259.         return(ErrorStatus);
  260.         }
  261.     }
  262.  
  263.     /*
  264.      * read color keys and values 
  265.      */
  266.     curkey = 0;
  267.     lastwaskey = 0;
  268.     while (l = xpmNextWord(data, buf)) {
  269.         if (!lastwaskey) {
  270.         for (key = 0, sptr = xpmColorKeys; key < NKEYS; key++, sptr++)
  271.             if ((strlen(*sptr) == l) && (!strncmp(*sptr, buf, l)))
  272.             break;
  273.         }
  274.         if (!lastwaskey && key < NKEYS) { /* open new key */
  275.         if (curkey) {        /* flush string */
  276.             s = cts[curkey] = (char *) malloc(strlen(curbuf) + 1);
  277.             if (!s) {
  278.             xpmFreeColorTable(colorTable, ncolors);
  279.             return(XpmNoMemory);
  280.             }
  281.             strcpy(s, curbuf);
  282.         }
  283.         curkey = key + 1;    /* set new key  */
  284.         *curbuf = '\0';        /* reset curbuf */
  285.         lastwaskey = 1;
  286.         } else {
  287.         if (!curkey) {        /* key without value */
  288.             xpmFreeColorTable(colorTable, ncolors);
  289.             return(XpmFileInvalid);
  290.         }
  291.         if (!lastwaskey)
  292.             strcat(curbuf, " "); /* append space */
  293.         buf[l] = '\0';
  294.         strcat(curbuf, buf);    /* append buf */
  295.         lastwaskey = 0;
  296.         }
  297.     }
  298.     if (!curkey) {            /* key without value */
  299.         xpmFreeColorTable(colorTable, ncolors);
  300.         return(XpmFileInvalid);
  301.     }
  302.     s = cts[curkey] = (char *) malloc(strlen(curbuf) + 1);
  303.     if (!s) {
  304.         xpmFreeColorTable(colorTable, ncolors);
  305.         return(XpmNoMemory);
  306.     }
  307.     strcpy(s, curbuf);
  308.     }
  309.     *colorTablePtr = colorTable;
  310.     return(XpmSuccess);
  311. }
  312.  
  313. static int
  314. ParsePixels(data, width, height, ncolors, cpp, colorTable, hashtable, pixels)
  315.     xpmData *data;
  316.     unsigned int width;
  317.     unsigned int height;
  318.     unsigned int ncolors;
  319.     unsigned int cpp;
  320.     char ***colorTable;
  321.     xpmHashTable *hashtable;
  322.     unsigned int **pixels;
  323. {
  324.     unsigned int *iptr, *iptr2;
  325.     unsigned int a, x, y;
  326.  
  327.     iptr2 = (unsigned int *) malloc(sizeof(unsigned int) * width * height);
  328.     if (!iptr2)
  329.     return(XpmNoMemory);
  330.  
  331.     iptr = iptr2;
  332.  
  333.     switch (cpp) {
  334.  
  335.        case (1): /* Optimize for single character colors */
  336.        {
  337.        unsigned short colidx[256];
  338.  
  339.        bzero(colidx, 256 * sizeof(short));
  340.        for (a = 0; a < ncolors; a++)
  341.            colidx[ colorTable[a][0][0] ] = a + 1;
  342.                 
  343.        for (y = 0; y < height; y++) 
  344.        {
  345.            xpmNextString(data);
  346.            for (x = 0; x < width; x++, iptr++)
  347.            {
  348.            int idx = colidx[xpmGetC(data)];
  349.            if ( idx != 0 )
  350.                *iptr = idx - 1;
  351.            else {
  352.                free(iptr2);
  353.                return(XpmFileInvalid);
  354.            }
  355.            }
  356.        }
  357.        }
  358.        break;
  359.  
  360.        case (2): /* Optimize for double character colors */
  361.        {
  362.        unsigned short cidx[256][256];
  363.  
  364.        bzero(cidx, 256*256 * sizeof(short));
  365.        for (a = 0; a < ncolors; a++)
  366.            cidx [ colorTable[a][0][0] ][ colorTable[a][0][1] ] = a + 1;
  367.  
  368.        for (y = 0; y < height; y++) 
  369.        {
  370.            xpmNextString(data);
  371.            for (x = 0; x < width; x++, iptr++)
  372.            {
  373.            int cc1 = xpmGetC(data);
  374.            int idx = cidx[cc1][ xpmGetC(data) ];
  375.            if ( idx != 0 )
  376.                *iptr = idx - 1;
  377.            else {
  378.                free(iptr2);
  379.                return(XpmFileInvalid);
  380.            }
  381.            }
  382.        }
  383.        }
  384.        break;
  385.  
  386.        default : /* Non-optimized case of long color names */
  387.        {
  388.        char *s;
  389.        char buf[BUFSIZ];
  390.  
  391.        buf[cpp] = '\0';
  392.        if (USE_HASHTABLE) {
  393.            xpmHashAtom *slot;
  394.  
  395.            for (y = 0; y < height; y++) {
  396.            xpmNextString(data);
  397.            for (x = 0; x < width; x++, iptr++) {
  398.                for (a = 0, s = buf; a < cpp; a++, s++)
  399.                *s = xpmGetC(data);
  400.                slot = xpmHashSlot(hashtable, buf);
  401.                if (!*slot) {        /* no color matches */
  402.                free(iptr2);
  403.                return(XpmFileInvalid);
  404.                }
  405.                *iptr = HashColorIndex(slot);
  406.            }
  407.            }
  408.        } else {
  409.            for (y = 0; y < height; y++) {
  410.            xpmNextString(data);
  411.            for (x = 0; x < width; x++, iptr++) {
  412.                for (a = 0, s = buf; a < cpp; a++, s++)
  413.                *s = xpmGetC(data);
  414.                for (a = 0; a < ncolors; a++)
  415.                if (!strcmp(colorTable[a][0], buf))
  416.                    break;
  417.                if (a == ncolors) {    /* no color matches */
  418.                free(iptr2);
  419.                return(XpmFileInvalid);
  420.                }
  421.                *iptr = a;
  422.            }
  423.            }
  424.        }
  425.        }
  426.        break;
  427.    }
  428.     *pixels = iptr2;
  429.     return (XpmSuccess);
  430. }
  431.  
  432. static int
  433. ParseExtensions(data, extensions, nextensions)
  434.     xpmData *data;
  435.     XpmExtension **extensions;
  436.     unsigned int *nextensions;
  437. {
  438.     XpmExtension *exts = NULL, *ext;
  439.     unsigned int num = 0;
  440.     unsigned int nlines, a, l, notstart, notend = 0;
  441.     int status;
  442.     char *string, *s, *s2, **sp;
  443.  
  444.     xpmNextString(data);
  445.     exts = (XpmExtension *) malloc(sizeof(XpmExtension));
  446.     /* get the whole string */
  447.     status = xpmGetString(data, &string, &l);
  448.     if (status != XpmSuccess) {
  449.     free(exts);
  450.     return(status);
  451.     }
  452.     /* look for the key word XPMEXT, skip lines before this */
  453.     while ((notstart = strncmp("XPMEXT", string, 6))
  454.        && (notend = strncmp("XPMENDEXT", string, 9))) {
  455.     free(string);
  456.     xpmNextString(data);
  457.     status = xpmGetString(data, &string, &l);
  458.     if (status != XpmSuccess) {
  459.         free(exts);
  460.         return(status);
  461.     }
  462.     }
  463.     if (!notstart)
  464.     notend = strncmp("XPMENDEXT", string, 9);
  465.     while (!notstart && notend) {
  466.     /* there starts an extension */
  467.     ext = (XpmExtension *) realloc(exts, (num + 1) * sizeof(XpmExtension));
  468.     if (!ext) {
  469.         free(string);
  470.         XpmFreeExtensions(exts, num);
  471.         return(XpmNoMemory);
  472.     }
  473.     exts = ext;
  474.     ext += num;
  475.     /* skip whitespace and store its name */
  476.     s2 = s = string + 6;
  477.     while (isspace(*s2))
  478.         s2++;
  479.     a = s2 - s;
  480.     ext->name = (char *) malloc(l - a - 6);
  481.     if (!ext->name) {
  482.         free(string);
  483.         ext->lines = NULL;
  484.         ext->nlines = 0;
  485.         XpmFreeExtensions(exts, num + 1);
  486.         return(XpmNoMemory);
  487.     }
  488.     strncpy(ext->name, s + a, l - a - 6);
  489.     free(string);
  490.     /* now store the related lines */
  491.     xpmNextString(data);
  492.     status = xpmGetString(data, &string, &l);
  493.     if (status != XpmSuccess) {
  494.         ext->lines = NULL;
  495.         ext->nlines = 0;
  496.         XpmFreeExtensions(exts, num + 1);
  497.         return(status);
  498.     }
  499.     ext->lines = (char **) malloc(sizeof(char *));
  500.     nlines = 0;
  501.     while ((notstart = strncmp("XPMEXT", string, 6))
  502.            && (notend = strncmp("XPMENDEXT", string, 9))) {
  503.         sp = (char **) realloc(ext->lines, (nlines + 1) * sizeof(char *));
  504.         if (!sp) {
  505.         free(string);
  506.         ext->nlines = nlines;
  507.         XpmFreeExtensions(exts, num + 1);
  508.         return(XpmNoMemory);
  509.         }
  510.         ext->lines = sp;
  511.         ext->lines[nlines] = string;
  512.         nlines++;
  513.         xpmNextString(data);
  514.         status = xpmGetString(data, &string, &l);
  515.         if (status != XpmSuccess) {
  516.         ext->nlines = nlines;
  517.         XpmFreeExtensions(exts, num + 1);
  518.         return(status);
  519.         }
  520.     }
  521.     if (!nlines) {
  522.         free(ext->lines);
  523.         ext->lines = NULL;
  524.     }
  525.     ext->nlines = nlines;
  526.     num++;
  527.     }
  528.     if (!num) {
  529.     free(string);
  530.     free(exts);
  531.     exts = NULL;
  532.     } else if (!notend)
  533.     free(string);
  534.     *nextensions = num;
  535.     *extensions = exts;
  536.     return(XpmSuccess);
  537. }
  538.