You are viewing a plain text version of this content. The canonical link for it is here.
Posted to fop-dev@xmlgraphics.apache.org by bu...@apache.org on 2003/05/08 14:48:45 UTC

DO NOT REPLY [Bug 19764] New: - PFBParser reports "Could not load the whole segment"

DO NOT REPLY TO THIS EMAIL, BUT PLEASE POST YOUR BUG 
RELATED COMMENTS THROUGH THE WEB INTERFACE AVAILABLE AT
<http://nagoya.apache.org/bugzilla/show_bug.cgi?id=19764>.
ANY REPLY MADE TO THIS MESSAGE WILL NOT BE COLLECTED AND 
INSERTED IN THE BUG DATABASE.

http://nagoya.apache.org/bugzilla/show_bug.cgi?id=19764

PFBParser reports "Could not load the whole segment"

           Summary: PFBParser reports "Could not load the whole segment"
           Product: Fop
           Version: 0.20.5
          Platform: All
        OS/Version: All
            Status: NEW
          Severity: Normal
          Priority: Other
         Component: pdf renderer
        AssignedTo: fop-dev@xml.apache.org
        ReportedBy: germannm@post.ch


If the location of a PFB File is specified with an URL, it happens sometimes
that an IOException with the message "Could not load the whole segment" is thrown. 

I think that i found the bug in the parsePCFormat() method of the class
org.apache.fop.fonts.type1.PCFParser (FOP 0.20.5rc2). In this class, i found
three occurences of the following code:

> bytesRead = din.read(encryptedSegment);
> if (bytesRead != len2) {
>    throw new IOException("Could not load the whole segment");
> }

In my opinion, this does not work, because the read() method of InputStream does
only read as many bytes as are imediately available. It seams, that in a network
connection, not all bytes are imediately available. I think, that the read()
method must be replaced by the readFully() method as follows.

> din.readFully(encryptedSegment);

I've replaced the calls to the read() method with the readFully() method and it
works for me as it should. 

Feel free to contact me, if you need any additional information.

Regards,

Matthias Germann
Swiss Post
Information Technology Services (IT1-5.4)
Webergutstrasse 12
3030 Bern (Zollikofen)
Switzerland

Phone	+41 (0)31 338 07 09
Fax	+41 (0)31 338 53 25
E-Mail	germannm@post.ch

Here is the version of the PFBParser which works for me. Beginn and end of the
modifications are marked with 'XXX'.

/*
 * $Id: PFBParser.java,v 1.1.2.2 2002/12/02 14:04:16 jeremias Exp $
 * 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.tools.IOUtil;

/**
 * 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];
        // XXX beginn modification
        // bytesRead = din.read(headerSegment);
        // if (bytesRead != len1) {
		//           throw new IOException("Could not load the whole segment");
		// }
        din.readFully(headerSegment);
        // XXX end modification
                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];
        // XXX beginn modification
        // bytesRead = din.read(encryptedSegment);
        // if (bytesRead != len2) {
        //     throw new IOException("Could not load the whole segment");
        // }
        din.readFully(encryptedSegment);
        // XXX end modification

        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];
        // XXX beginn modification
		// bytesRead = din.read(trailerSegment);
        // if (bytesRead != len3) {
        //     throw new IOException("Could not load the whole segment");
        // }
		din.readFully(trailerSegment);
		// XXX end modification
        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, IOUtil.toByteArray(bin, 32768));
    }

}

---------------------------------------------------------------------
To unsubscribe, e-mail: fop-dev-unsubscribe@xml.apache.org
For additional commands, email: fop-dev-help@xml.apache.org