Make first real commit: copy of CaRMetal 4.2.8

This commit is contained in:
Glen Whitney 2018-09-04 22:51:42 -04:00
parent 002acfc88e
commit c312811084
1120 changed files with 226843 additions and 1 deletions

281
rene/util/FileList.java Normal file
View file

@ -0,0 +1,281 @@
/*
Copyright 2006 Rene Grothmann, modified by Eric Hakenholz
This file is part of C.a.R. software.
C.a.R. is a free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, version 3 of the License.
C.a.R. 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 for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package rene.util;
import java.io.File;
import java.util.Enumeration;
import java.util.StringTokenizer;
import java.util.Vector;
import rene.util.sort.SortObject;
import rene.util.sort.Sorter;
class SortFile extends File implements SortObject {
/**
*
*/
private static final long serialVersionUID = 1L;
String S;
static int SortBy = 0;
final public static int NAME = 0, DATE = 1;
public SortFile(final File dir, final String name) {
super(dir, name);
try {
S = getCanonicalPath().toUpperCase();
} catch (final Exception e) {
S = "";
}
}
public int compare(final SortObject o) {
final SortFile f = (SortFile) o;
if (SortBy == DATE) {
final long n = f.lastModified();
final long m = lastModified();
if (n < m)
return -1;
if (n > m)
return 1;
return 0;
}
return -f.S.compareTo(S);
}
}
class FileFilter {
char F[][];
public FileFilter(final String s) {
final StringTokenizer t = new StringTokenizer(s);
final int n = t.countTokens();
F = new char[n][];
for (int i = 0; i < n; i++) {
F[i] = t.nextToken().toCharArray();
}
}
public char[] filter(final int i) {
return F[i];
}
public int filterCount() {
return F.length;
}
}
/**
* This class parses a subtree for files that match a pattern. The pattern may
* contain one or more * and ? as usual. The class delivers an enumerator for
* the files, or may be subclassed to handle the files directly. The routines
* directory and file can be used to return, if more scanning is necessary.
*/
public class FileList {
Vector V = new Vector(), Vdir = new Vector();
boolean Stop;
boolean Recurse;
String Dir, Filter;
boolean UseCase = false;
public FileList(final String dir, final String filter, final boolean recurse) {
Stop = false;
Recurse = recurse;
Dir = dir;
Filter = filter;
if (Dir.equals("-")) {
Dir = ".";
Recurse = false;
} else if (Dir.startsWith("-")) {
Dir = Dir.substring(1);
Recurse = false;
}
}
public FileList(final String dir, final String filter) {
this(dir, filter, true);
}
public FileList(final String dir) {
this(dir, "*", true);
}
public void setCase(final boolean usecase) {
UseCase = usecase;
}
public void search() {
Stop = false;
final File file = new File(Dir);
if (!UseCase)
Filter = Filter.toLowerCase();
if (file.isDirectory())
find(file, new FileFilter(Filter));
}
void find(final File dir, final FileFilter filter) {
if (!directory(dir))
return;
final String list[] = dir.list();
loop: for (int i = 0; i < list.length; i++) {
final SortFile file = new SortFile(dir, list[i]);
if (file.isDirectory()) {
Vdir.addElement(file);
if (Recurse)
find(file, filter);
} else {
String filename = file.getName();
if (!UseCase)
filename = filename.toLowerCase();
final char fn[] = filename.toCharArray();
for (int j = 0; j < filter.filterCount(); j++) {
if (match(fn, 0, filter.filter(j), 0)) {
Stop = !file(file);
if (Stop)
break loop;
V.addElement(file);
}
}
}
if (Stop)
break;
}
parsed(dir);
}
boolean match(final char filename[], final int n, final char filter[],
final int m) {
if (filter == null)
return true;
if (m >= filter.length)
return n >= filename.length;
if (n >= filename.length)
return m == filter.length - 1 && filter[m] == '*';
if (filter[m] == '?') {
return match(filename, n + 1, filter, m + 1);
}
if (filter[m] == '*') {
if (m == filter.length - 1)
return true;
for (int i = n; i < filename.length; i++) {
if (match(filename, i, filter, m + 1))
return true;
}
return false;
}
if (filter[m] == filename[n])
return match(filename, n + 1, filter, m + 1);
return false;
}
/**
* Return an Enumeration with the files.
*/
public Enumeration files() {
return V.elements();
}
/**
* Return an Enumeration with the directories.
*/
public Enumeration dirs() {
return Vdir.elements();
}
/**
* @return The number of files found.
*/
public int size() {
return V.size();
}
/**
* Sort the result.
*/
public void sort() {
int i, n = V.size();
SortObject v[] = new SortObject[n];
for (i = 0; i < n; i++)
v[i] = (SortFile) V.elementAt(i);
Sorter.sort(v);
for (i = 0; i < n; i++)
V.setElementAt(v[i], i);
n = Vdir.size();
v = new SortObject[n];
for (i = 0; i < n; i++)
v[i] = (SortFile) Vdir.elementAt(i);
Sorter.sort(v);
for (i = 0; i < n; i++)
Vdir.setElementAt(v[i], i);
}
public void sort(final int type) {
SortFile.SortBy = type;
sort();
SortFile.SortBy = SortFile.NAME;
}
/**
* @param file
* The directory that has been found.
* @return false if recursion should stop here. (i.e. that directory needs
* not be parsed).
*/
protected boolean directory(final File dir) {
return true;
}
/**
* @param file
* The file that has been found.
* @return false if you need no more file at all.
*/
protected boolean file(final File file) {
return true;
}
/**
* @param parsed
* The directory that has been parsed.
*/
protected void parsed(final File dir) {
}
/**
* This stops the search from other threads.
*/
public void stopIt() {
Stop = true;
}
/**
* Returns a canonical version of the directory
*/
public String getDir() {
final File dir = new File(Dir);
try {
return (dir.getCanonicalPath());
} catch (final Exception e) {
return "Dir does not exist!";
}
}
}

206
rene/util/FileName.java Normal file
View file

@ -0,0 +1,206 @@
/*
Copyright 2006 Rene Grothmann, modified by Eric Hakenholz
This file is part of C.a.R. software.
C.a.R. is a free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, version 3 of the License.
C.a.R. 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 for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package rene.util;
import java.io.File;
/**
* This is a static class to determine extensions etc. from a file name.
*/
public class FileName {
static public int ChopLength = 48;
static public String purefilename(final String filename) {
final char a[] = filename.toCharArray();
int i = a.length - 1;
final char fs = File.separatorChar;
while (i >= 0) {
if (a[i] == fs || a[i] == '/' || i == 0) {
if (i == 0)
i = -1;
if (i < a.length - 1) {
int j = a.length - 1;
while (j > i && a[j] != '.')
j--;
if (j > i + 1)
return new String(a, i + 1, j - i - 1);
else
return "";
} else
return "";
}
i--;
}
return filename;
}
static public String path(final String filename) {
final char a[] = filename.toCharArray();
int i = a.length - 1;
final char fs = File.separatorChar;
while (i > 0) {
if (a[i] == fs || a[i] == '/') {
return new String(a, 0, i);
}
i--;
}
return "";
}
static public String pathAndSeparator(final String filename) {
final char a[] = filename.toCharArray();
int i = a.length - 1;
final char fs = File.separatorChar;
while (i > 0) {
if (a[i] == fs || a[i] == '/') {
return new String(a, 0, i + 1);
}
i--;
}
return "";
}
static public String filename(final String filename) {
final char a[] = filename.toCharArray();
int i = a.length - 1;
final char fs = File.separatorChar;
while (i > 0) {
if (a[i] == fs || a[i] == '/') {
if (i + 1 < a.length)
return new String(a, i + 1, a.length - i - 1);
else
return "";
}
i--;
}
return filename;
}
static public String extension(final String filename) {
final char a[] = filename.toCharArray();
int i = a.length - 1;
final char fs = File.separatorChar;
while (i > 0) {
if (a[i] == '.') {
if (i + 1 < a.length)
return new String(a, i + 1, a.length - i - 1);
else
return "";
}
if (a[i] == fs || a[i] == '/')
break;
i--;
}
return "";
}
static public String chop(String filename, final int chop)
// chop the filename to 32 characters
{
if (filename.length() > chop) {
filename = "... " + filename.substring(filename.length() - chop);
}
return filename;
}
static public String chop(final String filename) {
return chop(filename, ChopLength);
}
static public String chop(final int start, String filename, final int chop)
// chop the filename.substring(start) to 32 characters
{
if (filename.length() > start + chop) {
filename = filename.substring(0, start) + " ... "
+ filename.substring(filename.length() - chop);
}
return filename;
}
static public String chop(final int start, final String filename) {
return chop(start, filename, ChopLength);
}
static public String relative(String dir, final String filename) {
dir = dir + System.getProperty("file.separator");
if (filename.startsWith(dir)) {
return filename.substring(dir.length());
} else
return filename;
}
static public String canonical(final String filename) {
final File f = new File(filename);
try {
String s = f.getCanonicalPath();
if (s.length() > 2 && s.charAt(1) == ':')
s = s.substring(0, 2).toLowerCase() + s.substring(2);
return s;
} catch (final Exception e) {
return f.getAbsolutePath();
}
}
static public String toURL(final String filename) {
final int n = filename.indexOf(' ');
if (n >= 0)
return filename.substring(0, n) + "%20"
+ toURL(filename.substring(n + 1));
else
return filename;
}
static boolean match(final char filename[], final int n,
final char filter[], final int m) {
if (filter == null)
return true;
if (m >= filter.length)
return n >= filename.length;
if (n >= filename.length)
return m == filter.length - 1 && filter[m] == '*';
if (filter[m] == '?') {
return match(filename, n + 1, filter, m + 1);
}
if (filter[m] == '*') {
if (m == filter.length - 1)
return true;
for (int i = n; i < filename.length; i++) {
if (match(filename, i, filter, m + 1))
return true;
}
return false;
}
if (filter[m] == filename[n])
return match(filename, n + 1, filter, m + 1);
return false;
}
public static boolean match(final String filename, final String filter) {
final char fn[] = filename.toCharArray(), f[] = filter.toCharArray();
return match(fn, 0, f, 0);
}
public static void main(final String args[]) {
System.out.println("-" + toURL(" test test test ") + "-");
}
}

View file

@ -0,0 +1,61 @@
/*
Copyright 2006 Rene Grothmann, modified by Eric Hakenholz
This file is part of C.a.R. software.
C.a.R. is a free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, version 3 of the License.
C.a.R. 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 for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package rene.util;
import java.awt.Image;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;
/**
* @author unknown Class to hold an image for the clipboad, implements the
* Transferable class properly.
*/
public class ImageSelection implements Transferable {
// the Image object which will be housed by the ImageSelection
private final Image image;
public ImageSelection(final Image image) {
this.image = image;
}
// Returns the supported flavors of our implementation
public DataFlavor[] getTransferDataFlavors() {
return new DataFlavor[] { DataFlavor.imageFlavor };
}
// Returns true if flavor is supported
public boolean isDataFlavorSupported(final DataFlavor flavor) {
return DataFlavor.imageFlavor.equals(flavor);
}
// Returns Image object housed by Transferable object
public Object getTransferData(final DataFlavor flavor)
throws UnsupportedFlavorException, IOException {
if (!DataFlavor.imageFlavor.equals(flavor)) {
throw new UnsupportedFlavorException(flavor);
}
// else return the payload
return image;
}
}

325
rene/util/MyVector.java Normal file
View file

@ -0,0 +1,325 @@
/*
Copyright 2006 Rene Grothmann, modified by Eric Hakenholz
This file is part of C.a.R. software.
C.a.R. is a free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, version 3 of the License.
C.a.R. 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 for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package rene.util;
import java.util.Enumeration;
/**
* This is a more effective replacement of the Vector class. It is based on a
* growing array. If an object is removed, it is replaced by null. The class
* knows about the first null object (the gap). Searching for elements or other
* operations automatically compress the array by copying the elements upwards,
* but only as far as they need to go anyway.
*
* Accessing an element is very effective, at least the second time. If you want
* to make sure, it is always effective, compress first. The most effective way
* is to get the object array itself.
*
* The objects can be enumerated. The object returned by nextElement() is found
* very rapidly. E.g. it can be deleted at once.
*
* Enumeration is not reentrant. Do it only once each time.
*
* Nothing in this class is synchronized!
**/
public class MyVector implements Enumeration {
Object O[];
int OSize, ON, OLast, Gap;
int EN = 0;
public MyVector(final int initsize) {
O = new Object[initsize];
OSize = initsize;
OLast = ON = 0;
Gap = -1;
}
public MyVector() {
this(8);
}
/**
* Add an element. Extend the array, if necessary.
*/
public void addElement(final Object o) {
if (OLast >= OSize)
extend();
O[OLast++] = o;
ON++;
}
/**
* Extend the array, or get space by compressing it.
*/
public void extend() {
if (ON < OLast / 2) {
compress();
return;
}
final Object o[] = new Object[2 * OSize];
System.arraycopy(O, 0, o, 0, OLast);
OSize *= 2;
O = o;
}
/**
* Compress the array.
*/
public void compress() {
if (Gap < 0)
return;
int k = Gap;
for (int i = Gap; i < OLast; i++) {
if (O[i] == null)
continue;
O[k++] = O[i];
}
ON = k;
for (int i = k; i < OLast; i++)
O[i] = null;
Gap = -1;
OLast = ON;
}
/**
* Get an enumeration of this array.
*/
public Enumeration elements() {
compress();
EN = 0;
return this;
}
/**
* Method for Enumeration.
*/
public boolean hasMoreElements() {
while (EN < OLast && O[EN] == null)
EN++;
return EN < OLast;
}
/**
* Method for Enumeration.
*/
public Object nextElement() {
if (!hasMoreElements())
throw new ArrayIndexOutOfBoundsException(OLast);
return O[EN++];
}
/**
* Clear this array, but keep its memory!
*/
public void removeAllElements() {
for (int i = 0; i < OLast; i++)
O[i] = null;
ON = OLast = 0;
Gap = -1;
}
/**
* Remove a single element. This will also compress the part below the
* element, or all, if it is not found.
*/
public void removeElement(final Object o) {
final int i = indexOf(o);
if (i < 0)
return;
O[i] = null;
ON--;
if (Gap < 0 || Gap > i)
Gap = i;
if (i == OLast - 1)
OLast--;
while (OLast > 0 && O[OLast - 1] == null)
OLast--;
if (Gap >= OLast)
Gap = -1;
}
/**
* Find an element. Compress on the way. Check for the last element,
* returned by nextElement() first. Equality is checked with the equal()
* function.
*
* @return -1, if not found.
*/
public int indexOf(final Object o) {
if (EN > 0 && EN <= OLast && O[EN - 1].equals(o))
return EN - 1;
if (Gap < 0) {
for (int i = 0; i < OLast; i++) {
if (O[i].equals(o))
return i;
}
return -1;
}
for (int i = 0; i < Gap; i++) {
if (O[i].equals(o))
return i;
}
int k = Gap;
for (int i = Gap; i < OLast; i++) {
if (O[i] == null)
continue;
if (O[i].equals(o)) {
Gap = k;
return i;
}
O[k++] = O[i];
O[i] = null;
}
ON = k;
for (int i = k; i < OLast; i++)
O[i] = null;
Gap = -1;
OLast = ON;
return -1;
}
/**
* @return the number of objects in the vector.
*/
public int size() {
return ON;
}
/**
* Get the element at a given position. Second access will always be
* effective. First access compresses. Throws an exception, if the index is
* invalid.
*/
public Object elementAt(final int n) {
if (n < 0 || n >= ON)
throw new ArrayIndexOutOfBoundsException(n);
if (Gap < 0 || n < Gap)
return O[n];
int k = Gap;
for (int i = Gap; i < OLast; i++) {
if (O[i] == null)
continue;
O[k] = O[i];
O[i] = null;
if (k == n) {
final Object ret = O[k];
k++;
Gap = k;
if (Gap >= ON) {
for (int j = Gap; j < OLast; j++)
O[j] = null;
OLast = ON;
Gap = -1;
}
return ret;
}
k++;
}
// never happens
throw new ArrayIndexOutOfBoundsException(n);
}
/**
* Get the array itself (compressed). Make sure, you also use size() to
* determine the true length of the array. Do not change objects beyond the
* size! Do not set objects to null!
*/
public Object[] getArray() {
compress();
return O;
}
/**
* Copy the array into an object array of at least the same size.
*/
public void copyInto(final Object o[]) {
compress();
System.arraycopy(O, 0, o, 0, ON);
}
/**
* Test for equality with another vector, using equals.
*/
public boolean equals(final MyVector V) {
if (V.ON != ON)
return false;
V.compress();
compress();
for (int i = 0; i < ON; i++) {
if (!V.O[i].equals(O[i]))
return false;
}
return true;
}
/**
* Test for equality with another vector, using object equality.
*/
public boolean equalsIdentical(final MyVector V) {
if (V.ON != ON)
return false;
V.compress();
compress();
for (int i = 0; i < ON; i++) {
if (V.O[i] != O[i])
return false;
}
return true;
}
/**
* Trancate the vector to n elements, if it has more.
*/
public void truncate(final int n) {
if (n >= ON)
return;
compress();
for (int i = n; i < OLast; i++)
O[i] = null;
OLast = ON = n;
}
public static void main(final String args[]) {
final MyVector V = new MyVector();
for (int i = 1; i <= 10; i++)
V.addElement("Element " + i);
for (int i = 4; i <= 9; i++)
V.removeElement("Element " + i);
System.out.println("--> " + V.elementAt(3));
System.out.println(V.ON + " elements, " + V.OLast + " used, " + V.Gap
+ " gap.");
System.out.println("--> " + V.elementAt(3));
System.out.println(V.ON + " elements, " + V.OLast + " used, " + V.Gap
+ " gap.");
for (int i = 11; i <= 20; i++)
V.addElement("Element " + i);
System.out.println(V.ON + " elements, " + V.OLast + " used ," + V.Gap
+ " gap.");
final Enumeration E = V.elements();
while (E.hasMoreElements()) {
System.out.println((String) E.nextElement());
}
System.out.println(V.ON + " elements, " + V.OLast + " used, " + V.Gap
+ " gap.");
}
}

647
rene/util/PngEncoder.java Normal file
View file

@ -0,0 +1,647 @@
/*
Copyright 2006 Rene Grothmann, modified by Eric Hakenholz
This file is part of C.a.R. software.
C.a.R. is a free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, version 3 of the License.
C.a.R. 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 for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package rene.util;
/**
* PngEncoder takes a Java Image object and creates a byte string which can be saved as a PNG file.
* The Image is presumed to use the DirectColorModel.
*
* Thanks to Jay Denny at KeyPoint Software
* http://www.keypoint.com/
* who let me develop this code on company time.
*
* You may contact me with (probably very-much-needed) improvements,
* comments, and bug fixes at:
*
* david@catcode.com
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* A copy of the GNU LGPL may be found at
* http://www.gnu.org/copyleft/lesser.html,
*
* @author J. David Eisenberg
* @version 1.4, 31 March 2000
*/
import java.awt.Image;
import java.awt.image.ImageObserver;
import java.awt.image.PixelGrabber;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.zip.CRC32;
import java.util.zip.Deflater;
import java.util.zip.DeflaterOutputStream;
public class PngEncoder extends Object {
/** Constant specifying that alpha channel should be encoded. */
public static final boolean ENCODE_ALPHA = true;
/** Constant specifying that alpha channel should not be encoded. */
public static final boolean NO_ALPHA = false;
/** Constants for filters */
public static final int FILTER_NONE = 0;
public static final int FILTER_SUB = 1;
public static final int FILTER_UP = 2;
public static final int FILTER_LAST = 2;
protected byte[] pngBytes;
protected byte[] priorRow;
protected byte[] leftBytes;
protected Image image;
protected int width, height;
protected int bytePos, maxPos;
protected int hdrPos, dataPos, endPos;
protected CRC32 crc = new CRC32();
protected long crcValue;
protected boolean encodeAlpha;
protected int filter;
protected int bytesPerPixel;
protected int compressionLevel;
protected double DPI = 300;
/**
* Class constructor
*
*/
public PngEncoder() {
this(null, false, FILTER_NONE, 0);
}
/**
* Class constructor specifying Image to encode, with no alpha channel
* encoding.
*
* @param image
* A Java Image object which uses the DirectColorModel
* @see java.awt.Image
*/
public PngEncoder(final Image image) {
this(image, false, FILTER_NONE, 0);
}
/**
* Class constructor specifying Image to encode, and whether to encode
* alpha.
*
* @param image
* A Java Image object which uses the DirectColorModel
* @param encodeAlpha
* Encode the alpha channel? false=no; true=yes
* @see java.awt.Image
*/
public PngEncoder(final Image image, final boolean encodeAlpha) {
this(image, encodeAlpha, FILTER_NONE, 0);
}
/**
* Class constructor specifying Image to encode, whether to encode alpha,
* and filter to use.
*
* @param image
* A Java Image object which uses the DirectColorModel
* @param encodeAlpha
* Encode the alpha channel? false=no; true=yes
* @param whichFilter
* 0=none, 1=sub, 2=up
* @see java.awt.Image
*/
public PngEncoder(final Image image, final boolean encodeAlpha,
final int whichFilter) {
this(image, encodeAlpha, whichFilter, 0);
}
/**
* Class constructor specifying Image source to encode, whether to encode
* alpha, filter to use, and compression level.
*
* @param image
* A Java Image object
* @param encodeAlpha
* Encode the alpha channel? false=no; true=yes
* @param whichFilter
* 0=none, 1=sub, 2=up
* @param compLevel
* 0..9
* @see java.awt.Image
*/
public PngEncoder(final Image image, final boolean encodeAlpha,
final int whichFilter, final int compLevel) {
this.image = image;
this.encodeAlpha = encodeAlpha;
setFilter(whichFilter);
if (compLevel >= 0 && compLevel <= 9) {
this.compressionLevel = compLevel;
}
}
/**
* Set the image to be encoded
*
* @param image
* A Java Image object which uses the DirectColorModel
* @see java.awt.Image
* @see java.awt.image.DirectColorModel
*/
public void setImage(final Image image) {
this.image = image;
pngBytes = null;
}
public void setDPI(final double dpi) {
DPI = dpi;
}
/**
* Creates an array of bytes that is the PNG equivalent of the current
* image, specifying whether to encode alpha or not.
*
* @param encodeAlpha
* boolean false=no alpha, true=encode alpha
* @return an array of bytes, or null if there was a problem
*/
public byte[] pngEncode(final boolean encodeAlpha) {
final byte[] pngIdBytes = { -119, 80, 78, 71, 13, 10, 26, 10 };
if (image == null) {
return null;
}
width = image.getWidth(null);
height = image.getHeight(null);
/*
* start with an array that is big enough to hold all the pixels (plus
* filter bytes), and an extra 200 bytes for header info
*/
pngBytes = new byte[((width + 1) * height * 3) + 200];
/*
* keep track of largest byte written to the array
*/
maxPos = 0;
bytePos = writeBytes(pngIdBytes, 0);
hdrPos = bytePos;
writeHeader();
writePhys();
dataPos = bytePos;
if (writeImageData()) {
writeEnd();
pngBytes = resizeByteArray(pngBytes, maxPos);
} else {
pngBytes = null;
}
return pngBytes;
}
/**
* Creates an array of bytes that is the PNG equivalent of the current
* image. Alpha encoding is determined by its setting in the constructor.
*
* @return an array of bytes, or null if there was a problem
*/
public byte[] pngEncode() {
return pngEncode(encodeAlpha);
}
/**
* Set the alpha encoding on or off.
*
* @param encodeAlpha
* false=no, true=yes
*/
public void setEncodeAlpha(final boolean encodeAlpha) {
this.encodeAlpha = encodeAlpha;
}
/**
* Retrieve alpha encoding status.
*
* @return boolean false=no, true=yes
*/
public boolean getEncodeAlpha() {
return encodeAlpha;
}
/**
* Set the filter to use
*
* @param whichFilter
* from constant list
*/
public void setFilter(final int whichFilter) {
this.filter = FILTER_NONE;
if (whichFilter <= FILTER_LAST) {
this.filter = whichFilter;
}
}
/**
* Retrieve filtering scheme
*
* @return int (see constant list)
*/
public int getFilter() {
return filter;
}
/**
* Set the compression level to use
*
* @param level
* 0 through 9
*/
public void setCompressionLevel(final int level) {
if (level >= 0 && level <= 9) {
this.compressionLevel = level;
}
}
/**
* Retrieve compression level
*
* @return int in range 0-9
*/
public int getCompressionLevel() {
return compressionLevel;
}
/**
* Increase or decrease the length of a byte array.
*
* @param array
* The original array.
* @param newLength
* The length you wish the new array to have.
* @return Array of newly desired length. If shorter than the original, the
* trailing elements are truncated.
*/
protected byte[] resizeByteArray(final byte[] array, final int newLength) {
final byte[] newArray = new byte[newLength];
final int oldLength = array.length;
System.arraycopy(array, 0, newArray, 0, Math.min(oldLength, newLength));
return newArray;
}
/**
* Write an array of bytes into the pngBytes array. Note: This routine has
* the side effect of updating maxPos, the largest element written in the
* array. The array is resized by 1000 bytes or the length of the data to be
* written, whichever is larger.
*
* @param data
* The data to be written into pngBytes.
* @param offset
* The starting point to write to.
* @return The next place to be written to in the pngBytes array.
*/
protected int writeBytes(final byte[] data, final int offset) {
maxPos = Math.max(maxPos, offset + data.length);
if (data.length + offset > pngBytes.length) {
pngBytes = resizeByteArray(pngBytes, pngBytes.length
+ Math.max(1000, data.length));
}
System.arraycopy(data, 0, pngBytes, offset, data.length);
return offset + data.length;
}
/**
* Write an array of bytes into the pngBytes array, specifying number of
* bytes to write. Note: This routine has the side effect of updating
* maxPos, the largest element written in the array. The array is resized by
* 1000 bytes or the length of the data to be written, whichever is larger.
*
* @param data
* The data to be written into pngBytes.
* @param nBytes
* The number of bytes to be written.
* @param offset
* The starting point to write to.
* @return The next place to be written to in the pngBytes array.
*/
protected int writeBytes(final byte[] data, final int nBytes,
final int offset) {
maxPos = Math.max(maxPos, offset + nBytes);
if (nBytes + offset > pngBytes.length) {
pngBytes = resizeByteArray(pngBytes, pngBytes.length
+ Math.max(1000, nBytes));
}
System.arraycopy(data, 0, pngBytes, offset, nBytes);
return offset + nBytes;
}
/**
* Write a two-byte integer into the pngBytes array at a given position.
*
* @param n
* The integer to be written into pngBytes.
* @param offset
* The starting point to write to.
* @return The next place to be written to in the pngBytes array.
*/
protected int writeInt2(final int n, final int offset) {
final byte[] temp = { (byte) ((n >> 8) & 0xff), (byte) (n & 0xff) };
return writeBytes(temp, offset);
}
/**
* Write a four-byte integer into the pngBytes array at a given position.
*
* @param n
* The integer to be written into pngBytes.
* @param offset
* The starting point to write to.
* @return The next place to be written to in the pngBytes array.
*/
protected int writeInt4(final int n, final int offset) {
final byte[] temp = { (byte) ((n >> 24) & 0xff),
(byte) ((n >> 16) & 0xff), (byte) ((n >> 8) & 0xff),
(byte) (n & 0xff) };
return writeBytes(temp, offset);
}
/**
* Write a single byte into the pngBytes array at a given position.
*
* @param n
* The integer to be written into pngBytes.
* @param offset
* The starting point to write to.
* @return The next place to be written to in the pngBytes array.
*/
protected int writeByte(final int b, final int offset) {
final byte[] temp = { (byte) b };
return writeBytes(temp, offset);
}
/**
* Write a string into the pngBytes array at a given position. This uses the
* getBytes method, so the encoding used will be its default.
*
* @param n
* The integer to be written into pngBytes.
* @param offset
* The starting point to write to.
* @return The next place to be written to in the pngBytes array.
* @see java.lang.String#getBytes()
*/
protected int writeString(final String s, final int offset) {
return writeBytes(s.getBytes(), offset);
}
/**
* Write a PNG "IHDR" chunk into the pngBytes array.
*/
protected void writeHeader() {
int startPos;
startPos = bytePos = writeInt4(13, bytePos);
bytePos = writeString("IHDR", bytePos);
width = image.getWidth(null);
height = image.getHeight(null);
bytePos = writeInt4(width, bytePos);
bytePos = writeInt4(height, bytePos);
bytePos = writeByte(8, bytePos); // bit depth
bytePos = writeByte((encodeAlpha) ? 6 : 2, bytePos); // direct model
bytePos = writeByte(0, bytePos); // compression method
bytePos = writeByte(0, bytePos); // filter method
bytePos = writeByte(0, bytePos); // no interlace
crc.reset();
crc.update(pngBytes, startPos, bytePos - startPos);
crcValue = crc.getValue();
bytePos = writeInt4((int) crcValue, bytePos);
}
/**
* Write a PNG "pHYs" chunk into the pngBytes array.
*/
protected void writePhys() {
int startPos;
startPos = bytePos = writeInt4(9, bytePos);
bytePos = writeString("pHYs", bytePos);
final int dots = (int) (DPI * 39.37);
bytePos = writeInt4(dots, bytePos);
bytePos = writeInt4(dots, bytePos);
bytePos = writeByte(1, bytePos); // bit depth
crc.reset();
crc.update(pngBytes, startPos, bytePos - startPos);
crcValue = crc.getValue();
bytePos = writeInt4((int) crcValue, bytePos);
}
/**
* Perform "sub" filtering on the given row. Uses temporary array leftBytes
* to store the original values of the previous pixels. The array is 16
* bytes long, which will easily hold two-byte samples plus two-byte alpha.
*
* @param pixels
* The array holding the scan lines being built
* @param startPos
* Starting position within pixels of bytes to be filtered.
* @param width
* Width of a scanline in pixels.
*/
protected void filterSub(final byte[] pixels, final int startPos,
final int width) {
int i;
final int offset = bytesPerPixel;
final int actualStart = startPos + offset;
final int nBytes = width * bytesPerPixel;
int leftInsert = offset;
int leftExtract = 0;
for (i = actualStart; i < startPos + nBytes; i++) {
leftBytes[leftInsert] = pixels[i];
pixels[i] = (byte) ((pixels[i] - leftBytes[leftExtract]) % 256);
leftInsert = (leftInsert + 1) % 0x0f;
leftExtract = (leftExtract + 1) % 0x0f;
}
}
/**
* Perform "up" filtering on the given row. Side effect: refills the prior
* row with current row
*
* @param pixels
* The array holding the scan lines being built
* @param startPos
* Starting position within pixels of bytes to be filtered.
* @param width
* Width of a scanline in pixels.
*/
protected void filterUp(final byte[] pixels, final int startPos,
final int width) {
int i, nBytes;
byte current_byte;
nBytes = width * bytesPerPixel;
for (i = 0; i < nBytes; i++) {
current_byte = pixels[startPos + i];
pixels[startPos + i] = (byte) ((pixels[startPos + i] - priorRow[i]) % 256);
priorRow[i] = current_byte;
}
}
/**
* Write the image data into the pngBytes array. This will write one or more
* PNG "IDAT" chunks. In order to conserve memory, this method grabs as many
* rows as will fit into 32K bytes, or the whole image; whichever is less.
*
*
* @return true if no errors; false if error grabbing pixels
*/
protected boolean writeImageData() {
int rowsLeft = height; // number of rows remaining to write
int startRow = 0; // starting row to process this time through
int nRows; // how many rows to grab at a time
byte[] scanLines; // the scan lines to be compressed
int scanPos; // where we are in the scan lines
int startPos; // where this line's actual pixels start (used for
// filtering)
byte[] compressedLines; // the resultant compressed lines
int nCompressed; // how big is the compressed area?
PixelGrabber pg;
bytesPerPixel = (encodeAlpha) ? 4 : 3;
final Deflater scrunch = new Deflater(compressionLevel);
final ByteArrayOutputStream outBytes = new ByteArrayOutputStream(1024);
final DeflaterOutputStream compBytes = new DeflaterOutputStream(
outBytes, scrunch);
try {
nRows = (64 * 32768 - 1) / (width * (bytesPerPixel + 1));
final int[] pixels = new int[width * nRows];
while (rowsLeft > 0) {
if (nRows >= rowsLeft)
nRows = rowsLeft;
pg = new PixelGrabber(image, 0, startRow, width, nRows, pixels,
0, width);
try {
pg.grabPixels();
} catch (final Exception e) {
System.err.println("interrupted waiting for pixels!");
return false;
}
if ((pg.getStatus() & ImageObserver.ABORT) != 0) {
System.err.println("image fetch aborted or errored");
return false;
}
/*
* Create a data chunk. scanLines adds "nRows" for the filter
* bytes.
*/
scanLines = new byte[width * nRows * bytesPerPixel + nRows];
if (filter == FILTER_SUB) {
leftBytes = new byte[16];
}
if (filter == FILTER_UP) {
priorRow = new byte[width * bytesPerPixel];
}
scanPos = 0;
startPos = 1;
for (int i = 0; i < width * nRows; i++) {
if (i % width == 0) {
scanLines[scanPos++] = (byte) filter;
startPos = scanPos;
}
scanLines[scanPos++] = (byte) ((pixels[i] >> 16) & 0xff);
scanLines[scanPos++] = (byte) ((pixels[i] >> 8) & 0xff);
scanLines[scanPos++] = (byte) ((pixels[i]) & 0xff);
if (encodeAlpha) {
scanLines[scanPos++] = (byte) ((pixels[i] >> 24) & 0xff);
}
if ((i % width == width - 1) && (filter != FILTER_NONE)) {
if (filter == FILTER_SUB) {
filterSub(scanLines, startPos, width);
}
if (filter == FILTER_UP) {
filterUp(scanLines, startPos, width);
}
}
}
/*
* Write these lines to the output area
*/
compBytes.write(scanLines, 0, scanPos);
startRow += nRows;
rowsLeft -= nRows;
}
compBytes.close();
/*
* Write the compressed bytes
*/
compressedLines = outBytes.toByteArray();
nCompressed = compressedLines.length;
crc.reset();
bytePos = writeInt4(nCompressed, bytePos);
bytePos = writeString("IDAT", bytePos);
crc.update("IDAT".getBytes());
bytePos = writeBytes(compressedLines, nCompressed, bytePos);
crc.update(compressedLines, 0, nCompressed);
crcValue = crc.getValue();
bytePos = writeInt4((int) crcValue, bytePos);
scrunch.finish();
return true;
} catch (final IOException e) {
System.err.println(e.toString());
return false;
}
}
/**
* Write a PNG "IEND" chunk into the pngBytes array.
*/
protected void writeEnd() {
bytePos = writeInt4(0, bytePos);
bytePos = writeString("IEND", bytePos);
crc.reset();
crc.update("IEND".getBytes());
crcValue = crc.getValue();
bytePos = writeInt4((int) crcValue, bytePos);
}
}

View file

@ -0,0 +1,71 @@
/*
Copyright 2006 Rene Grothmann, modified by Eric Hakenholz
This file is part of C.a.R. software.
C.a.R. is a free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, version 3 of the License.
C.a.R. 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 for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package rene.util;
public class SimpleByteBuffer {
private int Size, N;
private byte Buf[];
public SimpleByteBuffer(final int size) {
Size = size;
Buf = new byte[size];
N = 0;
}
public SimpleByteBuffer(final byte b[]) {
Size = b.length;
Buf = b;
N = 0;
}
public void append(final byte c) {
if (N < Size)
Buf[N++] = c;
else {
Size = 2 * Size;
final byte NewBuf[] = new byte[Size];
for (int i = 0; i < N; i++)
NewBuf[i] = Buf[i];
Buf = NewBuf;
Buf[N++] = c;
}
}
public void clear() {
N = 0;
}
public byte[] getBuffer() {
return Buf;
}
public byte[] getByteArray() {
final byte b[] = new byte[N];
for (int i = 0; i < N; i++)
b[i] = Buf[i];
return b;
}
public int size() {
return N;
}
}

View file

@ -0,0 +1,69 @@
/*
Copyright 2006 Rene Grothmann, modified by Eric Hakenholz
This file is part of C.a.R. software.
C.a.R. is a free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, version 3 of the License.
C.a.R. 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 for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package rene.util;
public class SimpleStringBuffer {
private int Size, N;
private char Buf[];
public SimpleStringBuffer(final int size) {
Size = size;
Buf = new char[size];
N = 0;
}
public SimpleStringBuffer(final char b[]) {
Size = b.length;
Buf = b;
N = 0;
}
public void append(final char c) {
if (N < Size)
Buf[N++] = c;
else {
Size = 2 * Size;
final char NewBuf[] = new char[Size];
for (int i = 0; i < N; i++)
NewBuf[i] = Buf[i];
Buf = NewBuf;
Buf[N++] = c;
}
}
public void append(final String s) {
final int n = s.length();
for (int i = 0; i < n; i++)
append(s.charAt(i));
}
public void clear() {
N = 0;
}
@Override
public String toString() {
if (N == 0)
return "";
return new String(Buf, 0, N);
}
}

302
rene/util/TestEncoder.java Normal file
View file

@ -0,0 +1,302 @@
/*
Copyright 2006 Rene Grothmann, modified by Eric Hakenholz
This file is part of C.a.R. software.
C.a.R. is a free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, version 3 of the License.
C.a.R. 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 for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package rene.util;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.image.ImageObserver;
import java.awt.image.MemoryImageSource;
import java.awt.image.PixelGrabber;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Calendar;
/**
* TestEncoder creates a PNG file that shows an analog clock displaying the
* current time of day, optionally with an alpha channel, and with the specified
* filter.
*
* The file name is in the format:
*
* clockHHMM_fNC alphaclockDHHMM_fNC
*
* HH = hours (24-hour clock), MM = minutes,
*
* N = filter level (0, 1, or 2) C = compression level (0 to 9)
*
* "alpha" is prefixed to the name if alpha encoding was used.
*
* This test program was written in a burning hurry, so it is not a model of
* efficient, or even good, code. Comments and bug fixes should be directed to:
*
* david@catcode.com
*
* @author J. David Eisenberg
* @version 1.3, 6 April 2000
*/
public class TestEncoder extends Frame {
/**
*
*/
private static final long serialVersionUID = 1L;
String message;
String timeStr;
Image clockImage = null;
int hour, minute;
boolean encodeAlpha;
int filter;
int compressionLevel;
int pixelDepth;
String filename;
boolean fileSaved = false;
public TestEncoder(final String s) {
super(s);
setSize(200, 200);
}
public void drawClockImage(int hour, final int minute) {
// variables used for drawing hands of clock
Graphics g;
final Font smallFont = new Font("Helvetica", Font.PLAIN, 9);
FontMetrics fm;
int x0, y0, x1, y1;
double angle;
g = clockImage.getGraphics();
g.setFont(smallFont);
fm = g.getFontMetrics();
// draw the clock face; yellow for AM, blue for PM
if (hour < 12) {
g.setColor(new Color(255, 255, 192));
} else {
g.setColor(new Color(192, 192, 255));
}
g.fillOval(10, 10, 80, 80);
g.setColor(Color.black);
g.drawOval(10, 10, 80, 80);
g.drawOval(48, 48, 4, 4);
/* draw the 12 / 3 / 6/ 9 numerals */
g.setFont(smallFont);
g.drawString("12", 50 - fm.stringWidth("12") / 2, 11 + fm.getAscent());
g.drawString("3", 88 - fm.stringWidth("3"), 50 + fm.getAscent() / 2);
g.drawString("6", 50 - fm.stringWidth("6") / 2, 88);
g.drawString("9", 12, 50 + fm.getAscent() / 2);
x0 = 50;
y0 = 50;
/* draw the hour hand */
hour %= 12;
angle = -(hour * 30 + minute / 2) + 90;
angle = angle * (Math.PI / 180.0);
x1 = (int) (x0 + 28 * (Math.cos(angle)));
y1 = (int) (y0 - 28 * (Math.sin(angle)));
g.drawLine(x0, y0, x1, y1);
/* and the minute hand */
angle = -(minute * 6) + 90;
angle = angle * Math.PI / 180.0;
x1 = (int) (x0 + 35 * (Math.cos(angle)));
y1 = (int) (y0 - 35 * (Math.sin(angle)));
g.drawLine(x0, y0, x1, y1);
}
public void addAlphaToImage() {
final int width = 100;
final int height = 100;
int alphaMask = 0;
final int[] pixels = new int[width * height];
final PixelGrabber pg = new PixelGrabber(clockImage, 0, 0, width,
height, pixels, 0, width);
try {
pg.grabPixels();
} catch (final InterruptedException e) {
System.err.println("interrupted waiting for pixels!");
return;
}
if ((pg.getStatus() & ImageObserver.ABORT) != 0) {
System.err.println("image fetch aborted or errored");
return;
}
for (int i = 0; i < width * height; i++) {
if ((i % width) == 0) {
alphaMask = (alphaMask >> 24) & 0xff;
alphaMask += 2;
if (alphaMask > 255) {
alphaMask = 255;
}
alphaMask = (alphaMask << 24) & 0xff000000;
}
pixels[i] = (pixels[i] & 0xffffff) | alphaMask;
}
clockImage = createImage(new MemoryImageSource(width, height, pixels,
0, width));
}
@Override
public void paint(final Graphics g) {
if (clockImage == null) {
clockImage = createImage(100, 100);
}
if (clockImage != null) {
if (!fileSaved) {
drawClockImage(hour, minute);
if (encodeAlpha) {
addAlphaToImage();
}
saveClockImage();
fileSaved = true;
}
g.drawImage(clockImage, 50, 20, null);
}
if (message != null) {
g.drawString(message, 10, 140);
}
}
protected static void usage() {
System.out.print("Usage: TestEncoder -alpha -filter n -compress c");
System.out.println("-alpha means to use alpha encoding (default none)");
System.out.println("n is filter number 0=none (default), 1=sub, 2=up");
System.out.println("c is compression factor (0-9); 1 default");
System.exit(0);
}
public static void main(final String[] args) {
int i;
final TestEncoder te = new TestEncoder("Test PNG Alpha/Filter Encoder");
i = 0;
te.encodeAlpha = false;
te.filter = 0;
te.pixelDepth = 24;
te.compressionLevel = 1;
while (i < args.length) {
if (args[i].equals("-alpha")) {
te.encodeAlpha = true;
i++;
} else if (args[i].equals("-filter")) {
if (i != args.length - 1) {
try {
te.filter = Integer.parseInt(args[i + 1]);
} catch (final Exception e) {
usage();
break;
}
}
i += 2;
} else if (args[i].equals("-compress")) {
if (i != args.length - 1) {
try {
te.compressionLevel = Integer.parseInt(args[i + 1]);
} catch (final Exception e) {
usage();
break;
}
}
i += 2;
} else {
usage();
break;
}
}
if (te.pixelDepth == 8) {
te.encodeAlpha = false;
}
te.doYourThing();
}
public void doYourThing() {
final Calendar cal = Calendar.getInstance();
hour = cal.get(Calendar.HOUR);
if (cal.get(Calendar.AM_PM) == 1) {
hour += 12;
}
hour %= 24;
minute = cal.get(Calendar.MINUTE);
/*
* format the time to a string of the form hhmm for use in the filename
*/
timeStr = Integer.toString(minute);
if (minute < 10) {
timeStr = "0" + timeStr;
}
timeStr = Integer.toString(hour) + timeStr;
if (hour < 10) {
timeStr = "0" + timeStr;
}
filename = (encodeAlpha) ? "alphaclock" : "clock";
filename += timeStr + "_f" + filter + compressionLevel + ".png";
message = "File: " + filename;
final WindowListener l = new WindowAdapter() {
@Override
public void windowClosing(final WindowEvent e) {
System.exit(0);
}
};
addWindowListener(l);
setVisible(true);
// show();
}
public void saveClockImage() {
byte[] pngbytes;
final PngEncoder png = new PngEncoder(clockImage,
(encodeAlpha) ? PngEncoder.ENCODE_ALPHA : PngEncoder.NO_ALPHA,
filter, compressionLevel);
try {
final FileOutputStream outfile = new FileOutputStream(filename);
pngbytes = png.pngEncode();
if (pngbytes == null) {
System.out.println("Null image");
} else {
outfile.write(pngbytes);
}
outfile.flush();
outfile.close();
} catch (final IOException e) {
e.printStackTrace();
}
}
}

View file

@ -0,0 +1,166 @@
/*
Copyright 2006 Rene Grothmann, modified by Eric Hakenholz
This file is part of C.a.R. software.
C.a.R. is a free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, version 3 of the License.
C.a.R. 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 for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package rene.util.list;
/**
* A class for a list of things. The list is forward and backward chained.
*
* @see rene.list.ListElement
*/
public class ListClass {
ListElement First, Last; // Pointer to start and end of list.
/**
* Generate an empty list.
*/
public ListClass() {
First = null;
Last = null;
}
/**
* Append a node to the list
*/
public void append(final ListElement l) {
if (Last == null)
init(l);
else {
Last.next(l);
l.previous(Last);
Last = l;
l.next(null);
l.list(this);
}
}
public void prepend(final ListElement l)
// prepend a node to the list
{
if (First == null)
init(l);
else {
First.previous(l);
l.next(First);
First = l;
l.previous(null);
l.list(this);
}
}
/*
* @param l ListElement to be inserted.
*
* @param after If null, it works like prepend.
*/
public void insert(final ListElement l, final ListElement after) {
if (after == Last)
append(l);
else if (after == null)
prepend(l);
else {
after.next().previous(l);
l.next(after.next());
after.next(l);
l.previous(after);
l.list(this);
}
}
/**
* initialize the list with a single element.
*/
public void init(final ListElement l) {
Last = First = l;
l.previous(null);
l.next(null);
l.list(this);
}
/**
* Remove a node from the list. The node really should be in the list, which
* is not checked.
*/
public void remove(final ListElement l) {
if (First == l) {
First = l.next();
if (First != null)
First.previous(null);
else
Last = null;
} else if (Last == l) {
Last = l.previous();
if (Last != null)
Last.next(null);
else
First = null;
} else {
l.previous().next(l.next());
l.next().previous(l.previous());
}
l.next(null);
l.previous(null);
l.list(null);
}
/**
* Empty the list.
*/
public void removeall() {
First = null;
Last = null;
}
/** remove everything after e */
public void removeAfter(final ListElement e) {
e.next(null);
Last = e;
}
/**
* @return First ListElement.
*/
public ListElement first() {
return First;
}
/**
* @return Last ListElement.
*/
public ListElement last() {
return Last;
}
/**
* Prints the class
*/
@Override
public String toString() {
ListElement e = First;
String s = "";
while (e != null) {
s = s + e.content().toString() + ", ";
e = e.next();
}
return s;
}
}

View file

@ -0,0 +1,79 @@
/*
Copyright 2006 Rene Grothmann, modified by Eric Hakenholz
This file is part of C.a.R. software.
C.a.R. is a free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, version 3 of the License.
C.a.R. 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 for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package rene.util.list;
/**
* The nodes of a list.
*
* @see rene.list.ListClass
*/
public class ListElement
// A list node with pointers to previous and next element
// and with a content of type Object.
{
ListElement Next, Previous; // the chain pointers
Object Content; // the content of the node
ListClass L; // Belongs to this list
public ListElement(final Object content)
// get a new Element with the content and null pointers
{
Content = content;
Next = Previous = null;
L = null;
}
// access methods:
public Object content() {
return Content;
}
public ListElement next() {
return Next;
}
public ListElement previous() {
return Previous;
}
public void list(final ListClass l) {
L = l;
}
// modifying methods:
public void content(final Object o) {
Content = o;
}
public void next(final ListElement o) {
Next = o;
}
public void previous(final ListElement o) {
Previous = o;
}
public ListClass list() {
return L;
}
}

118
rene/util/list/Tree.java Normal file
View file

@ -0,0 +1,118 @@
/*
Copyright 2006 Rene Grothmann, modified by Eric Hakenholz
This file is part of C.a.R. software.
C.a.R. is a free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, version 3 of the License.
C.a.R. 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 for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package rene.util.list;
/**
* A node with a list of children trees.
*/
public class Tree {
ListClass Children; // list of children, each with Tree as content
Object Content; // content
ListElement Le; // the listelement containing the tree
Tree Parent; // the parent tree
/** initialize with an object and no children */
public Tree(final Object o) {
Content = o;
Children = new ListClass();
Le = null;
Parent = null;
}
/** add a child tree */
public void addchild(final Tree t) {
final ListElement p = new ListElement(t);
Children.append(p);
t.Le = p;
t.Parent = this;
}
/** insert a child tree */
public void insertchild(final Tree t) {
if (!haschildren()) // simple case
{
addchild(t);
return;
}
// give t my children
t.Children = Children;
// make t my only child
Children = new ListClass();
final ListElement p = new ListElement(t);
Children.append(p);
t.Le = p;
t.Parent = this;
// fix the parents of all grandchildren
ListElement le = t.Children.first();
while (le != null) {
final Tree h = (Tree) (le.content());
h.Parent = t;
le = le.next();
}
}
/** remove the specific child tree (must be in the tree!!!) */
public void remove(final Tree t) {
if (t.parent() != this)
return;
Children.remove(t.Le);
}
/** remove all children */
public void removeall() {
Children.removeall();
}
// Access Methods:
public boolean haschildren() {
return Children.first() != null;
}
public Tree firstchild() {
return (Tree) Children.first().content();
}
public Tree lastchild() {
return (Tree) Children.last().content();
}
public Tree parent() {
return Parent;
}
public ListClass children() {
return Children;
}
public Object content() {
return Content;
}
public void content(final Object o) {
Content = o;
}
public ListElement listelement() {
return Le;
}
}

View file

@ -0,0 +1,372 @@
/*
Copyright 2006 Rene Grothmann, modified by Eric Hakenholz
This file is part of C.a.R. software.
C.a.R. is a free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, version 3 of the License.
C.a.R. 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 for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package rene.util.parser;
import java.util.Vector;
/**
* This is a string simple parser.
*/
public class StringParser {
char C[];
int N, L;
boolean Error;
/**
* @param S
* the string to be parsed.
*/
public StringParser(final String S) {
C = S.toCharArray();
N = 0;
L = C.length;
Error = (N >= L);
}
/**
* @return next character is white?
*/
public boolean blank() {
return (C[N] == ' ' || C[N] == '\t' || C[N] == '\n' || C[N] == '\r');
}
/**
* @return next character is white or c?
*/
public boolean blank(final char c) {
return (C[N] == ' ' || C[N] == '\t' || C[N] == '\n' || C[N] == '\r' || C[N] == c);
}
/**
* Cut off the String upto a character c.
*/
public String upto(final char c) {
if (Error)
return "";
int n = N;
while (n < L && C[n] != c)
n++;
if (n >= L)
Error = true;
final String s = new String(C, N, n - N);
N = n;
return s;
}
/**
* Advance one character.
*
* @return String is not empty.
*/
public boolean advance() {
if (N < L)
N++;
if (N >= L)
Error = true;
return !Error;
}
/**
* Parse a word up to a blank.
*/
public String parseword() {
if (Error)
return "";
while (blank()) {
if (!advance())
return "";
}
final int n = N;
while (!Error && !blank())
advance();
return new String(C, n, N - n);
}
/**
* Parse digits upto the character c or blank.
*/
public String parsedigits(final char c) {
if (Error)
return "";
while (blank()) {
if (!advance())
return "";
}
final int n = N;
while (!Error && !blank()) {
if (N > L || C[N] < '0' || C[N] > '9' || C[N] == c)
break;
advance();
}
return new String(C, n, N - n);
}
/**
* Parse digits upto a blank.
*/
public String parsedigits() {
if (Error)
return "";
while (blank()) {
if (!advance())
return "";
}
final int n = N;
while (!Error && !blank()) {
if (N > L || C[N] < '0' || C[N] > '9')
break;
advance();
}
return new String(C, n, N - n);
}
/**
* Parse a word upto the character c or blank.
*/
public String parseword(final char c) {
if (Error)
return "";
while (blank()) {
if (!advance())
return "";
}
final int n = N;
while (!Error && !blank(c))
advance();
return new String(C, n, N - n);
}
/**
* @return next character is a digit?
*/
public boolean isint() {
if (Error)
return false;
return (C[N] >= '0' && C[N] <= '9');
}
/**
* Parse an int upto a blank. The int may be negative.
*
* @return the int
*/
public int parseint() {
int sig = 1;
try {
skipblanks();
if (Error)
return 0;
if (C[N] == '-') {
sig = -1;
N++;
if (N > L) {
Error = true;
return 0;
}
}
return sig * Integer.parseInt(parsedigits(), 10);
} catch (final NumberFormatException e) {
return 0;
}
}
/**
* Parse an int upto a blank or c. The int may be negative.
*
* @return the int
*/
public int parseint(final char c) {
int sig = 1;
try {
skipblanks();
if (Error)
return 0;
if (C[N] == '-') {
sig = -1;
N++;
if (N > L) {
Error = true;
return 0;
}
}
return sig * Integer.parseInt(parsedigits(c), 10);
} catch (final NumberFormatException e) {
return 0;
}
}
/**
* Skip all white characters.
*/
public void skipblanks() {
if (Error)
return;
while (blank())
if (!advance())
break;
}
/**
* Skip everything to the string s.
*
* @return String was found
*/
public boolean skip(final String s) {
if (Error)
return false;
final int l = s.length();
if (N + l > L)
return false;
if (!new String(C, N, l).equals(s))
return false;
N += l;
if (N >= L)
Error = true;
return true;
}
/**
* Get the next character.
*/
public char next() {
if (Error)
return ' ';
else {
N++;
if (N >= L) {
Error = true;
}
return C[N - 1];
}
}
/**
* Return a String, which is parsed from words with limited length.
*
* @param columns
* the maximal length of the string
*/
public String wrapline(final int columns) {
int n = N, good = N;
String s = "";
while (n < L) {
if (C[n] == '\n') {
if (n > N)
s = new String(C, N, n - N);
N = n + 1;
break;
}
if (C[n] == ' ' || C[n] == '\t' || C[n] == '\n') {
good = n;
}
n++;
if (n - N >= columns && good > N) {
s = new String(C, N, good - N);
N = good + 1;
break;
}
if (n >= L) {
if (n > N)
s = new String(C, N, n - N);
N = n;
break;
}
}
if (N >= L)
Error = true;
return s;
}
/**
* Parse the string into lines.
*
* @param columns
* the maximal length of each line
* @return a Vector with lines
*/
public Vector wraplines(final int columns) {
final Vector v = new Vector(10, 10);
String s;
while (!Error) {
s = wrapline(columns);
v.addElement(s);
}
return v;
}
public String wraplineword(final int columns) {
int n = N;
final int good = N;
String s = "";
while (n < L) {
if (C[n] == '\n') {
s = new String(C, N, n - N);
N = n + 1;
break;
}
n++;
if (n >= L) {
if (n > N)
s = new String(C, N, n - N);
N = n;
break;
}
if (n - N >= columns && good > N) {
s = new String(C, N, good - N);
N = good + 1;
if (N < L && C[N] != '\n')
s = s + "\\";
break;
}
}
if (N >= L)
Error = true;
return s;
}
public Vector wrapwords(final int columns) {
final Vector v = new Vector(10, 10);
String s;
while (!Error) {
s = wraplineword(columns);
v.addElement(s);
}
return v;
}
/**
* Replace c1 by c2
*/
public void replace(final char c1, final char c2) {
for (int i = 0; i < L; i++)
if (C[i] == c1)
C[i] = c2;
}
/**
* @return if an error has occured during the parsing.
*/
public boolean error() {
return Error;
}
}

View file

@ -0,0 +1,26 @@
/*
Copyright 2006 Rene Grothmann, modified by Eric Hakenholz
This file is part of C.a.R. software.
C.a.R. is a free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, version 3 of the License.
C.a.R. 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 for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package rene.util.sort;
public interface SortObject {
public int compare(SortObject o);
}

View file

@ -0,0 +1,40 @@
/*
Copyright 2006 Rene Grothmann, modified by Eric Hakenholz
This file is part of C.a.R. software.
C.a.R. is a free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, version 3 of the License.
C.a.R. 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 for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package rene.util.sort;
public class SortString implements SortObject {
String S;
public SortString(final String s) {
S = s;
}
public int compare(final SortObject o) {
final SortString s = (SortString) o;
return S.compareTo(s.S);
}
@Override
public String toString() {
return S;
}
}

View file

@ -0,0 +1,36 @@
/*
Copyright 2006 Rene Grothmann, modified by Eric Hakenholz
This file is part of C.a.R. software.
C.a.R. is a free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, version 3 of the License.
C.a.R. 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 for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package rene.util.sort;
public class SortStringNoCase extends SortString {
String Orig;
public SortStringNoCase(final String s) {
super(s.toLowerCase());
Orig = s;
}
@Override
public String toString() {
return Orig;
}
}

140
rene/util/sort/Sorter.java Normal file
View file

@ -0,0 +1,140 @@
/*
Copyright 2006 Rene Grothmann, modified by Eric Hakenholz
This file is part of C.a.R. software.
C.a.R. is a free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, version 3 of the License.
C.a.R. 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 for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package rene.util.sort;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Enumeration;
import java.util.Vector;
/**
* Quick sort implementation. Sorts an array or a vector of SortObject.
*/
public class Sorter {
static public void sort(final SortObject v[]) {
QuickSort(v, 0, v.length - 1);
}
static public void sort(final SortObject v[], final int n) {
QuickSort(v, 0, n - 1);
}
static public void sort(final Vector v) {
final SortObject o[] = new SortObject[v.size()];
v.copyInto(o);
sort(o);
for (int i = 0; i < o.length; i++)
v.setElementAt(o[i], i);
}
static public void QuickSort(final SortObject a[], final int lo0,
final int hi0) {
int lo = lo0;
int hi = hi0;
SortObject mid;
if (hi0 > lo0) {
mid = a[(lo0 + hi0) / 2];
while (lo <= hi) {
while ((lo < hi0) && (a[lo].compare(mid) < 0))
++lo;
while ((hi > lo0) && (a[hi].compare(mid) > 0))
--hi;
if (lo <= hi) {
swap(a, lo, hi);
++lo;
--hi;
}
}
if (lo0 < hi)
QuickSort(a, lo0, hi);
if (lo < hi0)
QuickSort(a, lo, hi0);
}
}
static private void swap(final SortObject a[], final int i, final int j) {
SortObject T;
T = a[i];
a[i] = a[j];
a[j] = T;
}
static public void QuickSort(final Object a[], final int lo0, final int hi0) {
int lo = lo0;
int hi = hi0;
SortObject mid;
if (hi0 > lo0) {
mid = (SortObject) a[(lo0 + hi0) / 2];
while (lo <= hi) {
while ((lo < hi0) && (((SortObject) a[lo]).compare(mid) < 0))
++lo;
while ((hi > lo0) && (((SortObject) a[hi]).compare(mid) > 0))
--hi;
if (lo <= hi) {
swap(a, lo, hi);
++lo;
--hi;
}
}
if (lo0 < hi)
QuickSort(a, lo0, hi);
if (lo < hi0)
QuickSort(a, lo, hi0);
}
}
static private void swap(final Object a[], final int i, final int j) {
Object T;
T = a[i];
a[i] = a[j];
a[j] = T;
}
public static void main(final String args[]) throws IOException
// Sort the incoming lines and remove doublicates
{
final BufferedReader in = new BufferedReader(new InputStreamReader(
System.in));
final Vector v = new Vector();
while (true) {
final String line = in.readLine();
if (line == null)
break;
v.addElement(new SortString(line));
}
in.close();
sort(v);
final Enumeration e = v.elements();
String last = null;
while (e.hasMoreElements()) {
final String s = ((SortString) e.nextElement()).toString();
if (last == null || !s.equals(last)) {
System.out.println(s);
last = s;
}
}
}
}

View file

@ -0,0 +1,86 @@
/*
Copyright 2006 Rene Grothmann, modified by Eric Hakenholz
This file is part of C.a.R. software.
C.a.R. is a free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, version 3 of the License.
C.a.R. 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 for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package rene.util.xml;
import java.io.FileOutputStream;
import java.io.PrintWriter;
public class SVGWriter extends XmlWriter {
int W, H;
public SVGWriter(final PrintWriter o, final String enc, final int w,
final int h) {
super(o);
printEncoding(enc);
W = w;
H = h;
startTagStart("svg");
printArg("width", "" + w);
printArg("height", "" + h);
startTagEndNewLine();
}
public SVGWriter(final PrintWriter o) {
super(o);
}
public void startSVG(final int w, final int h) {
printEncoding("utf-8");
Out.println("<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"");
Out.println("\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">");
startTagStart("svg");
printArg("xmlns", "http://www.w3.org/2000/svg");
printArg("width", "" + w);
printArg("height", "" + h);
startTagEndNewLine();
}
@Override
public void close() {
endTag("svg");
super.close();
}
public void coord(final int x, final int y) {
printArg("x", "" + x);
printArg("y", "" + y);
}
public void text(final String text, final int x, final int y) {
startTagStart("text");
coord(x, y);
startTagEnd();
print(text);
endTagNewLine("text");
}
public static void main(final String args[]) throws Exception {
final SVGWriter out = new SVGWriter(new PrintWriter(
new FileOutputStream("test.svg")), "", 300, 300);
out.text("Hallo Welt", 10, 95);
out.startTagStart("path");
out.printArg("d", "M 150 150 A 50 50 0 1 0 100 200");
out.printArg("style", "fill:none;stroke-width:1;stroke:black");
out.finishTagNewLine();
out.close();
}
}

View file

@ -0,0 +1,505 @@
/*
Copyright 2006 Rene Grothmann, modified by Eric Hakenholz
This file is part of C.a.R. software.
C.a.R. is a free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, version 3 of the License.
C.a.R. 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 for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package rene.util.xml;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import rene.util.SimpleByteBuffer;
import rene.util.SimpleStringBuffer;
import rene.util.list.ListElement;
public class XmlReader {
BufferedReader In;
SimpleStringBuffer buf = new SimpleStringBuffer(10000);
public XmlReader() {
In = null;
}
public XmlReader(final BufferedReader in) {
In = in;
}
public XmlReader(final InputStream in) throws XmlReaderException {
try { // read the file into a buffer
final BufferedInputStream rin = new BufferedInputStream(in);
final SimpleByteBuffer bb = new SimpleByteBuffer(10000);
while (true) {
final int k = rin.read();
if (k < 0)
break;
bb.append((byte) k);
}
rin.close();
final byte b[] = bb.getByteArray();
// Try to open an ASCII stream, or a default stream
ByteArrayInputStream bin = new ByteArrayInputStream(b);
XmlReader R = null;
try {
R = new XmlReader(new BufferedReader(new InputStreamReader(bin,
"ASCII")));
} catch (final UnsupportedEncodingException ex) {
R = new XmlReader(
new BufferedReader(new InputStreamReader(bin)));
}
// Determine the encoding
String Encoding = null;
while (true) {
while (true) {
final int c = R.read();
if (c == -1)
throw new Exception("<?xml> tag not found");
if (c == '<')
break;
}
if (R.found("?xml")) {
String s = R.scanFor("?>");
if (s == null)
throw new Exception("<?xml> tag error");
int n = s.indexOf("encoding=\"");
if (n >= 0) {
n += "encoding=\"".length();
s = s.substring(n);
final int m = s.indexOf('\"');
if (m < 0)
throw new Exception("Closing bracket missing");
Encoding = s.substring(0, m).toUpperCase();
if (Encoding.equals("UTF-8"))
Encoding = "UTF8";
// for IE5 !
break;
}
break;
}
}
// Open a stream with this encoding
bin = new ByteArrayInputStream(b);
if (Encoding == null)
In = new BufferedReader(new InputStreamReader(bin));
else
try {
In = new BufferedReader(
new InputStreamReader(bin, Encoding));
} catch (final UnsupportedEncodingException e) {
try {
In = new BufferedReader(new InputStreamReader(bin,
"ASCII"));
} catch (final UnsupportedEncodingException ex) {
In = new BufferedReader(new InputStreamReader(bin));
}
}
} catch (final Exception e) {
throw new XmlReaderException(e.toString());
}
}
public void init(final InputStream in) throws XmlReaderException {
try { // read the file into a buffer
final BufferedInputStream rin = new BufferedInputStream(in);
final SimpleByteBuffer bb = new SimpleByteBuffer(10000);
while (true) {
final int k = rin.read();
if (k < 0)
break;
bb.append((byte) k);
}
rin.close();
final byte b[] = bb.getByteArray();
// Try to open an ASCII stream, or a default stream
ByteArrayInputStream bin = new ByteArrayInputStream(b);
XmlReader R = null;
try {
R = new XmlReader(new BufferedReader(new InputStreamReader(bin,
"ASCII")));
} catch (final UnsupportedEncodingException ex) {
R = new XmlReader(
new BufferedReader(new InputStreamReader(bin)));
}
// Determine the encoding
String Encoding = null;
while (true) {
while (true) {
final int c = R.read();
if (c == -1)
throw new Exception("<?xml> tag not found");
if (c == '<')
break;
}
if (R.found("?xml")) {
String s = R.scanFor("?>");
if (s == null)
throw new Exception("<?xml> tag error");
int n = s.indexOf("encoding=\"");
if (n >= 0) {
n += "encoding=\"".length();
s = s.substring(n);
final int m = s.indexOf('\"');
if (m < 0)
throw new Exception("Closing bracket missing");
Encoding = s.substring(0, m).toUpperCase();
if (Encoding.equals("UTF-8"))
Encoding = "UTF8";
// for IE5 !
break;
}
break;
}
}
// Open a stream with this encoding
bin = new ByteArrayInputStream(b);
if (Encoding == null)
In = new BufferedReader(new InputStreamReader(bin));
else
try {
In = new BufferedReader(
new InputStreamReader(bin, Encoding));
} catch (final UnsupportedEncodingException e) {
try {
In = new BufferedReader(new InputStreamReader(bin,
"ASCII"));
} catch (final UnsupportedEncodingException ex) {
In = new BufferedReader(new InputStreamReader(bin));
}
}
} catch (final Exception e) {
throw new XmlReaderException(e.toString());
}
}
/**
* Scan an xml file. This function reads, until <?xml is found. then it
* skips this declaration and scans the rest of the items.
*/
public XmlTree scan() throws XmlReaderException {
while (true) {
while (true) {
final int c = read();
if (c == -1)
return null;
if (c == '<')
break;
}
if (found("?xml")) {
final String s = scanFor("?>");
if (s == null)
return null;
final XmlTree t = new XmlTree(new XmlTagRoot());
t.addchild(new XmlTree(new XmlTagPI(s)));
scanContent(t);
return t;
}
}
}
public void scanContent(final XmlTree t) throws XmlReaderException { // System.out.println("Sanning for "+t.getTag().name()+" ("+
// t.getTag().countParams()+")");
while (true) {
String s = scanFor('<');
if (s == null) {
if (t.getTag() instanceof XmlTagRoot)
return;
exception("File ended surprisingly");
}
if (!empty(s)) {
t
.addchild(new XmlTree(new XmlTagText(XmlTranslator
.toText(s))));
}
if (found("!--")) {
s = scanFor("-->");
continue;
}
if (found("!")) {
s = scanTagFor('>');
continue;
}
if (found("?")) {
s = scanTagFor("?>");
t.addchild(new XmlTree(new XmlTagPI(s)));
continue;
}
s = scanTagFor('>');
if (s == null)
exception("> missing");
if (s.startsWith("/")) {
if (s.substring(1).equals(t.getTag().name()))
return;
else
exception("End tag without start tag");
}
if (s.endsWith("/")) {
t.addchild(new XmlTree(new XmlTag(s
.substring(0, s.length() - 1))));
} else {
final XmlTree t0 = new XmlTree(new XmlTag(s));
scanContent(t0);
t.addchild(t0);
}
}
}
public boolean empty(final String s) {
final int n = s.length();
for (int i = 0; i < n; i++) {
final char c = s.charAt(i);
if (c != ' ' && c != '\n' && c != '\t')
return false;
}
return true;
}
/**
* Skip Blanks.
*
* @return Non-blank character or -1 for EOF.
*/
public int skipBlanks() throws XmlReaderException {
while (true) {
final int c = read();
if (c == ' ' || c == '\t' || c == '\n')
continue;
else
return c;
}
}
/**
* Scan for an end character.
*
* @return String between the current position and the end character, or
* null.
*/
public String scanFor(final char end) throws XmlReaderException {
buf.clear();
int c = read();
while (c != end) {
buf.append((char) c);
c = read();
if (c < 0)
return null;
}
return buf.toString();
}
/**
* Scan for a specific string.
*
* @return String between the current position and the string.
*/
public String scanFor(final String s) throws XmlReaderException {
buf.clear();
while (!found(s)) {
final int c = read();
if (c < 0)
return null;
buf.append((char) c);
}
for (int i = 0; i < s.length(); i++)
read();
return buf.toString();
}
/**
* Scan tag for an end character (interpreting " and ')
*
* @return String between the current position and the end character, or
* null.
*/
public String scanTagFor(final char end) throws XmlReaderException {
buf.clear();
int c = read();
while (c != end) {
if (c == '\"') {
buf.append((char) c);
while (true) {
c = read();
if (c < 0)
return null;
if (c == '\"')
break;
buf.append((char) c);
}
buf.append((char) c);
} else if (c == '\'') {
buf.append((char) c);
while (true) {
c = read();
if (c < 0)
return null;
if (c == '\'')
break;
buf.append((char) c);
}
buf.append((char) c);
} else
buf.append((char) c);
c = read();
if (c < 0)
return null;
}
return buf.toString();
}
/**
* Scan tag for a specific string (interpreting " and ')
*
* @return String between the current position and the string.
*/
public String scanTagFor(final String s) throws XmlReaderException {
buf.clear();
while (!found(s)) {
int c = read();
if (c < 0)
return null;
if (c == '\"') {
buf.append((char) c);
while (true) {
c = read();
if (c < 0)
return null;
if (c == '\"')
break;
buf.append((char) c);
}
buf.append((char) c);
} else if (c == '\'') {
buf.append((char) c);
while (true) {
c = read();
if (c < 0)
return null;
if (c == '\'')
break;
buf.append((char) c);
}
buf.append((char) c);
} else
buf.append((char) c);
}
for (int i = 0; i < s.length(); i++)
read();
return buf.toString();
}
String Line = null;
int LinePos;
public int read() throws XmlReaderException {
try {
if (Line == null) {
Line = In.readLine();
LinePos = 0;
// System.out.println("Read --> "+Line);
}
if (Line == null)
return -1;
if (LinePos >= Line.length()) {
Line = null;
return '\n';
}
return Line.charAt(LinePos++);
} catch (final Exception e) {
return -1;
}
}
/**
* @return If the string is at the current line position.
*/
public boolean found(final String s) {
final int n = s.length();
if (LinePos + n > Line.length())
return false;
for (int i = 0; i < n; i++)
if (s.charAt(i) != Line.charAt(LinePos + i))
return false;
return true;
}
public void exception(final String s) throws XmlReaderException {
throw new XmlReaderException(s, Line, LinePos);
}
/**
* A test program.
*/
public static void main(final String args[]) {
try {
final BufferedReader in = new BufferedReader(new InputStreamReader(
new FileInputStream("rene\\util\\xml\\test.xml"), "UTF8"));
final XmlReader reader = new XmlReader(in);
final XmlTree tree = reader.scan();
in.close();
print(tree);
} catch (final XmlReaderException e) {
System.out.println(e.toString() + "\n" + e.getLine() + "\n"
+ "Position : " + e.getPos());
} catch (final IOException e) {
System.out.println(e);
}
}
public static void print(final XmlTree t) {
final XmlTag tag = t.getTag();
System.out.print("<" + tag.name());
for (int i = 0; i < tag.countParams(); i++) {
System.out.print(" " + tag.getParam(i) + "=\"" + tag.getValue(i)
+ "\"");
}
System.out.println(">");
ListElement el = t.children().first();
while (el != null) {
print((XmlTree) (el.content()));
el = el.next();
}
System.out.println("</" + tag.name() + ">");
}
public static boolean testXml(final String s) {
int i = 0;
while (i < s.length()) {
final char c = s.charAt(i);
if (c == '<')
break;
i++;
}
if (i >= s.length())
return false;
if (s.substring(i).startsWith("<?xml"))
return true;
return false;
}
}

View file

@ -0,0 +1,55 @@
/*
Copyright 2006 Rene Grothmann, modified by Eric Hakenholz
This file is part of C.a.R. software.
C.a.R. is a free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, version 3 of the License.
C.a.R. 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 for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package rene.util.xml;
public class XmlReaderException extends Exception {
/**
*
*/
private static final long serialVersionUID = 1L;
String Line;
int Pos;
String S;
public XmlReaderException(final String s, final String line, final int pos) {
super(s);
S = s;
Line = line;
Pos = pos;
}
public XmlReaderException(final String s) {
this(s, "", 0);
}
public String getLine() {
return Line;
}
public int getPos() {
return Pos;
}
public String getText() {
return S;
}
}

149
rene/util/xml/XmlTag.java Normal file
View file

@ -0,0 +1,149 @@
/*
Copyright 2006 Rene Grothmann, modified by Eric Hakenholz
This file is part of C.a.R. software.
C.a.R. is a free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, version 3 of the License.
C.a.R. 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 for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package rene.util.xml;
public class XmlTag {
protected String Tag = "";
String Param[];
String Value[];
int N = 0;
public XmlTag(final String s) {
int n = 0;
int k = 0;
n = skipBlanks(s, n);
while (n < s.length()) {
n = endItem(s, n);
k++;
n = skipBlanks(s, n);
}
if (k == 0)
return;
n = 0;
n = skipBlanks(s, n);
int m = endItem(s, n);
Tag = s.substring(n, m);
n = m;
N = k - 1;
Param = new String[N];
Value = new String[N];
for (int i = 0; i < N; i++) {
n = skipBlanks(s, n);
m = endItem(s, n);
final String p = s.substring(n, m);
n = m;
final int kp = p.indexOf('=');
if (kp >= 0) {
Param[i] = p.substring(0, kp);
Value[i] = XmlTranslator.toText(p.substring(kp + 1));
if (Value[i].startsWith("\"") && Value[i].endsWith("\"")) {
Value[i] = Value[i].substring(1, Value[i].length() - 1);
} else if (Value[i].startsWith("\'") && Value[i].endsWith("\'")) {
Value[i] = Value[i].substring(1, Value[i].length() - 1);
}
} else {
Param[i] = p;
Value[i] = "";
}
}
}
int skipBlanks(final String s, int n) {
while (n < s.length()) {
final char c = s.charAt(n);
if (c == ' ' || c == '\t' || c == '\n')
n++;
else
break;
}
return n;
}
int endItem(final String s, int n) {
while (n < s.length()) {
final char c = s.charAt(n);
if (c == ' ' || c == '\t' || c == '\n')
break;
if (c == '\"') {
n++;
while (true) {
if (n >= s.length())
return n;
if (s.charAt(n) == '\"')
break;
n++;
}
} else if (c == '\'') {
n++;
while (true) {
if (n >= s.length())
return n;
if (s.charAt(n) == '\'')
break;
n++;
}
}
n++;
}
return n;
}
public String name() {
return Tag;
}
public int countParams() {
return N;
}
public String getParam(final int i) {
return Param[i];
}
public String getValue(final int i) {
return Value[i];
}
public boolean hasParam(final String param) {
for (int i = 0; i < N; i++)
if (Param[i].equals(param))
return true;
return false;
}
public boolean hasTrueParam(final String param) {
for (int i = 0; i < N; i++)
if (Param[i].equals(param)) {
if (Value[i].equals("true"))
return true;
return false;
}
return false;
}
public String getValue(final String param) {
for (int i = 0; i < N; i++)
if (Param[i].equals(param))
return Value[i];
return null;
}
}

View file

@ -0,0 +1,30 @@
/*
Copyright 2006 Rene Grothmann, modified by Eric Hakenholz
This file is part of C.a.R. software.
C.a.R. is a free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, version 3 of the License.
C.a.R. 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 for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package rene.util.xml;
public class XmlTagPI extends XmlTag {
String Content;
public XmlTagPI(final String s) {
super(s);
}
}

View file

@ -0,0 +1,30 @@
/*
Copyright 2006 Rene Grothmann, modified by Eric Hakenholz
This file is part of C.a.R. software.
C.a.R. is a free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, version 3 of the License.
C.a.R. 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 for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package rene.util.xml;
public class XmlTagRoot extends XmlTag {
String Content;
public XmlTagRoot() {
super("#ROOT");
}
}

View file

@ -0,0 +1,35 @@
/*
Copyright 2006 Rene Grothmann, modified by Eric Hakenholz
This file is part of C.a.R. software.
C.a.R. is a free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, version 3 of the License.
C.a.R. 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 for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package rene.util.xml;
public class XmlTagText extends XmlTag {
String Content;
public XmlTagText(final String s) {
super("#PCDATA");
Content = s;
}
public String getContent() {
return Content;
}
}

View file

@ -0,0 +1,104 @@
/*
Copyright 2006 Rene Grothmann, modified by Eric Hakenholz
This file is part of C.a.R. software.
C.a.R. is a free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, version 3 of the License.
C.a.R. 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 for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package rene.util.xml;
import rene.util.SimpleStringBuffer;
public class XmlTranslator {
static SimpleStringBuffer H = new SimpleStringBuffer(10000);
static String toXml(final String s) {
final int m = s.length();
H.clear();
for (int i = 0; i < m; i++) {
final char c = s.charAt(i);
switch (c) {
case '<':
toH("&lt;");
break;
case '>':
toH("&gt;");
break;
case '&':
toH("&amp;");
break;
case '\'':
toH("&apos;");
break;
case '\"':
toH("&quot;");
break;
default:
H.append(c);
}
}
return H.toString();
}
static void toH(final String s) {
final int m = s.length();
for (int i = 0; i < m; i++) {
H.append(s.charAt(i));
}
}
static String toText(final String s) {
final int m = s.length();
H.clear();
for (int i = 0; i < m; i++) {
final char c = s.charAt(i);
if (c == '&') {
if (find(s, i, "&lt;")) {
H.append('<');
i += 3;
} else if (find(s, i, "&gt;")) {
H.append('>');
i += 3;
} else if (find(s, i, "&quot;")) {
H.append('\"');
i += 5;
} else if (find(s, i, "&apos;")) {
H.append('\'');
i += 5;
} else if (find(s, i, "&amp;")) {
H.append('&');
i += 4;
} else
H.append(c);
} else
H.append(c);
}
return H.toString();
}
static boolean find(final String s, final int pos, final String t) {
try {
for (int i = 0; i < t.length(); i++) {
if (s.charAt(pos + i) != t.charAt(i))
return false;
}
return true;
} catch (final Exception e) {
return false;
}
}
}

119
rene/util/xml/XmlTree.java Normal file
View file

@ -0,0 +1,119 @@
/*
Copyright 2006 Rene Grothmann, modified by Eric Hakenholz
This file is part of C.a.R. software.
C.a.R. is a free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, version 3 of the License.
C.a.R. 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 for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package rene.util.xml;
import java.util.Enumeration;
import java.util.Vector;
import rene.util.list.ListElement;
import rene.util.list.Tree;
import rene.util.parser.StringParser;
public class XmlTree extends Tree implements Enumeration {
public XmlTree(final XmlTag t) {
super(t);
}
public XmlTag getTag() {
return (XmlTag) content();
}
public XmlTree xmlFirstContent() {
if (firstchild() != null)
return (XmlTree) firstchild();
else
return null;
}
public boolean isText() {
if (!haschildren())
return true;
if (firstchild() != lastchild())
return false;
final XmlTree t = (XmlTree) firstchild();
final XmlTag tag = t.getTag();
if (!(tag instanceof XmlTagText))
return false;
return true;
}
public String getText() {
if (!haschildren())
return "";
final XmlTree t = (XmlTree) firstchild();
final XmlTag tag = t.getTag();
return ((XmlTagText) tag).getContent();
}
ListElement Current;
public Enumeration getContent() {
Current = children().first();
return this;
}
public boolean hasMoreElements() {
return Current != null;
}
public Object nextElement() {
if (Current == null)
return null;
final XmlTree c = (XmlTree) (Current.content());
Current = Current.next();
return c;
}
public String parseComment() throws XmlReaderException {
final StringBuffer s = new StringBuffer();
final Enumeration e = getContent();
while (e.hasMoreElements()) {
final XmlTree tree = (XmlTree) e.nextElement();
final XmlTag tag = tree.getTag();
if (tag.name().equals("P")) {
if (!tree.haschildren())
s.append("\n");
else {
final XmlTree h = tree.xmlFirstContent();
String k = ((XmlTagText) h.getTag()).getContent();
k = k.replace('\n', ' ');
final StringParser p = new StringParser(k);
final Vector v = p.wraplines(1000);
for (int i = 0; i < v.size(); i++) {
s.append((String) v.elementAt(i));
s.append("\n");
}
}
} else if (tag instanceof XmlTagText) {
final String k = ((XmlTagText) tag).getContent();
final StringParser p = new StringParser(k);
final Vector v = p.wraplines(1000);
for (int i = 0; i < v.size(); i++) {
s.append((String) v.elementAt(i));
s.append("\n");
}
} else
throw new XmlReaderException("<" + tag.name()
+ "> not proper here.");
}
return s.toString();
}
}

View file

@ -0,0 +1,203 @@
/*
Copyright 2006 Rene Grothmann, modified by Eric Hakenholz
This file is part of C.a.R. software.
C.a.R. is a free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, version 3 of the License.
C.a.R. 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 for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package rene.util.xml;
import java.io.PrintWriter;
import java.util.Vector;
import rene.util.parser.StringParser;
public class XmlWriter {
PrintWriter Out;
public XmlWriter(final PrintWriter o) {
Out = o;
}
public void printTag(final String tag, final String content) {
startTag(tag);
print(content);
endTag(tag);
}
public void printTagNewLine(final String tag, final String content) {
printTag(tag, content);
Out.println();
}
public void printTag(final String tag, final String arg,
final String value, final String content) {
startTag(tag, arg, value);
print(content);
endTag(tag);
}
public void printTagNewLine(final String tag, final String arg,
final String value, final String content) {
printTag(tag, arg, value, content);
Out.println();
}
public void startTag(final String tag) {
Out.print("<");
Out.print(tag);
Out.print(">");
}
public void startTag(final String tag, final String arg, final String value) {
Out.print("<");
Out.print(tag);
printArg(arg, value);
Out.print(">");
}
public void finishTag(final String tag, final String arg, final String value) {
Out.print("<");
Out.print(tag);
printArg(arg, value);
Out.println("/>");
}
public void finishTag(final String tag) {
Out.print("<");
Out.print(tag);
Out.print("/>");
}
public void finishTagNewLine(final String tag) {
Out.print("<");
Out.print(tag);
Out.println("/>");
}
public void startTagStart(final String tag) {
Out.print("<");
Out.print(tag);
}
public void startTagEnd() {
Out.print(">");
}
public void finishTag() {
Out.print("/>");
}
public void finishTagNewLine() {
Out.println("/>");
}
public void startTagEndNewLine() {
Out.println(">");
}
public void printArg(final String arg, final String value) {
Out.print(" ");
print(arg);
Out.print("=\"");
print(value);
Out.print("\"");
}
public void startTagNewLine(final String tag, final String arg,
final String value) {
startTag(tag, arg, value);
Out.println();
}
public void startTagNewLine(final String tag) {
startTag(tag);
Out.println();
}
public void endTag(final String tag) {
Out.print("</");
Out.print(tag);
Out.print(">");
}
public void endTagNewLine(final String tag) {
endTag(tag);
Out.println();
}
public void println() {
Out.println();
}
public void print(final String s) {
Out.print(XmlTranslator.toXml(s));
}
public void println(final String s) {
Out.println(XmlTranslator.toXml(s));
}
public void printEncoding(final String s) {
if (s.equals(""))
Out.println("<?xml version=\"1.0\"?>");
else
Out.println("<?xml version=\"1.0\" encoding=\"" + s + "\"?>");
}
public void printXml() {
printEncoding("");
}
public void printEncoding() {
printEncoding("utf-8");
}
public void printXls(final String s) {
Out.println("<?xml-stylesheet href=\"" + s + "\" type=\"text/xsl\"?>");
}
public void printParagraphs(String s, final int linelength) {
final StringParser p = new StringParser(s);
final Vector v = p.wrapwords(linelength);
for (int i = 0; i < v.size(); i++) {
startTag("P");
s = (String) v.elementAt(i);
final StringParser q = new StringParser(s);
final Vector w = q.wraplines(linelength);
for (int j = 0; j < w.size(); j++) {
if (j > 0)
println();
s = (String) w.elementAt(j);
print(s);
}
endTagNewLine("P");
}
}
public void printDoctype(final String top, final String dtd) {
Out.print("<!DOCTYPE ");
Out.print(top);
Out.print(" SYSTEM \"");
Out.print(dtd);
Out.println("\">");
}
public void close() {
Out.close();
}
}