You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

PFBParser.java 6.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. /* $Id$ */
  18. package org.apache.fop.fonts.type1;
  19. import java.io.BufferedInputStream;
  20. import java.io.DataInputStream;
  21. import java.io.IOException;
  22. import java.io.InputStream;
  23. import org.apache.commons.io.IOUtils;
  24. /**
  25. * This class represents a parser for Adobe Type 1 PFB files.
  26. *
  27. * @see PFBData
  28. */
  29. public class PFBParser {
  30. private static final byte[] CURRENTFILE_EEXEC;
  31. private static final byte[] CLEARTOMARK;
  32. static {
  33. try {
  34. CURRENTFILE_EEXEC = "currentfile eexec".getBytes("US-ASCII");
  35. CLEARTOMARK = "cleartomark".getBytes("US-ASCII");
  36. } catch (java.io.UnsupportedEncodingException e) {
  37. throw new RuntimeException("Incompatible VM. It doesn't support the US-ASCII encoding");
  38. }
  39. }
  40. /**
  41. * Parses a PFB file into a PFBData object.
  42. * @param in InputStream to load the PFB file from
  43. * @return PFBData memory representation of the font
  44. * @throws IOException In case of an I/O problem
  45. */
  46. public PFBData parsePFB(InputStream in) throws IOException {
  47. PFBData pfb = new PFBData();
  48. BufferedInputStream bin = new BufferedInputStream(in);
  49. DataInputStream din = new DataInputStream(bin);
  50. din.mark(32);
  51. int firstByte = din.readUnsignedByte();
  52. din.reset();
  53. if (firstByte == 128) {
  54. pfb.setPFBFormat(PFBData.PFB_PC);
  55. parsePCFormat(pfb, din);
  56. } else {
  57. pfb.setPFBFormat(PFBData.PFB_RAW);
  58. parseRAWFormat(pfb, bin);
  59. }
  60. return pfb;
  61. }
  62. private static int swapInteger(final int value) {
  63. return (((value >> 0) & 0xff) << 24)
  64. + (((value >> 8) & 0xff) << 16)
  65. + (((value >> 16) & 0xff) << 8)
  66. + (((value >> 24) & 0xff) << 0);
  67. }
  68. private void parsePCFormat(PFBData pfb, DataInputStream din) throws IOException {
  69. int segmentHead;
  70. int segmentType;
  71. //Read first segment
  72. segmentHead = din.readUnsignedByte();
  73. if (segmentHead != 128) {
  74. throw new IOException("Invalid file format. Expected ASCII 80hex");
  75. }
  76. segmentType = din.readUnsignedByte(); //Read
  77. int len1 = swapInteger(din.readInt());
  78. byte[] headerSegment = new byte[len1];
  79. din.readFully(headerSegment);
  80. pfb.setHeaderSegment(headerSegment);
  81. //Read second segment
  82. segmentHead = din.readUnsignedByte();
  83. if (segmentHead != 128) {
  84. throw new IOException("Invalid file format. Expected ASCII 80hex");
  85. }
  86. segmentType = din.readUnsignedByte();
  87. int len2 = swapInteger(din.readInt());
  88. byte[] encryptedSegment = new byte[len2];
  89. din.readFully(encryptedSegment);
  90. pfb.setEncryptedSegment(encryptedSegment);
  91. //Read third segment
  92. segmentHead = din.readUnsignedByte();
  93. if (segmentHead != 128) {
  94. throw new IOException("Invalid file format. Expected ASCII 80hex");
  95. }
  96. segmentType = din.readUnsignedByte();
  97. int len3 = swapInteger(din.readInt());
  98. byte[] trailerSegment = new byte[len3];
  99. din.readFully(trailerSegment);
  100. pfb.setTrailerSegment(trailerSegment);
  101. //Read EOF indicator
  102. segmentHead = din.readUnsignedByte();
  103. if (segmentHead != 128) {
  104. throw new IOException("Invalid file format. Expected ASCII 80hex");
  105. }
  106. segmentType = din.readUnsignedByte();
  107. if (segmentType != 3) {
  108. throw new IOException("Expected segment type 3, but found: " + segmentType);
  109. }
  110. }
  111. private static boolean byteCmp(byte[] src, int srcOffset, byte[] cmp) {
  112. for (int i = 0; i < cmp.length; i++) {
  113. // System.out.println("Compare: " + src[srcOffset + i] + " " + cmp[i]);
  114. if (src[srcOffset + i] != cmp[i]) {
  115. return false;
  116. }
  117. }
  118. return true;
  119. }
  120. private void calcLengths(PFBData pfb, byte[] originalData) {
  121. // Calculate length 1 and 3
  122. // System.out.println ("Checking font, size = "+originalData.length);
  123. // Length1 is the size of the initial ascii portion
  124. // search for "currentfile eexec"
  125. // Get the first binary number and search backwards for "eexec"
  126. int len1 = 30;
  127. // System.out.println("Length1="+len1);
  128. while (!byteCmp(originalData, len1 - CURRENTFILE_EEXEC.length, CURRENTFILE_EEXEC)) {
  129. len1++;
  130. }
  131. // Skip newline
  132. len1++;
  133. // Length3 is length of the last portion of the file
  134. int len3 = 0;
  135. len3 -= CLEARTOMARK.length;
  136. while (!byteCmp(originalData, originalData.length + len3, CLEARTOMARK)) {
  137. len3--;
  138. // System.out.println("Len3="+len3);
  139. }
  140. len3 = -len3;
  141. len3++;
  142. // Eat 512 zeroes
  143. int numZeroes = 0;
  144. byte[] ws1 = new byte[]{0x0D}; //CR
  145. byte[] ws2 = new byte[]{0x0A}; //LF
  146. byte[] ws3 = new byte[]{0x30}; //"0"
  147. while ((originalData[originalData.length - len3] == ws1[0]
  148. || originalData[originalData.length - len3] == ws2[0]
  149. || originalData[originalData.length - len3] == ws3[0])
  150. && numZeroes < 512) {
  151. len3++;
  152. if (originalData[originalData.length - len3] == ws3[0]) {
  153. numZeroes++;
  154. }
  155. }
  156. // System.out.println("Length3="+len3);
  157. //Create the 3 segments
  158. byte[] buffer = new byte[len1];
  159. System.arraycopy(originalData, 0, buffer, 0, len1);
  160. pfb.setHeaderSegment(buffer);
  161. int len2 = originalData.length - len3 - len1;
  162. buffer = new byte[len2];
  163. System.arraycopy(originalData, len1, buffer, 0, len2);
  164. pfb.setEncryptedSegment(buffer);
  165. buffer = new byte[len3];
  166. System.arraycopy(originalData, len1 + len2, buffer, 0, len3);
  167. pfb.setTrailerSegment(buffer);
  168. }
  169. private void parseRAWFormat(PFBData pfb, BufferedInputStream bin)
  170. throws IOException {
  171. calcLengths(pfb, IOUtils.toByteArray(bin));
  172. }
  173. }