![JAR search and dependency download from the Maven repository](/logo.png)
com.adobe.fontengine.font.FontByteArray Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aem-sdk-api Show documentation
Show all versions of aem-sdk-api Show documentation
The Adobe Experience Manager SDK
/*
*
* File: FontByteArray.java
*
*
* ADOBE CONFIDENTIAL
* ___________________
*
* Copyright 2004-2005 Adobe Systems Incorporated
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains the property of
* Adobe Systems Incorporated and its suppliers, if any. The intellectual
* and technical concepts contained herein are proprietary to Adobe Systems
* Incorporated and its suppliers and may be covered by U.S. and Foreign
* Patents, patents in process, and are protected by trade secret or
* copyright law. Dissemination of this information or reproduction of this
* material is strictly forbidden unless prior written permission is obtained
* from Adobe Systems Incorporated.
*
*/
package com.adobe.fontengine.font;
import java.io.IOException;
import java.io.OutputStream;
/** A sequence of bytes in an OpenType font file, with
methods to access the basic types.
The return type of the various accessors for the integral
types is int
whenever the OpenType type fits
in [-2^31 .. 2^31-1], long
otherwise. The
only exception is getuint32asint
*/
public class FontByteArray
{
static final private int kMaxBufferLength = 0x32000;
static final private int kBufferGrowthAmount = 0x2000;
/** The bytes. */
private byte[][] data;
private int size;
private int used;
public FontByteArray(int size)
{
this.size = size;
this.used = 0;
// only need to add 1 iff the size is not an exact multiple of the max buffer length
int numberBuffers = (size / kMaxBufferLength) + (((size % kMaxBufferLength) == 0) ? 0 : 1);
this.data = new byte[numberBuffers][];
for (int buffer = 0; buffer < numberBuffers; buffer++)
{
int bufferSize = Math.min(kMaxBufferLength, size);
this.data[buffer] = new byte[bufferSize];
size -= bufferSize;
}
}
public FontByteArray(FontInputStream in, int inStreamSize) throws IOException, InvalidFontException
{
this(inStreamSize);
addBytes(in, inStreamSize, 0);
}
protected FontByteArray(FontByteArray original, boolean copyData)
{
this.size = original.size;
this.used = original.used;
if (copyData)
{
this.data = new byte[original.data.length][];
for (int i = 0; i < original.data.length; i++)
{
this.data[i] = original.data[i].clone();
}
} else
{
this.data = original.data;
original.data = null;
}
}
void addBytes(FontInputStream in, int inStreamSize, int offset) throws IOException, InvalidFontException
{
int buffer = offset/kMaxBufferLength;
int subOffset = offset % kMaxBufferLength;
for (; buffer < this.data.length; buffer++)
{
int bytesRead = 0;
int toRead = Math.min(this.data[buffer].length - subOffset, inStreamSize);
while (toRead > 0)
{
int n = in.read (data[buffer], bytesRead+subOffset, toRead);
if (n == -1)
{
throw new InvalidFontException ("not enough data");
}
toRead -= n;
bytesRead += n;
subOffset = 0;
}
this.used += bytesRead;
}
}
public final int getSize()
{
return this.used;
}
// It is useful to keep in mind the guarantees offered by the
// Java language when reading the code below.
// - a byte
is a signed integer, in the range [-128, 127]
// - an int
is a signed integer, in the range [-2^31, 2^31-1]
// - all integral types are represented using 2's complement
// - undecorated literals are of type int;
// a literal with an 'L' or 'l' suffix is of type long
// - most binary operators involve promotion of their arguments; for integral types,
// this boils down to: if either argument is a long then the
// other is promoted to long, otherwise if either argument is
// an int then the other is promoted to int
// - narrowing of integral types is just a bit masking operation
// As a consequence, if b is a byte, then
// 'b & 0xff' is an int (because 0xff is and int, and b is
// promoted to an int); and the value of that expression is
// the value of the byte as if interpreted as an unsigned byte.
// Another consequence is that '(byte)0xaa' just sticks the bits
// 10101010 in a byte; the value of that expression is -86;
// and the value of '((byte)0xaa) & 0xff' is 0xaa.
/** return the uint8 at index
in the table */
protected final int getRawByte (int index)
throws InvalidFontException
{
if (index < 0 || index >= this.size)
{
throw new InvalidFontException("Invalid index = " + index);
}
return data [index / kMaxBufferLength][index % kMaxBufferLength] & 0xff;
}
/** return the uint8 at index
in the table */
protected final int getSignedRawByte (int index)
throws InvalidFontException
{
if (index < 0 || index >= this.size)
{
throw new InvalidFontException("Invalid index = " + index);
}
return data [index / kMaxBufferLength][index % kMaxBufferLength];
}
/**
* Copy 'fromBufferLength' bytes, starting at 'fromBufferOffset', from 'this' to 'toBufferOffset' in 'toArray'.
*/
public final void getBytes(FontByteArray toArray, int toBufferOffset, int fromBufferOffset, int fromBufferLength)
{
int bytesCopied = 0;
while (bytesCopied < fromBufferLength)
{
int fromBuffer = (fromBufferOffset + bytesCopied) / kMaxBufferLength;
int fromBufferSubOffset = (fromBufferOffset + bytesCopied) % kMaxBufferLength;
int toBuffer = (toBufferOffset + bytesCopied) / kMaxBufferLength;
int toBufferSubOffset = (toBufferOffset + bytesCopied) % kMaxBufferLength;
int bytesToCopy = Math.min(fromBufferLength - bytesCopied, this.data[fromBuffer].length - fromBufferSubOffset); //see how much is left in the source
if (bytesToCopy <= 0)
throw new ArrayIndexOutOfBoundsException("Source buffer is too small");
bytesToCopy = Math.min(bytesToCopy, toArray.data[toBuffer].length - toBufferSubOffset); // see how much is left in the dest
System.arraycopy(this.data[fromBuffer], fromBufferSubOffset, toArray.data[toBuffer], toBufferSubOffset, bytesToCopy);
bytesCopied += bytesToCopy;
}
}
public final byte[] getBytes(int index, int length)
{
// TODO - check parameters
byte[] b = new byte[length];
int bytesCopied = 0;
while (bytesCopied < length)
{
int buffer = (index + bytesCopied) / kMaxBufferLength;
int offset = (index + bytesCopied) % kMaxBufferLength;
int bytesToCopy = Math.min(length - bytesCopied, this.data[buffer].length - offset);
System.arraycopy(this.data[buffer], offset, b, bytesCopied, bytesToCopy);
bytesCopied += bytesToCopy;
}
return b;
}
public void write(OutputStream out)
throws IOException
{
for (int buffer = 0, dataWritten = 0; dataWritten < this.used; buffer++)
{
int dataToWrite = Math.min(this.used - dataWritten, kMaxBufferLength);
out.write(this.data[buffer], 0, dataToWrite);
dataWritten += dataToWrite;
}
}
/* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
public boolean equals(Object other)
{
if (this == other)
{
return true;
}
if (!(other instanceof FontByteArray))
{
return false;
}
FontByteArray otherBA = (FontByteArray) other;
if (otherBA.used != this.used)
{
return false;
}
for (int i = 0; i < this.used; i++)
{
try
{
if (this.getRawByte(i) != otherBA.getRawByte(i))
{
return false;
}
}
catch (InvalidFontException e)
{
throw new RuntimeException("Unable to get data at index = " + i, e);
}
}
return true;
}
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
public int hashCode()
{
// let's just look at the first few bytes
// if we use too many the early ones won't count anyways as their contribution will be
// pushed off the left hand edge
int hashCode = this.used;
int bytesToCheck = Math.min(this.used, 10);
for (int i = 0; i < bytesToCheck; i++)
{
hashCode = hashCode * 31 + this.data[0][1];
}
return hashCode;
}
protected static class FontByteArrayBuilder
{
protected FontByteArray byteArray;
protected FontByteArrayBuilder(FontByteArray byteArray)
{
this.byteArray = byteArray;
}
protected final void setRawByte (int index, int value)
{
ensureCapacity(index+1);
byteArray.data [index / kMaxBufferLength][index % kMaxBufferLength] = (byte) (value & 0xff);
byteArray.used = Math.max(byteArray.used, index + 1);
}
protected final int getRawByte(int index)
{
return byteArray.data [index / kMaxBufferLength][index % kMaxBufferLength];
}
protected final void appendRawByte (int value)
{
int index = byteArray.used;
ensureCapacity(index + 1);
setRawByte(index, value);
}
public int getSize()
{
return byteArray.getSize();
}
/**
*
* @param position start copying into 'this' at position
* @param other buffer to copy from
* @param start start copying from 'other' at 'start'
* @param length number of bytes to copy
* @throws InvalidFontException
*/
public final void replace(int position, FontByteArray other, int start, int length)
throws InvalidFontException
{
ensureCapacity(position + length);
if (length > 0)
{
other.getBytes(this.byteArray, position, start, length);
byteArray.used = Math.max(byteArray.used, position+length);
}
}
public final void replace(int position, byte[] b, int start, int length)
{
ensureCapacity(position + length);
// TODO - check parameters
for (int i = 0; i < length; i++)
{
// TODO - use underlying arrays
setRawByte(position + i, b[i + start]);
}
}
public final void append(FontByteArray other, int start, int length)
throws InvalidFontException
{
replace(byteArray.used, other, start, length);
}
public final void append(byte[] b, int start, int length)
{
replace(byteArray.used, b, start, length);
}
public final void append(FontInputStream in, int inStreamSize, int offset) throws IOException, InvalidFontException
{
byteArray.addBytes(in, inStreamSize, offset);
}
public final void ensureCapacity(int minCapacity)
{
if (minCapacity > byteArray.size)
{
grow(minCapacity);
}
}
public final void ensureFreeSpace(int minSpace)
{
if ((byteArray.size - byteArray.used) < minSpace)
{
grow(byteArray.used + minSpace);
}
}
// This has grow-to semantics where the size is the total size of the data, not an incremental size.
private final void grow(int size)
{
int lastBufferNumber = byteArray.data.length - 1;
// First grow the last buffer if we can
if (byteArray.data[lastBufferNumber].length != kMaxBufferLength)
{
// grow by either default grow size or requested difference, which ever is larger, capped to our max.
int growSize = Math.max(size-byteArray.size, kBufferGrowthAmount);
int newBufferSize = byteArray.data[lastBufferNumber].length + growSize;
newBufferSize = Math.min(newBufferSize, kMaxBufferLength);
byte[] newBuffer = new byte[newBufferSize];
// account for the change in size of the last buffer
byteArray.size += (newBufferSize - byteArray.data[lastBufferNumber].length);
System.arraycopy(byteArray.data[lastBufferNumber], 0, newBuffer, 0, byteArray.data[lastBufferNumber].length);
byteArray.data[lastBufferNumber] = newBuffer;
}
// Second add as many buffers as needed
// only need to add 1 iff the size is not an exact multiple of the max buffer length
int numberBuffers = (size / kMaxBufferLength) + (((size % kMaxBufferLength) == 0) ? 0 : 1);
if (numberBuffers != byteArray.data.length)
{
byte[][] buffers = new byte[numberBuffers][];
for (int buffer = 0; buffer < numberBuffers; buffer++)
{
if (buffer <= lastBufferNumber)
{
// add reference to already existing buffer
buffers[buffer] = byteArray.data[buffer];
size -= buffers[buffer].length;
} else {
// add a new buffer on the end
int bufferSize = Math.min(kMaxBufferLength, size);
buffers[buffer] = new byte[bufferSize];
size -= bufferSize;
byteArray.size += bufferSize;
}
}
byteArray.data = buffers;
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy