123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202 |
- /*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- /* $Id$ */
-
- package org.apache.fop.fonts.type1;
-
- import java.io.BufferedInputStream;
- import java.io.DataInputStream;
- import java.io.IOException;
- import java.io.InputStream;
-
- import org.apache.commons.io.IOUtils;
-
- /**
- * 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 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;
-
- //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];
- din.readFully(headerSegment);
- 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];
- din.readFully(encryptedSegment);
- 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];
- din.readFully(trailerSegment);
- 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 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, IOUtils.toByteArray(bin));
- }
-
- }
|