home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2240.zip / wxWindows-2.4.0 / src / common / xpmdecod.cpp < prev    next >
C/C++ Source or Header  |  2002-12-11  |  27KB  |  774 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name:        xpmdecod.cpp
  3. // Purpose:     wxXPMDecoder
  4. // Author:      John Cristy, Vaclav Slavik
  5. // RCS-ID:      $Id: xpmdecod.cpp,v 1.21.2.2 2002/12/07 02:30:35 VZ Exp $
  6. // Copyright:   (c) John Cristy, Vaclav Slavik
  7. // Licence:     wxWindows licence
  8. /////////////////////////////////////////////////////////////////////////////
  9.  
  10. /*
  11.  
  12. This file is partially based on source code of ImageMagick by John Cristy. Its
  13. license is as follows:
  14.  
  15. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  16. %                                                                             %
  17. %                                                                             %
  18. %                                                                             %
  19. %                            X   X  PPPP   M   M                              %
  20. %                             X X   P   P  MM MM                              %
  21. %                              X    PPPP   M M M                              %
  22. %                             X X   P      M   M                              %
  23. %                            X   X  P      M   M                              %
  24. %                                                                             %
  25. %                                                                             %
  26. %                    Read/Write ImageMagick Image Format.                     %
  27. %                                                                             %
  28. %                                                                             %
  29. %                              Software Design                                %
  30. %                                John Cristy                                  %
  31. %                                 July 1992                                   %
  32. %                                                                             %
  33. %                                                                             %
  34. %  Copyright (C) 2001 ImageMagick Studio, a non-profit organization dedicated %
  35. %  to making software imaging solutions freely available.                     %
  36. %                                                                             %
  37. %  Permission is hereby granted, free of charge, to any person obtaining a    %
  38. %  copy of this software and associated documentation files ("ImageMagick"),  %
  39. %  to deal in ImageMagick without restriction, including without limitation   %
  40. %  the rights to use, copy, modify, merge, publish, distribute, sublicense,   %
  41. %  and/or sell copies of ImageMagick, and to permit persons to whom the       %
  42. %  ImageMagick is furnished to do so, subject to the following conditions:    %
  43. %                                                                             %
  44. %  The above copyright notice and this permission notice shall be included in %
  45. %  all copies or substantial portions of ImageMagick.                         %
  46. %                                                                             %
  47. %  The software is provided "as is", without warranty of any kind, express or %
  48. %  implied, including but not limited to the warranties of merchantability,   %
  49. %  fitness for a particular purpose and noninfringement.  In no event shall   %
  50. %  ImageMagick Studio be liable for any claim, damages or other liability,    %
  51. %  whether in an action of contract, tort or otherwise, arising from, out of  %
  52. %  or in connection with ImageMagick or the use or other dealings in          %
  53. %  ImageMagick.                                                               %
  54. %                                                                             %
  55. %  Except as contained in this notice, the name of the ImageMagick Studio     %
  56. %  shall not be used in advertising or otherwise to promote the sale, use or  %
  57. %  other dealings in ImageMagick without prior written authorization from the %
  58. %  ImageMagick Studio.                                                        %
  59. %                                                                             %
  60. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  61. %
  62. %
  63. */
  64.  
  65. /*
  66.  * Also contains some pieces from libxpm and its modification for win32 by
  67.  * HeDu <hedu@cul-ipn.uni-kiel.de>:
  68.  *
  69.  * Copyright (C) 1989-95 GROUPE BULL
  70.  *
  71.  * Permission is hereby granted, free of charge, to any person obtaining a copy
  72.  * of this software and associated documentation files (the "Software"), to
  73.  * deal in the Software without restriction, including without limitation the
  74.  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  75.  * sell copies of the Software, and to permit persons to whom the Software is
  76.  * furnished to do so, subject to the following conditions:
  77.  *
  78.  * The above copyright notice and this permission notice shall be included in
  79.  * all copies or substantial portions of the Software.
  80.  *
  81.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  82.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  83.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  84.  * GROUPE BULL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
  85.  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  86.  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  87.  *
  88.  * Except as contained in this notice, the name of GROUPE BULL shall not be
  89.  * used in advertising or otherwise to promote the sale, use or other dealings
  90.  * in this Software without prior written authorization from GROUPE BULL.
  91.  */
  92.  
  93. #ifdef __GNUG__
  94. #pragma implementation "xpmdecod.h"
  95. #endif
  96.  
  97. // For compilers that support precompilation, includes "wx.h".
  98. #include "wx/wxprec.h"
  99.  
  100. #ifdef __BORLANDC__
  101. #  pragma hdrstop
  102. #endif
  103.  
  104. #ifndef WX_PRECOMP
  105. #  include "wx/defs.h"
  106. #endif
  107.  
  108. #if wxUSE_IMAGE && wxUSE_XPM
  109.  
  110. #include "wx/stream.h"
  111. #include "wx/image.h"
  112. #include "wx/utils.h"
  113. #include "wx/log.h"
  114. #include "wx/hashmap.h"
  115. #include "wx/intl.h"
  116. #include <string.h>
  117.  
  118. #include <ctype.h>
  119.  
  120. #include "wx/xpmdecod.h"
  121.  
  122. #if wxUSE_STREAMS
  123. bool wxXPMDecoder::CanRead(wxInputStream& stream)
  124. {
  125.     unsigned char buf[9];
  126.  
  127.     if ( !stream.Read(buf, WXSIZEOF(buf)) )
  128.         return FALSE;
  129.  
  130.     stream.SeekI(-(off_t)WXSIZEOF(buf), wxFromCurrent);
  131.  
  132.     return memcmp(buf, "/* XPM */", WXSIZEOF(buf)) == 0;
  133. }
  134.  
  135. wxImage wxXPMDecoder::ReadFile(wxInputStream& stream)
  136. {
  137.     size_t length = stream.GetSize();
  138.     wxCHECK_MSG( length != 0, wxNullImage,
  139.                  wxT("Cannot read XPM from stream of unknown size") );
  140.  
  141.     // use a smart buffer to be sure to free memory even when we return on
  142.     // error
  143.     wxCharBuffer buffer(length);
  144.  
  145.     char *xpm_buffer = (char *)buffer.data();
  146.     if ( stream.Read(xpm_buffer, length).GetLastError() == wxSTREAM_READ_ERROR )
  147.         return wxNullImage;
  148.     xpm_buffer[length] = '\0';
  149.  
  150.     /*
  151.      *  Remove comments from the file:
  152.      */
  153.     char *p, *q;
  154.     for (p = xpm_buffer; *p != '\0'; p++)
  155.     {
  156.         if ( (*p == '"') || (*p == '\'') )
  157.         {
  158.             if (*p == '"')
  159.             {
  160.               for (p++; *p != '\0'; p++)
  161.                 if ( (*p == '"') && (*(p - 1) != '\\') )
  162.                     break;
  163.             }
  164.             else // *p == '\''
  165.             {
  166.                 for (p++; *p != '\0'; p++)
  167.                     if ( (*p == '\'') && (*(p - 1) != '\\') )
  168.                         break;
  169.             }
  170.             if (*p == '\0')
  171.                 break;
  172.             continue;
  173.         }
  174.         if ( (*p != '/') || (*(p + 1) != '*') )
  175.             continue;
  176.         for (q = p + 2; *q != '\0'; q++)
  177.         {
  178.             if ( (*q == '*') && (*(q + 1) == '/') )
  179.                 break;
  180.         }
  181.         strcpy(p, q + 2);
  182.     }
  183.  
  184.     /*
  185.      *  Remove unquoted characters:
  186.      */
  187.     size_t i = 0;
  188.     for (p = xpm_buffer; *p != '\0'; p++)
  189.     {
  190.         if ( *p != '"' )
  191.             continue;
  192.         for (q = p + 1; *q != '\0'; q++)
  193.             if (*q == '"')
  194.                 break;
  195.         strncpy(xpm_buffer + i, p + 1, q - p - 1);
  196.         i += q - p - 1;
  197.         xpm_buffer[i++] = '\n';
  198.         p = q + 1;
  199.     }
  200.     xpm_buffer[i] = '\0';
  201.  
  202.     /*
  203.      *  Create array of lines and convert \n's to \0's:
  204.      */
  205.     const char **xpm_lines;
  206.     size_t lines_cnt = 0;
  207.     size_t line;
  208.  
  209.     for (p = xpm_buffer; *p != '\0'; p++)
  210.     {
  211.         if ( *p == '\n' )
  212.             lines_cnt++;
  213.     }
  214.  
  215.     if ( !lines_cnt )
  216.     {
  217.         // this doesn't really look an XPM image
  218.         return wxNullImage;
  219.     }
  220.  
  221.     xpm_lines = new const char*[lines_cnt];
  222.     xpm_lines[0] = xpm_buffer;
  223.     line = 1;
  224.     for (p = xpm_buffer; (*p != '\0') && (line < lines_cnt); p++)
  225.     {
  226.         if ( *p == '\n' )
  227.         {
  228.             xpm_lines[line] = p + 1;
  229.             *p = '\0';
  230.             line++;
  231.         }
  232.     }
  233.  
  234.     /*
  235.      *  Read the image:
  236.      */
  237.     wxImage img = ReadData(xpm_lines);
  238.  
  239. #ifdef __WIN16__
  240.     delete[] (char**) xpm_lines;
  241. #else
  242.     delete[] xpm_lines;
  243. #endif
  244.  
  245.     return img;
  246. }
  247. #endif // wxUSE_STREAMS
  248.  
  249.  
  250. /*****************************************************************************\
  251. * rgbtab.h                                                                    *
  252. *                                                                             *
  253. * A hard coded rgb.txt. To keep it short I removed all colornames with        *
  254. * trailing numbers, Blue3 etc, except the GrayXX. Sorry Grey-lovers I prefer  *
  255. * Gray ;-). But Grey is recognized on lookups, only on save Gray will be      *
  256. * used, maybe you want to do some substitue there too.                        *
  257. *                                                                             *
  258. * To save memory the RGBs are coded in one long value, as done by the RGB     *
  259. * macro.                                                                      *
  260. *                                                                             *
  261. * Developed by HeDu 3/94 (hedu@cul-ipn.uni-kiel.de)                           *
  262. \*****************************************************************************/
  263.  
  264.  
  265. typedef struct
  266. {
  267.     const char *name;
  268.     wxUint32 rgb;
  269. } rgbRecord;
  270.  
  271. #define myRGB(r,g,b)   ((wxUint32)r<<16|(wxUint32)g<<8|(wxUint32)b)
  272.  
  273. static rgbRecord theRGBRecords[] =
  274. {
  275.     {"aliceblue", myRGB(240, 248, 255)},
  276.     {"antiquewhite", myRGB(250, 235, 215)},
  277.     {"aquamarine", myRGB(50, 191, 193)},
  278.     {"azure", myRGB(240, 255, 255)},
  279.     {"beige", myRGB(245, 245, 220)},
  280.     {"bisque", myRGB(255, 228, 196)},
  281.     {"black", myRGB(0, 0, 0)},
  282.     {"blanchedalmond", myRGB(255, 235, 205)},
  283.     {"blue", myRGB(0, 0, 255)},
  284.     {"blueviolet", myRGB(138, 43, 226)},
  285.     {"brown", myRGB(165, 42, 42)},
  286.     {"burlywood", myRGB(222, 184, 135)},
  287.     {"cadetblue", myRGB(95, 146, 158)},
  288.     {"chartreuse", myRGB(127, 255, 0)},
  289.     {"chocolate", myRGB(210, 105, 30)},
  290.     {"coral", myRGB(255, 114, 86)},
  291.     {"cornflowerblue", myRGB(34, 34, 152)},
  292.     {"cornsilk", myRGB(255, 248, 220)},
  293.     {"cyan", myRGB(0, 255, 255)},
  294.     {"darkgoldenrod", myRGB(184, 134, 11)},
  295.     {"darkgreen", myRGB(0, 86, 45)},
  296.     {"darkkhaki", myRGB(189, 183, 107)},
  297.     {"darkolivegreen", myRGB(85, 86, 47)},
  298.     {"darkorange", myRGB(255, 140, 0)},
  299.     {"darkorchid", myRGB(139, 32, 139)},
  300.     {"darksalmon", myRGB(233, 150, 122)},
  301.     {"darkseagreen", myRGB(143, 188, 143)},
  302.     {"darkslateblue", myRGB(56, 75, 102)},
  303.     {"darkslategray", myRGB(47, 79, 79)},
  304.     {"darkturquoise", myRGB(0, 166, 166)},
  305.     {"darkviolet", myRGB(148, 0, 211)},
  306.     {"deeppink", myRGB(255, 20, 147)},
  307.     {"deepskyblue", myRGB(0, 191, 255)},
  308.     {"dimgray", myRGB(84, 84, 84)},
  309.     {"dodgerblue", myRGB(30, 144, 255)},
  310.     {"firebrick", myRGB(142, 35, 35)},
  311.     {"floralwhite", myRGB(255, 250, 240)},
  312.     {"forestgreen", myRGB(80, 159, 105)},
  313.     {"gainsboro", myRGB(220, 220, 220)},
  314.     {"ghostwhite", myRGB(248, 248, 255)},
  315.     {"gold", myRGB(218, 170, 0)},
  316.     {"goldenrod", myRGB(239, 223, 132)},
  317.     {"gray", myRGB(126, 126, 126)},
  318.     {"gray0", myRGB(0, 0, 0)},
  319.     {"gray1", myRGB(3, 3, 3)},
  320.     {"gray10", myRGB(26, 26, 26)},
  321.     {"gray100", myRGB(255, 255, 255)},
  322.     {"gray11", myRGB(28, 28, 28)},
  323.     {"gray12", myRGB(31, 31, 31)},
  324.     {"gray13", myRGB(33, 33, 33)},
  325.     {"gray14", myRGB(36, 36, 36)},
  326.     {"gray15", myRGB(38, 38, 38)},
  327.     {"gray16", myRGB(41, 41, 41)},
  328.     {"gray17", myRGB(43, 43, 43)},
  329.     {"gray18", myRGB(46, 46, 46)},
  330.     {"gray19", myRGB(48, 48, 48)},
  331.     {"gray2", myRGB(5, 5, 5)},
  332.     {"gray20", myRGB(51, 51, 51)},
  333.     {"gray21", myRGB(54, 54, 54)},
  334.     {"gray22", myRGB(56, 56, 56)},
  335.     {"gray23", myRGB(59, 59, 59)},
  336.     {"gray24", myRGB(61, 61, 61)},
  337.     {"gray25", myRGB(64, 64, 64)},
  338.     {"gray26", myRGB(66, 66, 66)},
  339.     {"gray27", myRGB(69, 69, 69)},
  340.     {"gray28", myRGB(71, 71, 71)},
  341.     {"gray29", myRGB(74, 74, 74)},
  342.     {"gray3", myRGB(8, 8, 8)},
  343.     {"gray30", myRGB(77, 77, 77)},
  344.     {"gray31", myRGB(79, 79, 79)},
  345.     {"gray32", myRGB(82, 82, 82)},
  346.     {"gray33", myRGB(84, 84, 84)},
  347.     {"gray34", myRGB(87, 87, 87)},
  348.     {"gray35", myRGB(89, 89, 89)},
  349.     {"gray36", myRGB(92, 92, 92)},
  350.     {"gray37", myRGB(94, 94, 94)},
  351.     {"gray38", myRGB(97, 97, 97)},
  352.     {"gray39", myRGB(99, 99, 99)},
  353.     {"gray4", myRGB(10, 10, 10)},
  354.     {"gray40", myRGB(102, 102, 102)},
  355.     {"gray41", myRGB(105, 105, 105)},
  356.     {"gray42", myRGB(107, 107, 107)},
  357.     {"gray43", myRGB(110, 110, 110)},
  358.     {"gray44", myRGB(112, 112, 112)},
  359.     {"gray45", myRGB(115, 115, 115)},
  360.     {"gray46", myRGB(117, 117, 117)},
  361.     {"gray47", myRGB(120, 120, 120)},
  362.     {"gray48", myRGB(122, 122, 122)},
  363.     {"gray49", myRGB(125, 125, 125)},
  364.     {"gray5", myRGB(13, 13, 13)},
  365.     {"gray50", myRGB(127, 127, 127)},
  366.     {"gray51", myRGB(130, 130, 130)},
  367.     {"gray52", myRGB(133, 133, 133)},
  368.     {"gray53", myRGB(135, 135, 135)},
  369.     {"gray54", myRGB(138, 138, 138)},
  370.     {"gray55", myRGB(140, 140, 140)},
  371.     {"gray56", myRGB(143, 143, 143)},
  372.     {"gray57", myRGB(145, 145, 145)},
  373.     {"gray58", myRGB(148, 148, 148)},
  374.     {"gray59", myRGB(150, 150, 150)},
  375.     {"gray6", myRGB(15, 15, 15)},
  376.     {"gray60", myRGB(153, 153, 153)},
  377.     {"gray61", myRGB(156, 156, 156)},
  378.     {"gray62", myRGB(158, 158, 158)},
  379.     {"gray63", myRGB(161, 161, 161)},
  380.     {"gray64", myRGB(163, 163, 163)},
  381.     {"gray65", myRGB(166, 166, 166)},
  382.     {"gray66", myRGB(168, 168, 168)},
  383.     {"gray67", myRGB(171, 171, 171)},
  384.     {"gray68", myRGB(173, 173, 173)},
  385.     {"gray69", myRGB(176, 176, 176)},
  386.     {"gray7", myRGB(18, 18, 18)},
  387.     {"gray70", myRGB(179, 179, 179)},
  388.     {"gray71", myRGB(181, 181, 181)},
  389.     {"gray72", myRGB(184, 184, 184)},
  390.     {"gray73", myRGB(186, 186, 186)},
  391.     {"gray74", myRGB(189, 189, 189)},
  392.     {"gray75", myRGB(191, 191, 191)},
  393.     {"gray76", myRGB(194, 194, 194)},
  394.     {"gray77", myRGB(196, 196, 196)},
  395.     {"gray78", myRGB(199, 199, 199)},
  396.     {"gray79", myRGB(201, 201, 201)},
  397.     {"gray8", myRGB(20, 20, 20)},
  398.     {"gray80", myRGB(204, 204, 204)},
  399.     {"gray81", myRGB(207, 207, 207)},
  400.     {"gray82", myRGB(209, 209, 209)},
  401.     {"gray83", myRGB(212, 212, 212)},
  402.     {"gray84", myRGB(214, 214, 214)},
  403.     {"gray85", myRGB(217, 217, 217)},
  404.     {"gray86", myRGB(219, 219, 219)},
  405.     {"gray87", myRGB(222, 222, 222)},
  406.     {"gray88", myRGB(224, 224, 224)},
  407.     {"gray89", myRGB(227, 227, 227)},
  408.     {"gray9", myRGB(23, 23, 23)},
  409.     {"gray90", myRGB(229, 229, 229)},
  410.     {"gray91", myRGB(232, 232, 232)},
  411.     {"gray92", myRGB(235, 235, 235)},
  412.     {"gray93", myRGB(237, 237, 237)},
  413.     {"gray94", myRGB(240, 240, 240)},
  414.     {"gray95", myRGB(242, 242, 242)},
  415.     {"gray96", myRGB(245, 245, 245)},
  416.     {"gray97", myRGB(247, 247, 247)},
  417.     {"gray98", myRGB(250, 250, 250)},
  418.     {"gray99", myRGB(252, 252, 252)},
  419.     {"green", myRGB(0, 255, 0)},
  420.     {"greenyellow", myRGB(173, 255, 47)},
  421.     {"honeydew", myRGB(240, 255, 240)},
  422.     {"hotpink", myRGB(255, 105, 180)},
  423.     {"indianred", myRGB(107, 57, 57)},
  424.     {"ivory", myRGB(255, 255, 240)},
  425.     {"khaki", myRGB(179, 179, 126)},
  426.     {"lavender", myRGB(230, 230, 250)},
  427.     {"lavenderblush", myRGB(255, 240, 245)},
  428.     {"lawngreen", myRGB(124, 252, 0)},
  429.     {"lemonchiffon", myRGB(255, 250, 205)},
  430.     {"lightblue", myRGB(176, 226, 255)},
  431.     {"lightcoral", myRGB(240, 128, 128)},
  432.     {"lightcyan", myRGB(224, 255, 255)},
  433.     {"lightgoldenrod", myRGB(238, 221, 130)},
  434.     {"lightgoldenrodyellow", myRGB(250, 250, 210)},
  435.     {"lightgray", myRGB(168, 168, 168)},
  436.     {"lightpink", myRGB(255, 182, 193)},
  437.     {"lightsalmon", myRGB(255, 160, 122)},
  438.     {"lightseagreen", myRGB(32, 178, 170)},
  439.     {"lightskyblue", myRGB(135, 206, 250)},
  440.     {"lightslateblue", myRGB(132, 112, 255)},
  441.     {"lightslategray", myRGB(119, 136, 153)},
  442.     {"lightsteelblue", myRGB(124, 152, 211)},
  443.     {"lightyellow", myRGB(255, 255, 224)},
  444.     {"limegreen", myRGB(0, 175, 20)},
  445.     {"linen", myRGB(250, 240, 230)},
  446.     {"magenta", myRGB(255, 0, 255)},
  447.     {"maroon", myRGB(143, 0, 82)},
  448.     {"mediumaquamarine", myRGB(0, 147, 143)},
  449.     {"mediumblue", myRGB(50, 50, 204)},
  450.     {"mediumforestgreen", myRGB(50, 129, 75)},
  451.     {"mediumgoldenrod", myRGB(209, 193, 102)},
  452.     {"mediumorchid", myRGB(189, 82, 189)},
  453.     {"mediumpurple", myRGB(147, 112, 219)},
  454.     {"mediumseagreen", myRGB(52, 119, 102)},
  455.     {"mediumslateblue", myRGB(106, 106, 141)},
  456.     {"mediumspringgreen", myRGB(35, 142, 35)},
  457.     {"mediumturquoise", myRGB(0, 210, 210)},
  458.     {"mediumvioletred", myRGB(213, 32, 121)},
  459.     {"midnightblue", myRGB(47, 47, 100)},
  460.     {"mintcream", myRGB(245, 255, 250)},
  461.     {"mistyrose", myRGB(255, 228, 225)},
  462.     {"moccasin", myRGB(255, 228, 181)},
  463.     {"navajowhite", myRGB(255, 222, 173)},
  464.     {"navy", myRGB(35, 35, 117)},
  465.     {"navyblue", myRGB(35, 35, 117)},
  466.     {"oldlace", myRGB(253, 245, 230)},
  467.     {"olivedrab", myRGB(107, 142, 35)},
  468.     {"orange", myRGB(255, 135, 0)},
  469.     {"orangered", myRGB(255, 69, 0)},
  470.     {"orchid", myRGB(239, 132, 239)},
  471.     {"palegoldenrod", myRGB(238, 232, 170)},
  472.     {"palegreen", myRGB(115, 222, 120)},
  473.     {"paleturquoise", myRGB(175, 238, 238)},
  474.     {"palevioletred", myRGB(219, 112, 147)},
  475.     {"papayawhip", myRGB(255, 239, 213)},
  476.     {"peachpuff", myRGB(255, 218, 185)},
  477.     {"peru", myRGB(205, 133, 63)},
  478.     {"pink", myRGB(255, 181, 197)},
  479.     {"plum", myRGB(197, 72, 155)},
  480.     {"powderblue", myRGB(176, 224, 230)},
  481.     {"purple", myRGB(160, 32, 240)},
  482.     {"red", myRGB(255, 0, 0)},
  483.     {"rosybrown", myRGB(188, 143, 143)},
  484.     {"royalblue", myRGB(65, 105, 225)},
  485.     {"saddlebrown", myRGB(139, 69, 19)},
  486.     {"salmon", myRGB(233, 150, 122)},
  487.     {"sandybrown", myRGB(244, 164, 96)},
  488.     {"seagreen", myRGB(82, 149, 132)},
  489.     {"seashell", myRGB(255, 245, 238)},
  490.     {"sienna", myRGB(150, 82, 45)},
  491.     {"skyblue", myRGB(114, 159, 255)},
  492.     {"slateblue", myRGB(126, 136, 171)},
  493.     {"slategray", myRGB(112, 128, 144)},
  494.     {"snow", myRGB(255, 250, 250)},
  495.     {"springgreen", myRGB(65, 172, 65)},
  496.     {"steelblue", myRGB(84, 112, 170)},
  497.     {"tan", myRGB(222, 184, 135)},
  498.     {"thistle", myRGB(216, 191, 216)},
  499.     {"tomato", myRGB(255, 99, 71)},
  500.     {"transparent", myRGB(0, 0, 1)},
  501.     {"turquoise", myRGB(25, 204, 223)},
  502.     {"violet", myRGB(156, 62, 206)},
  503.     {"violetred", myRGB(243, 62, 150)},
  504.     {"wheat", myRGB(245, 222, 179)},
  505.     {"white", myRGB(255, 255, 255)},
  506.     {"whitesmoke", myRGB(245, 245, 245)},
  507.     {"yellow", myRGB(255, 255, 0)},
  508.     {"yellowgreen", myRGB(50, 216, 56)},
  509.     {NULL, myRGB(0, 0, 0)}
  510. };
  511. static int numTheRGBRecords = 234;
  512.  
  513. static unsigned char ParseHexadecimal(char digit1, char digit2)
  514. {
  515.     unsigned char i1, i2;
  516.  
  517.     if (digit1 >= 'a')
  518.         i1 = digit1 - 'a' + 0x0A;
  519.     else if (digit1 >= 'A')
  520.         i1 = digit1 - 'A' + 0x0A;
  521.     else
  522.         i1 = digit1 - '0';
  523.     if (digit2 >= 'a')
  524.         i2 = digit2 - 'a' + 0x0A;
  525.     else if (digit2 >= 'A')
  526.         i2 = digit2 - 'A' + 0x0A;
  527.     else
  528.         i2 = digit2 - '0';
  529.     return (0x10 * i1 + i2);
  530. }
  531.  
  532. static bool GetRGBFromName(const char *inname, bool *isNone,
  533.                            unsigned char *r, unsigned char*g, unsigned char *b)
  534. {
  535.     int left, right, middle;
  536.     int cmp;
  537.     wxUint32 rgbVal;
  538.     char *name;
  539.     char *grey, *p;
  540.  
  541.     // Neither #rrggbb nor #rrrrggggbbbb are in database, we parse them directly
  542.     size_t inname_len = strlen(inname);
  543.     if ( *inname == '#' && (inname_len == 7 || inname_len == 13))
  544.     {
  545.         size_t ofs = (inname_len == 7) ? 2 : 4;
  546.         *r = ParseHexadecimal(inname[1], inname[2]);
  547.         *g = ParseHexadecimal(inname[1*ofs+1], inname[1*ofs+2]);
  548.         *b = ParseHexadecimal(inname[2*ofs+1], inname[2*ofs+2]);
  549.         *isNone = FALSE;
  550.         return TRUE;
  551.     }
  552.  
  553.     name = strdup(inname);
  554.  
  555.     // theRGBRecords[] has no names with spaces, and no grey, but a
  556.     // lot of gray...
  557.  
  558.     // so first extract ' '
  559.     while ((p = strchr(name, ' ')) != NULL)
  560.     {
  561.         while (*(p))            // till eof of string
  562.         {
  563.             *p = *(p + 1);      // copy to the left
  564.             p++;
  565.         }
  566.     }
  567.     // fold to lower case
  568.     p = name;
  569.     while (*p)
  570.     {
  571.         *p = tolower(*p);
  572.         p++;
  573.     }
  574.  
  575.     // substitute Grey with Gray, else rgbtab.h would have more than 100
  576.     // 'duplicate' entries
  577.     if ( (grey = strstr(name, "grey")) != NULL )
  578.         grey[2] = 'a';
  579.  
  580.     // check for special 'none' colour:
  581.     bool found;
  582.     if ( strcmp(name, "none") == 0 )
  583.     {
  584.         *isNone = TRUE;
  585.         found = TRUE;
  586.     }
  587.     else // not "None"
  588.     {
  589.         found = FALSE;
  590.  
  591.         // binary search:
  592.         left = 0;
  593.         right = numTheRGBRecords - 1;
  594.         do
  595.         {
  596.             middle = (left + right) / 2;
  597.             cmp = strcmp(name, theRGBRecords[middle].name);
  598.             if ( cmp == 0 )
  599.             {
  600.                 rgbVal = theRGBRecords[middle].rgb;
  601.                 *r = (unsigned char)((rgbVal >> 16) & 0xFF);
  602.                 *g = (unsigned char)((rgbVal >> 8) & 0xFF);
  603.                 *b = (unsigned char)((rgbVal) & 0xFF);
  604.                 *isNone = FALSE;
  605.                 found = TRUE;
  606.                 break;
  607.             }
  608.             else if ( cmp < 0 )
  609.             {
  610.                 right = middle - 1;
  611.             }
  612.             else // cmp > 0
  613.             {
  614.                 left = middle + 1;
  615.             }
  616.         } while (left <= right);
  617.     }
  618.  
  619.     free(name);
  620.  
  621.     return found;
  622. }
  623.  
  624. static const char *ParseColor(const char *data)
  625. {
  626.     static const char *targets[] =
  627.                         {"c ", "g ", "g4 ", "m ", "b ", "s ", NULL};
  628.  
  629.     const char *p, *r;
  630.     const char *q;
  631.     int i;
  632.  
  633.     for (i = 0; targets[i] != NULL; i++)
  634.     {
  635.         r = data;
  636.         for (q = targets[i]; *r != '\0'; r++)
  637.         {
  638.             if ( *r != *q )
  639.                 continue;
  640.             if ( !isspace((int) (*(r - 1))) )
  641.                 continue;
  642.             p = r;
  643.             for (;;)
  644.             {
  645.                 if ( *q == '\0' )
  646.                     return p;
  647.                 if ( *p++ != *q++ )
  648.                     break;
  649.             }
  650.             q = targets[i];
  651.         }
  652.     }
  653.     return NULL;
  654. }
  655.  
  656. struct wxXPMColourMapData
  657. {
  658.     unsigned char R,G,B;
  659. };
  660. WX_DECLARE_STRING_HASH_MAP(wxXPMColourMapData, wxXPMColourMap);
  661.  
  662. wxImage wxXPMDecoder::ReadData(const char **xpm_data)
  663. {
  664.     wxImage img;
  665.     int count;
  666.     unsigned width, height, colors_cnt, chars_per_pixel;
  667.     size_t i, j, i_key;
  668.     wxChar key[64];
  669.     const char *clr_def;
  670.     bool hasMask;
  671.     wxXPMColourMapData clr_data;
  672.     wxXPMColourMap clr_tbl;
  673.  
  674.     /*
  675.      *  Read hints and initialize structures:
  676.      */
  677.      
  678.     count = sscanf(xpm_data[0], "%u %u %u %u",
  679.                    &width, &height, &colors_cnt, &chars_per_pixel);
  680.     if ( count != 4 || width * height * colors_cnt == 0 )
  681.     {
  682.         wxLogError(_T("XPM: Not XPM data!"));
  683.         return wxNullImage;
  684.     }
  685.  
  686.     // VS: XPM color map this large would be insane, since XPMs are encoded with
  687.     //     92 possible values on each position, 92^64 is *way* larger space than
  688.     //     8bit RGB...
  689.     wxCHECK_MSG(chars_per_pixel < 64, wxNullImage, wxT("XPM colormaps this large not supported."));
  690.  
  691.     img.Create(width, height);
  692.     if ( !img.Ok() ) return img;
  693.  
  694.     img.SetMask(FALSE);
  695.     key[chars_per_pixel] = wxT('\0');
  696.     hasMask = FALSE;
  697.  
  698.     /*
  699.      *  Create colour map:
  700.      */
  701.     for (i = 0; i < colors_cnt; i++)
  702.     {
  703.         for (i_key = 0; i_key < chars_per_pixel; i_key++)
  704.             key[i_key] = (wxChar)xpm_data[1 + i][i_key];
  705.         clr_def = ParseColor(xpm_data[1 + i] + chars_per_pixel);
  706.  
  707.         if ( clr_def == NULL )
  708.         {
  709.             wxLogError(_("XPM: malformed colour definition '%s'!"), xpm_data[1+i]);
  710.             clr_data.R = 255, clr_data.G = 0, clr_data.B = 255;
  711.         }
  712.         else
  713.         {
  714.             bool isNone;
  715.             if ( !GetRGBFromName(clr_def, &isNone,
  716.                                  &clr_data.R, &clr_data.G, &clr_data.B) )
  717.             {
  718.                 wxLogError(_("XPM: malformed colour definition '%s'!"), xpm_data[1+i]);
  719.                 clr_data.R = 255, clr_data.G = 0, clr_data.B = 255;
  720.             }
  721.             else
  722.             {
  723.                 if ( isNone )
  724.                 {
  725.                     img.SetMask(TRUE);
  726.                     img.SetMaskColour(255, 0, 255);
  727.                     hasMask = TRUE;
  728.                     clr_data.R = 255, clr_data.G = 0, clr_data.B = 255;
  729.                 }
  730.                 else
  731.                 {
  732.                     if ( hasMask && clr_data.R == 255 &&
  733.                                     clr_data.G == 0 && clr_data.B == 255 )
  734.                         clr_data.B = 254;
  735.                 }
  736.             }
  737.         }
  738.         clr_tbl[key] = clr_data;
  739.     }
  740.  
  741.     /*
  742.      *  Parse image data:
  743.      */
  744.  
  745.     unsigned char *img_data = img.GetData();
  746.     wxXPMColourMap::iterator entry;
  747.     wxXPMColourMap::iterator end = clr_tbl.end();
  748.     
  749.     for (j = 0; j < height; j++)
  750.     {
  751.         for (i = 0; i < width; i++, img_data += 3)
  752.         {
  753.             for (i_key = 0; i_key < chars_per_pixel; i_key++)
  754.                 key[i_key] = (wxChar)xpm_data[1 + colors_cnt + j]
  755.                                              [chars_per_pixel * i + i_key];
  756.             entry = clr_tbl.find(key);
  757.             if ( entry == end )
  758.             {
  759.                 wxLogError(_("XPM: Malformed pixel data!"));
  760.             }
  761.             else
  762.             {
  763.                 img_data[0] = entry->second.R;
  764.                 img_data[1] = entry->second.G;
  765.                 img_data[2] = entry->second.B;
  766.             }
  767.         }
  768.     }
  769.  
  770.     return img;
  771. }
  772.  
  773. #endif // wxUSE_IMAGE && wxUSE_XPM
  774.