1 /*
   2  * Copyright (c) 1995, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 /*-
  27  *      Reads xbitmap format images into a DIBitmap structure.
  28  */
  29 package sun.awt.image;
  30 
  31 import java.io.*;
  32 import java.awt.image.*;
  33 
  34 /**
  35  * Parse files of the form:
  36  *
  37  * #define foo_width w
  38  * #define foo_height h
  39  * static char foo_bits[] = {
  40  * 0xnn,0xnn,0xnn,0xnn,0xnn,0xnn,0xnn,0xnn,0xnn,0xnn,0xnn,0xnn,0xnn,0xnn,0xnn,
  41  * 0xnn,0xnn,0xnn,0xnn,0xnn,0xnn,0xnn,0xnn,0xnn,0xnn,0xnn,0xnn,0xnn,0xnn,0xnn,
  42  * 0xnn,0xnn,0xnn,0xnn};
  43  *
  44  * @author James Gosling
  45  */
  46 public class XbmImageDecoder extends ImageDecoder {
  47     private static byte[] XbmColormap = {(byte) 255, (byte) 255, (byte) 255,
  48                                          0, 0, 0};
  49     private static int XbmHints = (ImageConsumer.TOPDOWNLEFTRIGHT |
  50                                    ImageConsumer.COMPLETESCANLINES |
  51                                    ImageConsumer.SINGLEPASS |
  52                                    ImageConsumer.SINGLEFRAME);
  53 
  54     public XbmImageDecoder(InputStreamImageSource src, InputStream is) {
  55         super(src, is);
  56         if (!(input instanceof BufferedInputStream)) {
  57             // If the topmost stream is a metered stream,
  58             // we take forever to decode the image...
  59             input = new BufferedInputStream(input, 80);
  60         }
  61     }
  62 
  63 
  64     /**
  65      * An error has occurred. Throw an exception.
  66      */
  67     private static void error(String s1) throws ImageFormatException {
  68         throw new ImageFormatException(s1);
  69     }
  70 
  71     /**
  72      * produce an image from the stream.
  73      */
  74     public void produceImage() throws IOException, ImageFormatException {
  75         char[] nm = new char[80];
  76         int c;
  77         int i = 0;
  78         int state = 0;
  79         int H = 0;
  80         int W = 0;
  81         int x = 0;
  82         int y = 0;
  83         boolean start = true;
  84         byte[] raster = null;
  85         IndexColorModel model = null;
  86         while (!aborted && (c = input.read()) != -1) {
  87             if ('a' <= c && c <= 'z' ||
  88                     'A' <= c && c <= 'Z' ||
  89                     '0' <= c && c <= '9' || c == '#' || c == '_') {
  90                 if (i < 78)
  91                     nm[i++] = (char) c;
  92             } else if (i > 0) {
  93                 int nc = i;
  94                 i = 0;
  95                 if (start) {
  96                     if (nc != 7 ||
  97                         nm[0] != '#' ||
  98                         nm[1] != 'd' ||
  99                         nm[2] != 'e' ||
 100                         nm[3] != 'f' ||
 101                         nm[4] != 'i' ||
 102                         nm[5] != 'n' ||
 103                         nm[6] != 'e')
 104                     {
 105                         error("Not an XBM file");
 106                     }
 107                     start = false;
 108                 }
 109                 if (nm[nc - 1] == 'h')
 110                     state = 1;  /* expecting width */
 111                 else if (nm[nc - 1] == 't' && nc > 1 && nm[nc - 2] == 'h')
 112                     state = 2;  /* expecting height */
 113                 else if (nc > 2 && state < 0 && nm[0] == '0' && nm[1] == 'x') {
 114                     int n = 0;
 115                     for (int p = 2; p < nc; p++) {
 116                         c = nm[p];
 117                         if ('0' <= c && c <= '9')
 118                             c = c - '0';
 119                         else if ('A' <= c && c <= 'Z')
 120                             c = c - 'A' + 10;
 121                         else if ('a' <= c && c <= 'z')
 122                             c = c - 'a' + 10;
 123                         else
 124                             c = 0;
 125                         n = n * 16 + c;
 126                     }
 127                     for (int mask = 1; mask <= 0x80; mask <<= 1) {
 128                         if (x < W) {
 129                             if ((n & mask) != 0)
 130                                 raster[x] = 1;
 131                             else
 132                                 raster[x] = 0;
 133                         }
 134                         x++;
 135                     }
 136                     if (x >= W) {
 137                         if (setPixels(0, y, W, 1, model, raster, 0, W) <= 0) {
 138                             return;
 139                         }
 140                         x = 0;
 141                         if (y++ >= H) {
 142                             break;
 143                         }
 144                     }
 145                 } else {
 146                     int n = 0;
 147                     for (int p = 0; p < nc; p++)
 148                         if ('0' <= (c = nm[p]) && c <= '9')
 149                             n = n * 10 + c - '0';
 150                         else {
 151                             n = -1;
 152                             break;
 153                         }
 154                     if (n > 0 && state > 0) {
 155                         if (state == 1)
 156                             W = n;
 157                         else
 158                             H = n;
 159                         if (W == 0 || H == 0)
 160                             state = 0;
 161                         else {
 162                             model = new IndexColorModel(8, 2, XbmColormap,
 163                                                         0, false, 0);
 164                             setDimensions(W, H);
 165                             setColorModel(model);
 166                             setHints(XbmHints);
 167                             headerComplete();
 168                             raster = new byte[W];
 169                             state = -1;
 170                         }
 171                     }
 172                 }
 173             }
 174         }
 175         input.close();
 176         imageComplete(ImageConsumer.STATICIMAGEDONE, true);
 177     }
 178 }