home *** CD-ROM | disk | FTP | other *** search
/ Compressed Image File Formats / CompressedImageFileFormatsJohnMiano.iso / pc / Library / source / xbmdecod.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-12-17  |  12.5 KB  |  593 lines

  1. //
  2. // Copyright (c) 1997,1998 Colosseum Builders, Inc.
  3. // All rights reserved.
  4. //
  5. // Colosseum Builders, Inc. makes no warranty, expressed or implied
  6. // with regards to this software. It is provided as is.
  7. //
  8. // See the README.TXT file that came with this software for restrictions
  9. // on the use and redistribution of this file or send E-mail to
  10. // info@colosseumbuilders.com
  11. //
  12.  
  13. //
  14. //  Title:  XBM Decoder
  15. //
  16. //  Author:  John M. Miano  miano@colosseumbuilers.com
  17. //
  18.  
  19. #include <ctype.h>
  20. #include <string>
  21.  
  22. #include "xbmdecod.h"
  23. #include "xbmpvt.h"
  24.  
  25. using namespace std ;
  26.  
  27. // File Tokens
  28. enum Token
  29. {
  30.   Invalid,    // INVALID TOKEN
  31.   Define,     // #define
  32.   Comma,      // ,
  33.   Integer,    // 123 0x123 0123
  34.   Static,     // static
  35.   Char,       // char
  36.   Bits,       // name_bits
  37.   LBrace,     // {
  38.   RBrace,     // }
  39.   Equal,      // =
  40.   LBracket,   // [
  41.   RBracket,   // ]
  42.   HotX,       // name_hot_x
  43.   HotY,       // name_hot_y
  44.   Width,      // name_width
  45.   Height,     // name_height
  46.   Semicolon,  // ;
  47.   Unsigned,   // signed or unsigned
  48. } ;
  49. const NoData = 0xFFFF ;
  50.  
  51. //
  52. //  Description:
  53. //
  54. //    Class default constructor
  55. //
  56. XbmDecoder::XbmDecoder ()
  57. {
  58.   Initialize () ;
  59.   return ;
  60. }
  61.  
  62. //
  63. //  Description:
  64. //
  65. //    Class copy constructor
  66. //
  67. XbmDecoder::XbmDecoder (const XbmDecoder &source)
  68. {
  69.   Initialize () ;
  70.   DoCopy (source) ;
  71.   return ;
  72. }
  73.  
  74. //
  75. //  Descripton:
  76. //
  77. //    Class Default Constructor
  78. //
  79. XbmDecoder::~XbmDecoder ()
  80. {
  81.   return ;
  82. }
  83.  
  84. //
  85. //  Description:
  86. //
  87. //    Class initialization function.
  88. //
  89. void XbmDecoder::Initialize ()
  90. {
  91.   image_name = "" ;
  92.   hot_spot_x = -1 ;
  93.   hot_spot_y = -1 ;
  94.   return ;
  95. }
  96.  
  97. //
  98. //  Description:
  99. //
  100. //    Object copy function.
  101. //
  102. void XbmDecoder::DoCopy (const XbmDecoder &source)
  103. {
  104.   image_name = source.image_name ;
  105.   hot_spot_x = source.hot_spot_x ;
  106.   hot_spot_y = source.hot_spot_y ;
  107.   return;
  108. }
  109.  
  110. //
  111. //  Description:
  112. //
  113. //    Class assignment operator.
  114. //
  115. XbmDecoder &XbmDecoder::operator=(const XbmDecoder &source)
  116. {
  117.   DoCopy (source) ;
  118.   return *this ;
  119. }
  120.  
  121. //
  122. //  Description:
  123. //
  124. //    This function reads an XBM file from an input stream.
  125. //
  126. //    The format is (according to our grammar):
  127. //
  128. //      Define Width Integer
  129. //      Define Height Integer
  130. //      [Define HotX Integer
  131. //       Define HotY Integer]
  132. //      Static [signed|unsigned] Char LBracket RightBracket Equal
  133. //      LBrace
  134. //        Integer Comma Integer Comma ... Integer [Comma]
  135. //      RBrace Semicolon
  136. //
  137. //    In other words
  138. //
  139. //      #define name_width 124
  140. //      #define name_height 124
  141. //     -#define name_hot_x 124
  142. //     -#define name_hot_y 124
  143. //      static --un-signed- char name_bits [] = {
  144. //                 0x1, 0x2, .... } ;
  145. //
  146. //  Parameters:
  147. //    strm:  The input stream
  148. //    image: The image object
  149. //
  150. void XbmDecoder::ReadImage (std::istream &strm, BitmapImage &image)
  151. {
  152.   last_char = '\n' ;
  153.   hot_spot_x = -1 ;
  154.   hot_spot_y = -1 ;
  155.   int width = -1 ;
  156.   int height = -1 ;
  157.  
  158.   // Read Image Width/Height
  159.   Token token = (Token) NextToken (strm) ;
  160.   if (token != Define)
  161.     throw EXbmInvalid () ;
  162.  
  163.   token = (Token) NextToken (strm) ;
  164.   if (token == Height)
  165.   {
  166.     token = (Token) NextToken (strm) ;
  167.     if (token != Integer)
  168.       throw EXbmInvalid () ;
  169.     height = lexical_value ;
  170.   }
  171.   else if (token == Width)
  172.   {
  173.     token = (Token) NextToken (strm) ;
  174.     if (token != Integer)
  175.       throw EXbmInvalid () ;
  176.     width = lexical_value ;
  177.   }
  178.   else
  179.   {
  180.     throw EXbmInvalid () ;
  181.   }
  182.  
  183.   token = (Token) NextToken (strm) ;
  184.   if (token != Define)
  185.     throw EXbmInvalid () ;
  186.  
  187.   token = (Token) NextToken (strm) ;
  188.   if (token == Height)
  189.   {
  190.     token = (Token) NextToken (strm) ;
  191.     if (token != Integer)
  192.       throw EXbmInvalid () ;
  193.     height = lexical_value ;
  194.   }
  195.   else if (token == Width)
  196.   {
  197.     token = (Token) NextToken (strm) ;
  198.     if (token != Integer)
  199.       throw EXbmInvalid () ;
  200.     width = lexical_value ;
  201.   }
  202.   else
  203.   {
  204.     throw EXbmInvalid () ;
  205.   }
  206.   if (height < 0 || width < 0)
  207.     throw EXbmInvalid () ; // Width and Height must be specified
  208.  
  209.   // Read Hot Spot X
  210.   token = (Token) NextToken (strm) ;
  211.   if (token == Define)
  212.   {
  213.     token = (Token) NextToken (strm) ;
  214.     if (token != HotX)
  215.       throw EXbmInvalid () ;
  216.  
  217.     token = (Token) NextToken (strm) ;
  218.     if (token != Integer)
  219.       throw EXbmInvalid () ;
  220.     hot_spot_x = lexical_value ;
  221.  
  222.     token = (Token) NextToken (strm) ;
  223.     if (token != Define)
  224.       throw EXbmInvalid () ;
  225.  
  226.     // Read the Hot spot Y
  227.     token = (Token) NextToken (strm) ;
  228.     if (token != HotY)
  229.       throw EXbmInvalid () ;
  230.  
  231.     token = (Token) NextToken (strm) ;
  232.     if (token != Integer)
  233.       throw EXbmInvalid () ;
  234.     hot_spot_y = lexical_value ;
  235.     token = (Token) NextToken (strm) ;
  236.   }
  237.   if (token != Static)
  238.     throw EXbmInvalid () ;
  239.  
  240.   // Optional signed or unsigned
  241.   token = (Token) NextToken (strm) ;
  242.   if (token == Unsigned)
  243.     token = (Token) NextToken (strm) ;
  244.  
  245.   if (token != Char)
  246.     throw EXbmInvalid () ;
  247.  
  248.   token = (Token) NextToken (strm) ;
  249.   if (token != Bits)
  250.     throw EXbmInvalid () ;
  251.  
  252.   token = (Token) NextToken (strm) ;
  253.   if (token != LBracket)
  254.     throw EXbmInvalid () ;
  255.  
  256.   token = (Token) NextToken (strm) ;
  257.   if (token != RBracket)
  258.     throw EXbmInvalid () ;
  259.  
  260.   token = (Token) NextToken (strm) ;
  261.   if (token != Equal)
  262.     throw EXbmInvalid () ;
  263.  
  264.   token = (Token) NextToken (strm) ;
  265.   if (token != LBrace)
  266.     throw EXbmInvalid () ;
  267.  
  268.   image.SetSize (2, 1, width, height) ;
  269.   image.ColorMap (0).red = 255 ;
  270.   image.ColorMap (0).green = 255 ;
  271.   image.ColorMap (0).blue = 255 ;
  272.   image.ColorMap (1).red = 0 ;
  273.   image.ColorMap (1).green = 0 ;
  274.   image.ColorMap (1).blue = 0 ;
  275.  
  276.   for (unsigned int ii = 0 ; ii < height ; ++ ii)
  277.   {
  278.     for (unsigned int jj = 0 ; jj < (width + 7) / 8 ; ++ jj)
  279.     {
  280.       token = (Token) NextToken (strm) ;
  281.       if (token != Integer)
  282.         throw EXbmInvalid () ;
  283.       image [ii][jj] = RotateByte (lexical_value) ;
  284.       token = (Token) NextToken (strm) ;
  285.       if (token != Comma && ii != height - 1 && jj != width - 1)
  286.         throw EXbmInvalid () ;
  287.     }
  288.   }
  289.  
  290.   if (token == Comma)
  291.     token = (Token) NextToken (strm) ;
  292.   if (token != RBrace)
  293.     throw EXbmInvalid () ;
  294.  
  295.   token = (Token) NextToken (strm) ;
  296.   if (token != Semicolon)
  297.     throw EXbmInvalid () ;
  298.  
  299.   return ;
  300. }
  301.  
  302. //
  303. //  Description:
  304. //
  305. //    This function return the X coordinate of the Hot Spot
  306. //
  307. //  Return Value:
  308. //    >= 0 => The Hot Spot X coordinate
  309. //    < 0 => No Hot Spot
  310. //
  311. int XbmDecoder::GetHotSpotX () const
  312. {
  313.   return hot_spot_x ;
  314. }
  315.  
  316. //
  317. //  Description:
  318. //
  319. //    This function return the Y coordinate of the Hot Spot
  320. //
  321. //  Return Value:
  322. //    >= 0 => The Hot Spot Y coordinate
  323. //    < 0 => No Hot Spot
  324. //
  325. int XbmDecoder::GetHotSpotY () const
  326. {
  327.   return hot_spot_y ;
  328. }
  329.  
  330. //
  331. //  Description:
  332. //
  333. //    This function returns the name of the image used in the XBM file.
  334. //
  335. //  Return Value:
  336. //    The image name
  337. //
  338. std::string XbmDecoder::GetImageName () const
  339. {
  340.   return image_name ;
  341. }
  342.  
  343. //
  344. //  Description:
  345. //
  346. //    This function returns the next character in the input stream. One
  347. //    character of push back is supported.
  348. //
  349. //  Return Value:
  350. //    >= 0 => The next character in in the input stream.
  351. //    < 0 => EOF
  352. //
  353. int XbmDecoder::NextChar (std::istream &strm)
  354. {
  355.   if (last_char != NoData)
  356.   {
  357.     int value = last_char ;
  358.     last_char = NoData ;
  359.     return value ;
  360.   }
  361.  
  362.   char data ;
  363.   if (strm.eof ())
  364.     return -1 ;
  365.  
  366.   strm.read (&data, sizeof (data)) ;
  367.   return data ;
  368. }
  369.  
  370. //
  371. //  Description:
  372. //
  373. //    This function returns an identifier for the next token in the input
  374. //    stream.
  375. //
  376. //  Return Value:
  377. //    Enumeration from the Token type.
  378. //    The member variable lexical_value contains the value of an
  379. //    integer token.
  380. //
  381. int XbmDecoder::NextToken (std::istream &strm)
  382. {
  383.   int thischar = NextChar (strm) ;
  384.  
  385.   while (isspace (thischar) && thischar != '\n')
  386.     thischar = NextChar (strm) ;
  387.  
  388.   // Check for \n#<SPACE>define
  389.   if (thischar == '\n')
  390.   {
  391.     thischar = NextChar (strm) ;
  392.     if (thischar == '#')
  393.     {
  394.       thischar = NextChar (strm) ;
  395.       while (isspace (thischar))
  396.         thischar = NextChar (strm) ;
  397.  
  398.       if (thischar != 'd')
  399.         return Invalid ;
  400.       thischar = NextChar (strm) ;
  401.       if (thischar != 'e')
  402.         return Invalid ;
  403.       thischar = NextChar (strm) ;
  404.       if (thischar != 'f')
  405.         return Invalid ;
  406.       thischar = NextChar (strm) ;
  407.       if (thischar != 'i')
  408.         return Invalid ;
  409.       thischar = NextChar (strm) ;
  410.       if (thischar != 'n')
  411.         return Invalid ;
  412.       thischar = NextChar (strm) ;
  413.       if (thischar != 'e')
  414.         return Invalid ;
  415.  
  416.       thischar = NextChar (strm) ;
  417.       if (! isspace (thischar))
  418.         return Invalid ;
  419.  
  420.       return Define ;
  421.     }
  422.   }
  423.   // Skip whitespace
  424.   while (isspace (thischar))
  425.     thischar = NextChar (strm) ;
  426.  
  427.   // Check for one-character tokens
  428.   last_char = NoData ;
  429.   if (thischar == ',')
  430.   {
  431.     return Comma ;
  432.   }
  433.   else if (thischar == '[')
  434.   {
  435.     return LBracket ;
  436.   }
  437.   else if (thischar == ']')
  438.   {
  439.     return RBracket ;
  440.   }
  441.   else if (thischar == '{')
  442.   {
  443.     return LBrace ;
  444.   }
  445.   else if (thischar == '}')
  446.   {
  447.     return RBrace ;
  448.   }
  449.   else if (thischar == '=')
  450.   {
  451.     return Equal ;
  452.   }
  453.   else if (thischar == ';')
  454.   {
  455.     return Semicolon ;
  456.   }
  457.  
  458.   if (isdigit (thischar))
  459.   {
  460.     lexical_value = 0 ;
  461.     if (thischar == '0')
  462.     {
  463.       thischar = NextChar (strm) ;
  464.       if (thischar == 'x' || thischar == 'X')
  465.       {
  466.         thischar = NextChar (strm) ;
  467.         while (true)
  468.         {
  469.           if (isdigit (thischar))
  470.           {
  471.             lexical_value *= 16 ;
  472.             lexical_value += thischar - '0' ;
  473.           }
  474.           else if (thischar >= 'a' && thischar <= 'f')
  475.           {
  476.             lexical_value *= 16 ;
  477.             lexical_value += thischar - 'a' + 10 ;
  478.           }
  479.           else if (thischar >= 'A' && thischar <= 'F')
  480.           {
  481.             lexical_value *= 16 ;
  482.             lexical_value += thischar - 'A' + 10 ;
  483.           }
  484.           else
  485.           {
  486.             if (isalnum (thischar))
  487.               return Invalid ;
  488.  
  489.             last_char = thischar ;
  490.             return Integer ;
  491.           }
  492.           thischar = NextChar (strm) ;
  493.         }
  494.       }
  495.       else
  496.       {
  497.         // Octal Integer or Zero
  498.         while (thischar >= '0' && thischar <= '7')
  499.         {
  500.           lexical_value *= 8 ;
  501.           lexical_value += thischar - '0' ;
  502.           thischar = NextChar (strm) ;
  503.         }
  504.         // A Zero Integer
  505.         if (isalnum (thischar))
  506.           return Invalid ;
  507.         last_char = thischar ;
  508.         return Integer ;
  509.       }
  510.     }
  511.     else
  512.     {
  513.       // Handle Decimal Integers
  514.       lexical_value = 0 ;
  515.       while (thischar >= '0' && thischar <= '9')
  516.       {
  517.         lexical_value *= 10 ;
  518.         lexical_value += thischar - '0' ;
  519.         thischar = NextChar (strm) ;
  520.       }
  521.       if (isalnum (thischar))
  522.         return Invalid ;
  523.       last_char = thischar ;
  524.       return Integer ;
  525.     }
  526.   }
  527.  
  528.   if (! (isalpha (thischar) || thischar == '_'))
  529.     return Invalid ;
  530.  
  531.   const int buffersize = 256 ;
  532.   char buffer [buffersize] ;
  533.   unsigned int length = 0 ;
  534.   while (isalnum (thischar) || thischar == '_')
  535.   {
  536.     if (length >= buffersize)
  537.       return Invalid ;
  538.  
  539.     buffer [length] = thischar ;
  540.     ++ length ;
  541.     thischar = NextChar (strm) ;
  542.   }
  543.   if (length >= buffersize)
  544.     return Invalid ;
  545.   buffer [length] = '\000' ;
  546.   last_char = thischar ;
  547.  
  548.   if (std::string (buffer) == "char")
  549.   {
  550.     return Char ;
  551.   }
  552.   else if (std::string (buffer) == "static")
  553.   {
  554.     return Static ;
  555.   }
  556.   else if (std::string (buffer) == "unsigned"
  557.            || std::string (buffer) == "signed")
  558.   {
  559.     return Unsigned ;
  560.   }
  561.  
  562.   if (length < 6)
  563.     return Invalid ;
  564.  
  565.   if (std::string (&buffer [length - 5]) == "_bits")
  566.   {
  567.     image_name = std::string (buffer).substr (0, length - 5) ;
  568.     return Bits ;
  569.   }
  570.  
  571.   if (length < 7)
  572.     return Invalid ;
  573.  
  574.   if (std::string (&buffer [length - 6]) == "_x_hot")
  575.     return HotX ;
  576.   else if (std::string (&buffer [length - 6]) == "_y_hot")
  577.     return HotY ;
  578.   else if (std::string (&buffer [length - 6]) == "_width")
  579.     return Width ;
  580.   
  581.   if (length < 8)
  582.     return Invalid ;
  583.  
  584.   if (std::string (&buffer [length - 7]) == "_height")
  585.     return Height ;
  586.  
  587.   return Invalid ;
  588. }
  589.  
  590.  
  591.  
  592.  
  593.