--- /dev/null
+/*
+ * $Id$
+ * Copyright (C) 2002 The Apache Software Foundation. All rights reserved.
+ * For details on use and redistribution please refer to the
+ * LICENSE file included with these sources.
+ */
+package org.apache.fop.fonts.type1;
+
+import java.io.OutputStream;
+import java.io.IOException;
+
+/**
+ * Class that represents the contents of a PFB file.
+ *
+ * @see PFBParser
+ */
+public class PFBData {
+
+ /**
+ * Raw format, no special file structure
+ */
+ public static final int PFB_RAW = 0;
+
+ /**
+ * PC format
+ */
+ public static final int PFB_PC = 1;
+
+ /**
+ * MAC Format (unsupported, yet)
+ */
+ public static final int PFB_MAC = 2;
+
+ private int pfbFormat; //One of the PFB_* constants
+ private byte[] headerSegment;
+ private byte[] encryptedSegment;
+ private byte[] trailerSegment;
+
+
+ /**
+ * Sets the PFB format the font was loaded with.
+ * @param format one of the PFB_* constants
+ */
+ public void setPFBFormat(int format) {
+ switch (format) {
+ case PFB_RAW:
+ case PFB_PC:
+ this.pfbFormat = format;
+ break;
+ case PFB_MAC:
+ throw new UnsupportedOperationException("Mac format is not yet implemented");
+ default:
+ throw new IllegalArgumentException("Invalid value for PFB format: " + format);
+ }
+ }
+
+
+ /**
+ * Returns the format the font was loaded with.
+ * @return int one of the PFB_* constants
+ */
+ public int getPFBFormat() {
+ return this.pfbFormat;
+ }
+
+ /**
+ * Sets the header segment of the font file.
+ * @param headerSeg the header segment
+ */
+ public void setHeaderSegment(byte[] headerSeg) {
+ this.headerSegment = headerSeg;
+ }
+
+ /**
+ * Sets the encrypted segment of the font file.
+ * @param encryptedSeg the encrypted segment
+ */
+ public void setEncryptedSegment(byte[] encryptedSeg) {
+ this.encryptedSegment = encryptedSeg;
+ }
+
+ /**
+ * Sets the trailer segment of the font file.
+ * @param trailerSeg the trailer segment
+ */
+ public void setTrailerSegment(byte[] trailerSeg) {
+ this.trailerSegment = trailerSeg;
+ }
+
+ /**
+ * Returns the full length of the raw font file.
+ * @return int the raw file length
+ */
+ public int getLength() {
+ return getLength1() + getLength2() + getLength3();
+ }
+
+
+ /**
+ * Returns the Length1 (length of the header segment).
+ * @return int Length1
+ */
+ public int getLength1() {
+ return this.headerSegment.length;
+ }
+
+
+ /**
+ * Returns the Length2 (length of the encrypted segment).
+ * @return int Length2
+ */
+ public int getLength2() {
+ return this.encryptedSegment.length;
+ }
+
+
+ /**
+ * Returns the Length3 (length of the trailer segment).
+ * @return int Length3
+ */
+ public int getLength3() {
+ return this.trailerSegment.length;
+ }
+
+
+ /**
+ * Writes the PFB file in raw format to an OutputStream.
+ * @param out the OutputStream to write to
+ * @throws IOException In case of an I/O problem
+ */
+ public void outputAllParts(OutputStream out) throws IOException {
+ out.write(this.headerSegment);
+ out.write(this.encryptedSegment);
+ out.write(this.trailerSegment);
+ }
+
+
+ /**
+ * @see java.lang.Object#toString()
+ */
+ public String toString() {
+ return "PFB: format=" + getPFBFormat()
+ + " len1=" + getLength1()
+ + " len2=" + getLength2()
+ + " len3=" + getLength3();
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * $Id$
+ * Copyright (C) 2002 The Apache Software Foundation. All rights reserved.
+ * For details on use and redistribution please refer to the
+ * LICENSE file included with these sources.
+ */
+package org.apache.fop.fonts.type1;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.DataInputStream;
+import java.io.BufferedInputStream;
+
+//FOP
+import org.apache.fop.util.StreamUtilities;
+
+/**
+ * This class represents a parser for Adobe Type 1 PFB files.
+ *
+ * @see PFBData
+ */
+public class PFBParser {
+
+ private static final byte[] CURRENTFILE_EEXEC;
+ private static final byte[] CLEARTOMARK;
+
+ static {
+ try {
+ CURRENTFILE_EEXEC = "currentfile eexec".getBytes("US-ASCII");
+ CLEARTOMARK = "cleartomark".getBytes("US-ASCII");
+ } catch (java.io.UnsupportedEncodingException e) {
+ throw new RuntimeException("Incompatible VM. It doesn't support the US-ASCII encoding");
+ }
+ }
+
+
+ /**
+ * Parses a PFB file into a PFBData object.
+ * @param url URL to load the PFB file from
+ * @return PFBData memory representation of the font
+ * @throws IOException In case of an I/O problem
+ */
+ public PFBData parsePFB(java.net.URL url) throws IOException {
+ InputStream in = url.openStream();
+ try {
+ return parsePFB(in);
+ } finally {
+ in.close();
+ }
+ }
+
+
+ /**
+ * Parses a PFB file into a PFBData object.
+ * @param pfbFile File to load the PFB file from
+ * @return PFBData memory representation of the font
+ * @throws IOException In case of an I/O problem
+ */
+ public PFBData parsePFB(java.io.File pfbFile) throws IOException {
+ InputStream in = new java.io.FileInputStream(pfbFile);
+ try {
+ return parsePFB(in);
+ } finally {
+ in.close();
+ }
+ }
+
+
+ /**
+ * Parses a PFB file into a PFBData object.
+ * @param in InputStream to load the PFB file from
+ * @return PFBData memory representation of the font
+ * @throws IOException In case of an I/O problem
+ */
+ public PFBData parsePFB(InputStream in) throws IOException {
+ PFBData pfb = new PFBData();
+ BufferedInputStream bin = new BufferedInputStream(in);
+ DataInputStream din = new DataInputStream(bin);
+ din.mark(32);
+ int firstByte = din.readUnsignedByte();
+ din.reset();
+ if (firstByte == 128) {
+ pfb.setPFBFormat(PFBData.PFB_PC);
+ parsePCFormat(pfb, din);
+ } else {
+ pfb.setPFBFormat(PFBData.PFB_RAW);
+ parseRAWFormat(pfb, bin);
+ }
+ return pfb;
+ }
+
+
+ private static int swapInteger(final int value) {
+ return (((value >> 0) & 0xff) << 24)
+ + (((value >> 8) & 0xff) << 16)
+ + (((value >> 16) & 0xff) << 8)
+ + (((value >> 24) & 0xff) << 0);
+ }
+
+
+ private void parsePCFormat(PFBData pfb, DataInputStream din) throws IOException {
+ int segmentHead;
+ int segmentType;
+ int bytesRead;
+
+ //Read first segment
+ segmentHead = din.readUnsignedByte();
+ if (segmentHead != 128) {
+ throw new IOException("Invalid file format. Expected ASCII 80hex");
+ }
+ segmentType = din.readUnsignedByte(); //Read
+ int len1 = swapInteger(din.readInt());
+ byte[] headerSegment = new byte[len1];
+ bytesRead = din.read(headerSegment);
+ if (bytesRead != len1) {
+ throw new IOException("Could not load the whole segment");
+ }
+ pfb.setHeaderSegment(headerSegment);
+
+ //Read second segment
+ segmentHead = din.readUnsignedByte();
+ if (segmentHead != 128) {
+ throw new IOException("Invalid file format. Expected ASCII 80hex");
+ }
+ segmentType = din.readUnsignedByte();
+ int len2 = swapInteger(din.readInt());
+ byte[] encryptedSegment = new byte[len2];
+ bytesRead = din.read(encryptedSegment);
+ if (bytesRead != len2) {
+ throw new IOException("Could not load the whole segment");
+ }
+ pfb.setEncryptedSegment(encryptedSegment);
+
+ //Read third segment
+ segmentHead = din.readUnsignedByte();
+ if (segmentHead != 128) {
+ throw new IOException("Invalid file format. Expected ASCII 80hex");
+ }
+ segmentType = din.readUnsignedByte();
+ int len3 = swapInteger(din.readInt());
+ byte[] trailerSegment = new byte[len3];
+ bytesRead = din.read(trailerSegment);
+ if (bytesRead != len3) {
+ throw new IOException("Could not load the whole segment");
+ }
+ pfb.setTrailerSegment(trailerSegment);
+
+ //Read EOF indicator
+ segmentHead = din.readUnsignedByte();
+ if (segmentHead != 128) {
+ throw new IOException("Invalid file format. Expected ASCII 80hex");
+ }
+ segmentType = din.readUnsignedByte();
+ if (segmentType != 3) {
+ throw new IOException("Expected segment type 3, but found: " + segmentType);
+ }
+ }
+
+
+ private static final boolean byteCmp(byte[] src, int srcOffset, byte[] cmp) {
+ for (int i = 0; i < cmp.length; i++) {
+ // System.out.println("Compare: " + src[srcOffset + i] + " " + cmp[i]);
+ if (src[srcOffset + i] != cmp[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private void calcLengths(PFBData pfb, byte[] originalData) {
+ // Calculate length 1 and 3
+ // System.out.println ("Checking font, size = "+originalData.length);
+
+ // Length1 is the size of the initial ascii portion
+ // search for "currentfile eexec"
+ // Get the first binary number and search backwards for "eexec"
+ int len1 = 30;
+
+ // System.out.println("Length1="+len1);
+ while (!byteCmp(originalData, len1 - CURRENTFILE_EEXEC.length, CURRENTFILE_EEXEC)) {
+ len1++;
+ }
+
+ // Skip newline
+ len1++;
+
+ // Length3 is length of the last portion of the file
+ int len3 = 0;
+ len3 -= CLEARTOMARK.length;
+ while (!byteCmp(originalData, originalData.length + len3, CLEARTOMARK)) {
+ len3--;
+ // System.out.println("Len3="+len3);
+ }
+ len3 = -len3;
+ len3++;
+ // Eat 512 zeroes
+ int numZeroes = 0;
+ byte[] ws1 = new byte[]{0x0D}; //CR
+ byte[] ws2 = new byte[]{0x0A}; //LF
+ byte[] ws3 = new byte[]{0x30}; //"0"
+ while ((originalData[originalData.length - len3] == ws1[0]
+ || originalData[originalData.length - len3] == ws2[0]
+ || originalData[originalData.length - len3] == ws3[0])
+ && numZeroes < 512) {
+ len3++;
+ if (originalData[originalData.length - len3] == ws3[0]) {
+ numZeroes++;
+ }
+ }
+ // System.out.println("Length3="+len3);
+
+ //Create the 3 segments
+ byte[] buffer = new byte[len1];
+ System.arraycopy(originalData, 0, buffer, 0, len1);
+ pfb.setHeaderSegment(buffer);
+
+ int len2 = originalData.length - len3 - len1;
+ buffer = new byte[len2];
+ System.arraycopy(originalData, len1, buffer, 0, len2);
+ pfb.setEncryptedSegment(buffer);
+
+ buffer = new byte[len3];
+ System.arraycopy(originalData, len1 + len2, buffer, 0, len3);
+ pfb.setTrailerSegment(buffer);
+ }
+
+ private void parseRAWFormat(PFBData pfb, BufferedInputStream bin)
+ throws IOException {
+ calcLengths(pfb, StreamUtilities.toByteArray(bin, 32768));
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * $Id$
+ * Copyright (C) 2001-2002 The Apache Software Foundation. All rights reserved.
+ * For details on use and redistribution please refer to the
+ * LICENSE file included with these sources.
+ */
+
+package org.apache.fop.fonts.type1;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+
+//Avalon
+import org.apache.avalon.framework.logger.AbstractLogEnabled;
+
+//FOP
+import org.apache.fop.fonts.Glyphs;
+import org.apache.fop.util.StreamUtilities;
+
+/**
+ * This class represents a PFM file (or parts of it) as a Java object.
+ */
+public class PFMFile extends AbstractLogEnabled {
+
+ // Header stuff
+ private String windowsName;
+ private String postscriptName;
+ private short dfItalic;
+ private int dfWeight;
+ private short dfCharSet;
+ private short dfPitchAndFamily;
+ private int dfAvgWidth;
+ private int dfMaxWidth;
+ private int dfMinWidth;
+ private short dfFirstChar;
+ private short dfLastChar;
+
+ // Extension stuff
+ // ---
+
+ // Extend Text Metrics
+ private int etmCapHeight;
+ private int etmXHeight;
+ private int etmLowerCaseAscent;
+ private int etmLowerCaseDescent;
+
+ // Extent table
+ private int[] extentTable;
+
+ private Map kerningTab = new java.util.HashMap();
+
+ /**
+ * Parses a PFM file
+ *
+ * @param inStream The stream from which to read the PFM file.
+ * @throws IOException In case of an I/O problem
+ */
+ public void load(InputStream inStream) throws IOException {
+ final byte[] buf = StreamUtilities.toByteArray(inStream, 8000);
+ final InputStream bufin = new java.io.ByteArrayInputStream(buf);
+ PFMInputStream in = new PFMInputStream(bufin);
+ /*final int version =*/ in.readShort();
+ final long filesize = in.readInt();
+ if (filesize != buf.length) {
+ getLogger().warn("Effective file size is not the same as indicated in the header.");
+ }
+ bufin.reset();
+
+ loadHeader(in);
+ loadExtension(in);
+ }
+
+ /**
+ * Parses the header of the PFM file.
+ *
+ * @param inStream The stream from which to read the PFM file.
+ * @throws IOException In case of an I/O problem
+ */
+ private void loadHeader(PFMInputStream inStream) throws IOException {
+ inStream.skip(80);
+ dfItalic = inStream.readByte();
+ inStream.skip(2);
+ dfWeight = inStream.readShort();
+ dfCharSet = inStream.readByte();
+ inStream.skip(4);
+ dfPitchAndFamily = inStream.readByte();
+ dfAvgWidth = inStream.readShort();
+ dfMaxWidth = inStream.readShort();
+ dfFirstChar = inStream.readByte();
+ dfLastChar = inStream.readByte();
+ inStream.skip(8);
+ long faceOffset = inStream.readInt();
+
+ inStream.reset();
+ inStream.skip(faceOffset);
+ windowsName = inStream.readString();
+
+ inStream.reset();
+ inStream.skip(117);
+ }
+
+ /**
+ * Parses the extension part of the PFM file.
+ *
+ * @param inStream The stream from which to read the PFM file.
+ */
+ private void loadExtension(PFMInputStream inStream) throws IOException {
+ final int size = inStream.readShort();
+ if (size != 30) {
+ getLogger().warn("Size of extension block was expected to be "
+ + "30 bytes, but was " + size + " bytes.");
+ }
+ final long extMetricsOffset = inStream.readInt();
+ final long extentTableOffset = inStream.readInt();
+ inStream.skip(4); //Skip dfOriginTable
+ final long kernPairOffset = inStream.readInt();
+ inStream.skip(4); //Skip dfTrackKernTable
+ long driverInfoOffset = inStream.readInt();
+
+ if (kernPairOffset > 0) {
+ inStream.reset();
+ inStream.skip(kernPairOffset);
+ loadKernPairs(inStream);
+ }
+
+ inStream.reset();
+ inStream.skip(driverInfoOffset);
+ postscriptName = inStream.readString();
+
+ if (extMetricsOffset != 0) {
+ inStream.reset();
+ inStream.skip(extMetricsOffset);
+ loadExtMetrics(inStream);
+ }
+ if (extentTableOffset != 0) {
+ inStream.reset();
+ inStream.skip(extentTableOffset);
+ loadExtentTable(inStream);
+ }
+
+ }
+
+ /**
+ * Parses the kernPairs part of the pfm file
+ *
+ * @param inStream The stream from which to read the PFM file.
+ */
+ private void loadKernPairs(PFMInputStream inStream) throws IOException {
+ int i = inStream.readShort();
+
+
+ getLogger().info(i + " kerning pairs");
+ while (i > 0) {
+ int g1 = (int)inStream.readByte();
+ i--;
+
+ int g2 = (int)inStream.readByte();
+
+ int adj = inStream.readShort();
+ if (adj > 0x8000) {
+ adj = -(0x10000 - adj);
+ }
+ getLogger().debug("Char no: (" + g1 + ", " + g2 + ") kern: " + adj);
+
+ if (getLogger().isDebugEnabled()) {
+ final String glyph1 = Glyphs.TEX8R_GLYPH_NAMES[g1];
+ final String glyph2 = Glyphs.TEX8R_GLYPH_NAMES[g2];
+ getLogger().debug("glyphs: " + glyph1 + ", " + glyph2);
+ }
+
+ Map adjTab = (Map)kerningTab.get(new Integer(g1));
+ if (adjTab == null) {
+ adjTab = new java.util.HashMap();
+ }
+ adjTab.put(new Integer(g2), new Integer(adj));
+ kerningTab.put(new Integer(g1), adjTab);
+ }
+ }
+
+ /**
+ * Parses the extended metrics part of the PFM file.
+ *
+ * @param inStream The stream from which to read the PFM file.
+ */
+ private void loadExtMetrics(PFMInputStream inStream) throws IOException {
+ final int size = inStream.readShort();
+ if (size != 52) {
+ getLogger().warn("Size of extension block was expected to be "
+ + "52 bytes, but was " + size + " bytes.");
+ }
+ inStream.skip(12); //Skip etmPointSize, etmOrientation, etmMasterHeight,
+ //etmMinScale, etmMaxScale, emtMasterUnits
+ etmCapHeight = inStream.readShort();
+ etmXHeight = inStream.readShort();
+ etmLowerCaseAscent = inStream.readShort();
+ etmLowerCaseDescent = inStream.readShort();
+ //Ignore the rest of the values
+ }
+
+ /**
+ * Parses the extent table of the PFM file.
+ *
+ * @param inStream The stream from which to read the PFM file.
+ */
+ private void loadExtentTable(PFMInputStream inStream) throws IOException {
+ extentTable = new int[dfLastChar - dfFirstChar + 1];
+ dfMinWidth = dfMaxWidth;
+ for (short i = dfFirstChar; i <= dfLastChar; i++) {
+ extentTable[i - dfFirstChar] = inStream.readShort();
+ if (extentTable[i - dfFirstChar] < dfMinWidth) {
+ dfMinWidth = extentTable[i - dfFirstChar];
+ }
+ }
+ }
+
+ /**
+ * Returns the Windows name of the font.
+ *
+ * @return The Windows name.
+ */
+ public String getWindowsName() {
+ return windowsName;
+ }
+
+ /**
+ * Return the kerning table. The kerning table is a Map with
+ * strings with glyphnames as keys, containing Maps as value.
+ * The value map contains a glyph name string key and an Integer value
+ *
+ * @return A Map containing the kerning table
+ */
+ public Map getKerning() {
+ return kerningTab;
+ }
+
+ /**
+ * Returns the Postscript name of the font.
+ *
+ * @return The Postscript name.
+ */
+ public String getPostscriptName() {
+ return postscriptName;
+ }
+
+ /**
+ * Returns the charset used for the font.
+ *
+ * @return The charset (0=WinAnsi).
+ */
+ public short getCharSet() {
+ return dfCharSet;
+ }
+
+ /**
+ * Returns the charset of the font as a string.
+ *
+ * @return The name of the charset.
+ */
+ public String getCharSetName() {
+ switch (dfCharSet) {
+ case 0:
+ return "WinAnsi";
+ case 128:
+ return "Shift-JIS (Japanese)";
+ default:
+ return "Unknown";
+ }
+ }
+
+ /**
+ * Returns the number of the character that defines
+ * the first entry in the widths list.
+ *
+ * @return The number of the first character.
+ */
+ public short getFirstChar() {
+ return dfFirstChar;
+ }
+
+ /**
+ * Returns the number of the character that defines
+ * the last entry in the widths list.
+ *
+ * @return The number of the last character.
+ */
+ public short getLastChar() {
+ return dfLastChar;
+ }
+
+ /**
+ * Returns the CapHeight parameter for the font (height of uppercase H).
+ *
+ * @return The CapHeight parameter.
+ */
+ public int getCapHeight() {
+ return etmCapHeight;
+ }
+
+ /**
+ * Returns the XHeight parameter for the font (height of lowercase x).
+ *
+ * @return The CapHeight parameter.
+ */
+ public int getXHeight() {
+ return etmXHeight;
+ }
+
+ /**
+ * Returns the LowerCaseAscent parameter for the font (height of lowercase d).
+ *
+ * @return The LowerCaseAscent parameter.
+ */
+ public int getLowerCaseAscent() {
+ return etmLowerCaseAscent;
+ }
+
+ /**
+ * Returns the LowerCaseDescent parameter for the font (height of lowercase p).
+ *
+ * @return The LowerCaseDescent parameter.
+ */
+ public int getLowerCaseDescent() {
+ return etmLowerCaseDescent;
+ }
+
+ /**
+ * Tells whether the font has proportional character spacing.
+ *
+ * @return ex. true for Times, false for Courier.
+ */
+ public boolean getIsProportional() {
+ return ((dfPitchAndFamily & 1) == 1);
+ }
+
+ /**
+ * Returns the bounding box for the font.
+ * Note: this value is just an approximation,
+ * it does not really exist in the PFM file.
+ *
+ * @return The calculated Font BBox.
+ */
+ public int[] getFontBBox() {
+ int[] bbox = new int[4];
+
+ // Just guessing....
+ if (!getIsProportional() && (dfAvgWidth == dfMaxWidth)) {
+ bbox[0] = -20;
+ } else {
+ bbox[0] = -100;
+ }
+ bbox[1] = -(getLowerCaseDescent() + 5);
+ bbox[2] = dfMaxWidth + 10;
+ bbox[3] = getLowerCaseAscent() + 5;
+ return bbox;
+ }
+
+ /**
+ * Returns the characteristics flags for the font as
+ * needed for a PDF font descriptor (See PDF specs).
+ *
+ * @return The characteristics flags.
+ */
+ public int getFlags() {
+ int flags = 0;
+ if (!getIsProportional()) {
+ flags |= 1;
+ }
+ if ((dfPitchAndFamily & 16) == 16) {
+ flags |= 2;
+ }
+ if ((dfPitchAndFamily & 64) == 64) {
+ flags |= 4;
+ }
+ if (dfCharSet == 0) {
+ flags |= 6;
+ }
+ if (dfItalic != 0) {
+ flags |= 7;
+ }
+ return flags;
+ }
+
+ /**
+ * Returns the width of the dominant vertical stems of the font.
+ * Note: this value is just an approximation,
+ * it does not really exist in the PFM file.
+ *
+ * @return The vertical stem width.
+ */
+ public int getStemV() {
+ // Just guessing....
+ if (dfItalic != 0) {
+ return (int)Math.round(dfMinWidth * 0.25);
+ } else {
+ return (int)Math.round(dfMinWidth * 0.6);
+ }
+ }
+
+ /**
+ * Returns the italic angle of the font.
+ * Note: this value is just an approximation,
+ * it does not really exist in the PFM file.
+ *
+ * @return The italic angle.
+ */
+ public int getItalicAngle() {
+ if (dfItalic != 0) {
+ return -16; // Just guessing....
+ } else {
+ return 0;
+ }
+ }
+
+ /**
+ * Returns the width of a character
+ *
+ * @param which The number of the character for which the width is requested.
+ * @return The width of a character.
+ */
+ public int getCharWidth(short which) {
+ return extentTable[which - dfFirstChar];
+ }
+
+}
--- /dev/null
+/*
+ * $Id$
+ * Copyright (C) 2001-2002 The Apache Software Foundation. All rights reserved.
+ * For details on use and redistribution please refer to the
+ * LICENSE file included with these sources.
+ */
+
+package org.apache.fop.fonts.type1;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.DataInputStream;
+import java.io.InputStreamReader;
+
+/**
+ * This is a helper class for reading PFM files. It defines functions for
+ * extracting specific values out of the stream.
+ */
+public class PFMInputStream extends java.io.FilterInputStream {
+
+ private DataInputStream datain;
+
+ /**
+ * Constructs a PFMInputStream based on an InputStream representing the
+ * PFM file.
+ *
+ * @param in The stream from which to read the PFM file
+ */
+ public PFMInputStream(InputStream in) {
+ super(in);
+ datain = new DataInputStream(in);
+ }
+
+ /**
+ * Parses a one byte value out of the stream.
+ *
+ * @return The value extracted
+ * @throws IOException In case of an I/O problem
+ */
+ public short readByte() throws IOException {
+ short s = datain.readByte();
+ // Now, we've got to trick Java into forgetting the sign
+ int s1 = (((s & 0xF0) >>> 4) << 4) + (s & 0x0F);
+ return (short)s1;
+ }
+
+ /**
+ * Parses a two byte value out of the stream.
+ *
+ * @return The value extracted
+ * @throws IOException In case of an I/O problem
+ */
+ public int readShort() throws IOException {
+ int i = datain.readShort();
+
+ // Change byte order
+ int high = (i & 0xFF00) >>> 8;
+ int low = (i & 0x00FF) << 8;
+ return low + high;
+ }
+
+ /**
+ * Parses a four byte value out of the stream.
+ *
+ * @return The value extracted
+ * @throws IOException In case of an I/O problem
+ */
+ public long readInt() throws IOException {
+ int i = datain.readInt();
+
+ // Change byte order
+ int i1 = (i & 0xFF000000) >>> 24;
+ int i2 = (i & 0x00FF0000) >>> 8;
+ int i3 = (i & 0x0000FF00) << 8;
+ int i4 = (i & 0x000000FF) << 24;
+ return i1 + i2 + i3 + i4;
+ }
+
+ /**
+ * Parses a zero-terminated string out of the stream.
+ *
+ * @return The value extracted
+ * @throws IOException In case of an I/O problem
+ */
+ public String readString() throws IOException {
+ InputStreamReader reader = new InputStreamReader(in, "ISO-8859-1");
+ StringBuffer buf = new StringBuffer();
+ int ch = reader.read();
+ while (ch != 0) {
+ buf.append((char)ch);
+ ch = reader.read();
+ }
+ return buf.toString();
+ }
+
+}
--- /dev/null
+<HTML>
+<TITLE>org.apache.fop.fonts.type1 Package</TITLE>
+<BODY>
+<P>Classes for Adobe Type 1 fonts.</P>
+</BODY>
+</HTML>
\ No newline at end of file