mirror of
https://github.com/openjdk/jdk.git
synced 2026-04-25 14:20:35 +00:00
208 lines
8.0 KiB
Java
208 lines
8.0 KiB
Java
/*
|
|
* Copyright (c) 1995, 2025, Oracle and/or its affiliates. All rights reserved.
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
* published by the Free Software Foundation. Oracle designates this
|
|
* particular file as subject to the "Classpath" exception as provided
|
|
* by Oracle in the LICENSE file that accompanied this code.
|
|
*
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
* accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU General Public License version
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
* questions.
|
|
*/
|
|
|
|
/*
|
|
* Reads xbitmap format images into a DIBitmap structure.
|
|
*/
|
|
package sun.awt.image;
|
|
|
|
import java.awt.image.ImageConsumer;
|
|
import java.awt.image.IndexColorModel;
|
|
import java.io.BufferedInputStream;
|
|
import java.io.BufferedReader;
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.io.InputStreamReader;
|
|
import java.util.regex.Matcher;
|
|
import java.util.regex.Pattern;
|
|
|
|
import static java.lang.Math.multiplyExact;
|
|
|
|
/**
|
|
* Parse files of the form:
|
|
*
|
|
* #define foo_width w
|
|
* #define foo_height h
|
|
* static char foo_bits[] = {
|
|
* 0xnn,0xnn,0xnn,0xnn,0xnn,0xnn,0xnn,0xnn,0xnn,0xnn,0xnn,0xnn,0xnn,0xnn,0xnn,
|
|
* 0xnn,0xnn,0xnn,0xnn,0xnn,0xnn,0xnn,0xnn,0xnn,0xnn,0xnn,0xnn,0xnn,0xnn,0xnn,
|
|
* 0xnn,0xnn,0xnn,0xnn};
|
|
*
|
|
* @author James Gosling
|
|
*/
|
|
public class XbmImageDecoder extends ImageDecoder {
|
|
private static byte[] XbmColormap = {(byte) 255, (byte) 255, (byte) 255,
|
|
0, 0, 0};
|
|
private static int XbmHints = (ImageConsumer.TOPDOWNLEFTRIGHT |
|
|
ImageConsumer.COMPLETESCANLINES |
|
|
ImageConsumer.SINGLEPASS |
|
|
ImageConsumer.SINGLEFRAME);
|
|
private static final int MAX_XBM_SIZE = 16384;
|
|
private static final int HEADER_SCAN_LIMIT = 100;
|
|
|
|
public XbmImageDecoder(InputStreamImageSource src, InputStream is) {
|
|
super(src, is);
|
|
if (!(input instanceof BufferedInputStream)) {
|
|
// If the topmost stream is a metered stream,
|
|
// we take forever to decode the image...
|
|
input = new BufferedInputStream(input, 80);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* An error has occurred. Throw an exception.
|
|
*/
|
|
private static void error(String s1) throws ImageFormatException {
|
|
throw new ImageFormatException(s1);
|
|
}
|
|
|
|
/**
|
|
* produce an image from the stream.
|
|
*/
|
|
public void produceImage() throws IOException, ImageFormatException {
|
|
int H = 0;
|
|
int W = 0;
|
|
int x = 0;
|
|
int y = 0;
|
|
int n = 0;
|
|
int state = 0;
|
|
byte[] raster = null;
|
|
IndexColorModel model = null;
|
|
|
|
String matchRegex = "(0[xX])?[0-9a-fA-F]+[\\s+]?[,|};]";
|
|
String replaceRegex = "(0[xX])|,|[\\s+]|[};]";
|
|
|
|
String line;
|
|
int lineNum = 0;
|
|
|
|
try (BufferedReader br = new BufferedReader(new InputStreamReader(input))) {
|
|
// loop to process XBM header - width, height and create raster
|
|
while (!aborted && (line = br.readLine()) != null
|
|
&& lineNum <= HEADER_SCAN_LIMIT) {
|
|
lineNum++;
|
|
// process #define stmts
|
|
if (line.trim().startsWith("#define")) {
|
|
String[] token = line.split("\\s+");
|
|
if (token.length != 3) {
|
|
error("Error while parsing define statement");
|
|
}
|
|
try {
|
|
if (!token[2].isBlank() && state == 0) {
|
|
W = Integer.parseInt(token[2]);
|
|
state = 1; // after width is set
|
|
} else if (!token[2].isBlank() && state == 1) {
|
|
H = Integer.parseInt(token[2]);
|
|
state = 2; // after height is set
|
|
}
|
|
} catch (NumberFormatException nfe) {
|
|
// parseInt() can throw NFE
|
|
error("Error while parsing width or height.");
|
|
}
|
|
}
|
|
|
|
if (state == 2) {
|
|
if (W <= 0 || H <= 0) {
|
|
error("Invalid values for width or height.");
|
|
}
|
|
if (multiplyExact(W, H) > MAX_XBM_SIZE) {
|
|
error("Large XBM file size."
|
|
+ " Maximum allowed size: " + MAX_XBM_SIZE);
|
|
}
|
|
model = new IndexColorModel(8, 2, XbmColormap,
|
|
0, false, 0);
|
|
setDimensions(W, H);
|
|
setColorModel(model);
|
|
setHints(XbmHints);
|
|
headerComplete();
|
|
raster = new byte[W];
|
|
state = 3;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (state != 3) {
|
|
error("Width or Height of XBM file not defined");
|
|
}
|
|
|
|
// loop to process image data
|
|
while (!aborted && (line = br.readLine()) != null) {
|
|
lineNum++;
|
|
|
|
if (line.contains("[]")) {
|
|
Matcher matcher = Pattern.compile(matchRegex).matcher(line);
|
|
while (matcher.find()) {
|
|
if (y >= H) {
|
|
error("Scan size of XBM file exceeds"
|
|
+ " the defined width x height");
|
|
}
|
|
|
|
int startIndex = matcher.start();
|
|
int endIndex = matcher.end();
|
|
String hexByte = line.substring(startIndex, endIndex);
|
|
|
|
if (!(hexByte.startsWith("0x")
|
|
|| hexByte.startsWith("0X"))) {
|
|
error("Invalid hexadecimal number at Ln#:" + lineNum
|
|
+ " Col#:" + (startIndex + 1));
|
|
}
|
|
hexByte = hexByte.replaceAll(replaceRegex, "");
|
|
if (hexByte.length() != 2) {
|
|
error("Invalid hexadecimal number at Ln#:" + lineNum
|
|
+ " Col#:" + (startIndex + 1));
|
|
}
|
|
|
|
try {
|
|
n = Integer.parseInt(hexByte, 16);
|
|
} catch (NumberFormatException nfe) {
|
|
error("Error parsing hexadecimal at Ln#:" + lineNum
|
|
+ " Col#:" + (startIndex + 1));
|
|
}
|
|
for (int mask = 1; mask <= 0x80; mask <<= 1) {
|
|
if (x < W) {
|
|
if ((n & mask) != 0)
|
|
raster[x] = 1;
|
|
else
|
|
raster[x] = 0;
|
|
}
|
|
x++;
|
|
}
|
|
|
|
if (x >= W) {
|
|
int result = setPixels(0, y, W, 1, model, raster, 0, W);
|
|
if (result <= 0) {
|
|
error("Unexpected error occurred during setPixel()");
|
|
}
|
|
x = 0;
|
|
y++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
imageComplete(ImageConsumer.STATICIMAGEDONE, true);
|
|
}
|
|
}
|
|
}
|