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 18 /* $Id: FontFileReader.java 1356646 2012-07-03 09:46:41Z mehdi $ */ 19 20 package org.apache.fop.fonts.truetype; 21 22 import java.io.IOException; 23 import java.io.InputStream; 24 25 import org.apache.commons.io.IOUtils; 26 27 /** 28 * Reads a TrueType font file into a byte array and 29 * provides file like functions for array access. 30 */ 31 public class FontFileReader { 32 33 private final int fsize; // file size 34 private int current; // current position in file 35 private final byte[] file; 36 37 /** 38 * Constructor 39 * 40 * @param in InputStream to read from 41 * @throws IOException In case of an I/O problem 42 */ FontFileReader(InputStream in)43 public FontFileReader(InputStream in) throws IOException { 44 this.file = IOUtils.toByteArray(in); 45 this.fsize = this.file.length; 46 this.current = 0; 47 } 48 49 50 /** 51 * Set current file position to offset 52 * 53 * @param offset The new offset to set 54 * @throws IOException In case of an I/O problem 55 */ seekSet(long offset)56 public void seekSet(long offset) throws IOException { 57 if (offset > fsize || offset < 0) { 58 throw new java.io.EOFException("Reached EOF, file size=" + fsize 59 + " offset=" + offset); 60 } 61 current = (int)offset; 62 } 63 64 /** 65 * Skip a given number of bytes. 66 * 67 * @param add The number of bytes to advance 68 * @throws IOException In case of an I/O problem 69 */ skip(long add)70 public void skip(long add) throws IOException { 71 seekSet(current + add); 72 } 73 74 /** 75 * Returns current file position. 76 * 77 * @return int The current position. 78 */ getCurrentPos()79 public int getCurrentPos() { 80 return current; 81 } 82 83 /** 84 * Returns the size of the file. 85 * 86 * @return int The filesize 87 */ getFileSize()88 public int getFileSize() { 89 return fsize; 90 } 91 92 /** 93 * Read 1 byte. 94 * 95 * @return One byte 96 * @throws IOException If EOF is reached 97 */ read()98 private byte read() throws IOException { 99 if (current >= fsize) { 100 throw new java.io.EOFException("Reached EOF, file size=" + fsize); 101 } 102 103 final byte ret = file[current++]; 104 return ret; 105 } 106 107 /** 108 * Read 1 signed byte. 109 * 110 * @return One byte 111 * @throws IOException If EOF is reached 112 */ readTTFByte()113 public final byte readTTFByte() throws IOException { 114 return read(); 115 } 116 117 /** 118 * Read 1 unsigned byte. 119 * 120 * @return One unsigned byte 121 * @throws IOException If EOF is reached 122 */ readTTFUByte()123 public final int readTTFUByte() throws IOException { 124 final byte buf = read(); 125 126 if (buf < 0) { 127 return (256 + buf); 128 } else { 129 return buf; 130 } 131 } 132 133 /** 134 * Read 2 bytes signed. 135 * 136 * @return One signed short 137 * @throws IOException If EOF is reached 138 */ readTTFShort()139 public final short readTTFShort() throws IOException { 140 final int ret = (readTTFUByte() << 8) + readTTFUByte(); 141 final short sret = (short)ret; 142 return sret; 143 } 144 145 /** 146 * Read 2 bytes unsigned. 147 * 148 * @return One unsigned short 149 * @throws IOException If EOF is reached 150 */ readTTFUShort()151 public final int readTTFUShort() throws IOException { 152 final int ret = (readTTFUByte() << 8) + readTTFUByte(); 153 return ret; 154 } 155 156 /** 157 * Write a USHort at a given position. 158 * 159 * @param pos The absolute position to write to 160 * @param val The value to write 161 * @throws IOException If EOF is reached 162 */ writeTTFUShort(long pos, int val)163 public final void writeTTFUShort(long pos, int val) throws IOException { 164 if ((pos + 2) > fsize) { 165 throw new java.io.EOFException("Reached EOF"); 166 } 167 final byte b1 = (byte)((val >> 8) & 0xff); 168 final byte b2 = (byte)(val & 0xff); 169 final int fileIndex = (int) pos; 170 file[fileIndex] = b1; 171 file[fileIndex + 1] = b2; 172 } 173 174 /** 175 * Read 2 bytes signed at position pos without changing current position. 176 * 177 * @param pos The absolute position to read from 178 * @return One signed short 179 * @throws IOException If EOF is reached 180 */ readTTFShort(long pos)181 public final short readTTFShort(long pos) throws IOException { 182 final long cp = getCurrentPos(); 183 seekSet(pos); 184 final short ret = readTTFShort(); 185 seekSet(cp); 186 return ret; 187 } 188 189 /** 190 * Read 2 bytes unsigned at position pos without changing current position. 191 * 192 * @param pos The absolute position to read from 193 * @return One unsigned short 194 * @throws IOException If EOF is reached 195 */ readTTFUShort(long pos)196 public final int readTTFUShort(long pos) throws IOException { 197 long cp = getCurrentPos(); 198 seekSet(pos); 199 int ret = readTTFUShort(); 200 seekSet(cp); 201 return ret; 202 } 203 204 /** 205 * Read 4 bytes. 206 * 207 * @return One signed integer 208 * @throws IOException If EOF is reached 209 */ readTTFLong()210 public final int readTTFLong() throws IOException { 211 long ret = readTTFUByte(); // << 8; 212 ret = (ret << 8) + readTTFUByte(); 213 ret = (ret << 8) + readTTFUByte(); 214 ret = (ret << 8) + readTTFUByte(); 215 216 return (int)ret; 217 } 218 219 /** 220 * Read 4 bytes. 221 * 222 * @return One unsigned integer 223 * @throws IOException If EOF is reached 224 */ readTTFULong()225 public final long readTTFULong() throws IOException { 226 long ret = readTTFUByte(); 227 ret = (ret << 8) + readTTFUByte(); 228 ret = (ret << 8) + readTTFUByte(); 229 ret = (ret << 8) + readTTFUByte(); 230 231 return ret; 232 } 233 234 /** 235 * Read a NUL terminated ISO-8859-1 string. 236 * 237 * @return A String 238 * @throws IOException If EOF is reached 239 */ readTTFString()240 public final String readTTFString() throws IOException { 241 int i = current; 242 while (file[i++] != 0) { 243 if (i >= fsize) { 244 throw new java.io.EOFException("Reached EOF, file size=" 245 + fsize); 246 } 247 } 248 249 byte[] tmp = new byte[i - current - 1]; 250 System.arraycopy(file, current, tmp, 0, i - current - 1); 251 return new String(tmp, "ISO-8859-1"); 252 } 253 254 255 /** 256 * Read an ISO-8859-1 string of len bytes. 257 * 258 * @param len The length of the string to read 259 * @return A String 260 * @throws IOException If EOF is reached 261 */ readTTFString(int len)262 public final String readTTFString(int len) throws IOException { 263 if ((len + current) > fsize) { 264 throw new java.io.EOFException("Reached EOF, file size=" + fsize); 265 } 266 267 byte[] tmp = new byte[len]; 268 System.arraycopy(file, current, tmp, 0, len); 269 current += len; 270 final String encoding; 271 if ((tmp.length > 0) && (tmp[0] == 0)) { 272 encoding = "UTF-16BE"; 273 } else { 274 encoding = "ISO-8859-1"; 275 } 276 return new String(tmp, encoding); 277 } 278 279 /** 280 * Read an ISO-8859-1 string of len bytes. 281 * 282 * @param len The length of the string to read 283 * @param encodingID the string encoding id (presently ignored; always uses UTF-16BE) 284 * @return A String 285 * @throws IOException If EOF is reached 286 */ readTTFString(int len, int encodingID)287 public final String readTTFString(int len, int encodingID) throws IOException { 288 if ((len + current) > fsize) { 289 throw new java.io.EOFException("Reached EOF, file size=" + fsize); 290 } 291 292 byte[] tmp = new byte[len]; 293 System.arraycopy(file, current, tmp, 0, len); 294 current += len; 295 final String encoding; 296 encoding = "UTF-16BE"; //Use this for all known encoding IDs for now 297 return new String(tmp, encoding); 298 } 299 300 /** 301 * Return a copy of the internal array 302 * 303 * @param offset The absolute offset to start reading from 304 * @param length The number of bytes to read 305 * @return An array of bytes 306 * @throws IOException if out of bounds 307 */ getBytes(int offset, int length)308 public byte[] getBytes(int offset, 309 int length) throws IOException { 310 if ((offset + length) > fsize) { 311 throw new java.io.IOException("Reached EOF"); 312 } 313 314 byte[] ret = new byte[length]; 315 System.arraycopy(file, offset, ret, 0, length); 316 return ret; 317 } 318 /** 319 * Returns the full byte array representation of the file. 320 * @return byte array. 321 */ getAllBytes()322 public byte[] getAllBytes() { 323 return file; 324 } 325 } 326