Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.jpedal.fonts.Type1 Maven / Gradle / Ivy
/*
* ===========================================
* Java Pdf Extraction Decoding Access Library
* ===========================================
*
* Project Info: http://www.idrsolutions.com
* Help section for developers at http://www.idrsolutions.com/support/
*
* (C) Copyright 1997-2017 IDRsolutions and Contributors.
*
* This file is part of JPedal/JPDF2HTML5
*
@LICENSE@
*
* ---------------
* Type1.java
* ---------------
*/
package org.jpedal.fonts;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.StringReader;
import java.util.StringTokenizer;
import org.jpedal.io.types.StreamReaderUtils;
import org.jpedal.utils.LogWriter;
import org.jpedal.utils.repositories.FastByteArrayOutputStream;
/**
* handles type1 specifics
*/
public class Type1 extends PdfFont {
protected boolean isCID;
protected boolean isCIDROS;
/**
* constant used in eexec and charset decode
*/
private static final int c1 = 52845;
/**
* constant used in eexec and charset decode
*/
private static final int c2 = 22719;
//number of random bytes in stream to ignore
private int skipBytes = 4;
//Private DICT values
protected int[] blueValues;
protected int[] otherBlues;
protected int[] familyBlues;
protected int[] familyOtherBlues;
protected Double blueScale;
protected Integer blueShift;
protected Integer blueFuzz;
protected Double stdHW;
protected Double stdVW;
protected int[] stemSnapH;
protected int[] stemSnapV;
protected Boolean forceBold;
protected Integer languageGroup;
/**
* lookup for 1 byte draw commands
*/
public static final String T1CcharCodes1Byte[] = {"-Reserved-", "hstem", "-Reserved-", "vstem",
"vmoveto", "rlineto", "hlineto", "vlineto",
"rrcurveto", "closePathT1", "callsubr", "return",
"escape", "hsbwT1", "endchar", "-Reserved-",
"blend", "-Reserved-", "hstemhm", "hintmask",
"cntrmask", "rmoveto", "hmoveto", "vstemhm",
"rcurveline", "rlinecurve", "vvcurveto", "hhcurveto",
"intint", "callgsubr", "vhcurveto", "hvcurveto"};
/**
* lookup for 2 byte draw commands
*/
public static final String T1C[] = {"dotSection", "vstem3", "hstem3", "and",
"or", "not", "seacT1", "swbT1",
"store", "abs", "add", "sub",
"div", "load", "neg", "eq",
"callothersubT1", "pop", "drop", "-Reserved-",
"put", "get", "ifelse", "random",
"mul", "-Reserved-", "sqrt", "dup",
"exch", "index", "roll", "-Reserved-",
"-Reserved-", "setcurrentpointT1", "hflex", "flex",
"hflex1", "flex1"};
//flag if we store reverse map for index to CMAP (use dbt OTF conversion)
boolean trackIndices;
public static final char[] DEF_CHARS = "def".toCharArray();
/*
* creates glyph from truetype font commands
*
//protected T1Glyph getType1Glyph(T1Glyph current_path,int rawInt, String displayValue, float currentWidth) {
protected T1Glyph getType1Glyph(double x,double y,T1Glyph current_path,String glyph,int rawInt, String displayValue, float currentWidth,boolean isRecursive) {
boolean test=false;
byte[] glyphStream=(byte[]) charStrings.get(glyph);
System.out.println(glyph+" "+glyphStream.length+" "+charStrings);
for(int i=0;i31 | (nextVal==28)) { //number,SID or array
//vector used so several values can be returned
Vector v = getInt(glyphStream, p);
op[opCount] = ((Double) v.elementAt(0)).doubleValue();
p = ((Integer) v.elementAt(1)).intValue();
opCount++;
}else{ // operator
lastKey=key;
key = nextVal;
p++;
currentOp=0;
if(test){
for(int j=0;jMath.abs(dy));
for(int points=0;points<6;points=points+2){ //first curve
x += op[points];
y += op[points+1];
pt[points]=(float) x;
pt[points+1]=(float) y;
}
current_path.curveTo(pt[0],pt[1],pt[2],pt[3],pt[4],pt[5]);
for(int points=0;points<4;points=points+2){ //second curve
x += op[points+6];
y += op[points+7];
pt[points]=(float) x;
pt[points+1]=(float) y;
}
// last point
if ( isHorizontal ){
x += op[10];
y = y1;
}else{
x = x1;
y += op[10];
}
pt[4]=(float) x;
pt[5]=(float) y;
current_path.curveTo(pt[0],pt[1],pt[2],pt[3],pt[4],pt[5]);
}else if(test){
System.out.println(p+" "+key+" "+charCodes2Byte[key]+" <2<<"+op);
}
} else {
if(test)
System.out.println(charCodes1Byte[key]+" "+key);
if(key==0){ //reserved
}else if((key==1)|(key==3)|(key==18)|(key==23)){ //hstem vstem hstemhm vstemhm
hintCount+=opCount/2;
}else if(key==4){ //vmoveto
if((isFirst)&&(opCount==2))
currentOp++;
y=y+op[currentOp];
current_path.moveTo((float)x,(float)y);
}else if((key==5)){ //rlineto
int lineCount=opCount/2;
while ( lineCount > 0 ){
x += op[currentOp];
y += op[currentOp+1];
current_path.lineTo((float)x,(float)y);
currentOp += 2;
lineCount--;
}
}else if((key==6)|(key==7)){ //hlineto or vlineto
boolean isHor = ( key==6 );
int start=0;
while (start 0 ){
float[] coords=new float[6];
x += op[currentOp];
y += op[currentOp+1];
coords[0]=(float) x;
coords[1]=(float) y;
x += op[currentOp+2];
y += op[currentOp+3];
coords[2]=(float) x;
coords[3]=(float) y;
x += op[currentOp+4];
y += op[currentOp+5];
coords[4]=(float) x;
coords[5]=(float) y;
current_path.curveTo(coords[0],coords[1],coords[2],coords[3],coords[4],coords[5]);
currentOp += 6;
curveCount--;
}
}else if(key==10){ //callsubr
System.out.println("callsubr");
}else if(key==11){ //return
}else if(key==14){ //endchar
if(opCount==5){ //allow for width and 4 chars
opCount--;
currentOp++;
}
if(opCount==4){
StandardFonts.checkLoaded(StandardFonts.STD);
float adx=(float)(x+op[currentOp]);
float ady=(float)(y+op[currentOp+1]);
String bchar=StandardFonts.getUnicodeChar(StandardFonts.STD ,(int)op[currentOp+2]);
String achar=StandardFonts.getUnicodeChar(StandardFonts.STD ,(int)op[currentOp+3]);
current_path=getType1CGlyph(0,0,current_path,bchar,rawInt, "", 0,true);
current_path.closePath();
current_path.moveTo(adx,ady);
current_path=(getType1CGlyph(adx,ady,current_path,achar,rawInt, "", 0,true));
}else
current_path.closePath();
p =dicEnd;
}else if(key==16){ //blend
}else if((key==19)|(key==20)){ //hintmask //cntrmask
if((lastKey==18)|(lastKey==1))
hintCount+=opCount/2;
int count=hintCount;
while(count>0){
p++;
count=count-8;
}
}else if(key==21){ //rmoveto
if((isFirst)&&(opCount==3))
currentOp++;
x=x+op[currentOp];
y=y+op[currentOp+1];
current_path.moveTo((float)x,(float)y);
}else if(key==22){ //hmoveto
if((isFirst)&&(opCount==2))
currentOp++;
x=x+op[currentOp];
current_path.moveTo((float)x,(float)y);
}else if(key==24){ //rcurveline
//curves
int curveCount=( opCount - 2 ) / 6;
while ( curveCount > 0 ){
float[] coords=new float[6];
x += op[currentOp];
y += op[currentOp+1];
coords[0]=(float) x;
coords[1]=(float) y;
x += op[currentOp+2];
y += op[currentOp+3];
coords[2]=(float) x;
coords[3]=(float) y;
x += op[currentOp+4];
y += op[currentOp+5];
coords[4]=(float) x;
coords[5]=(float) y;
current_path.curveTo(coords[0],coords[1],coords[2],coords[3],coords[4],coords[5]);
currentOp += 6;
curveCount--;
}
// line
x += op[currentOp];
y += op[currentOp+1];
current_path.lineTo((float)x,(float)y);
currentOp += 2;
}else if(key==25){ //rlinecurve
//lines
int lineCount=( opCount - 6 ) / 2;
while ( lineCount > 0 ){
x += op[currentOp];
y += op[currentOp+1];
current_path.lineTo((float)x,(float)y);
currentOp += 2;
lineCount--;
}
//curves
float[] coords=new float[6];
x += op[currentOp];
y += op[currentOp+1];
coords[0]=(float) x;
coords[1]=(float) y;
x += op[currentOp+2];
y += op[currentOp+3];
coords[2]=(float) x;
coords[3]=(float) y;
x += op[currentOp+4];
y += op[currentOp+5];
coords[4]=(float) x;
coords[5]=(float) y;
current_path.curveTo(coords[0],coords[1],coords[2],coords[3],coords[4],coords[5]);
currentOp += 6;
}else if((key==26)|(key==27)){ //vvcurve hhcurveto
boolean isVV=(key==26);
if ( (opCount & 1) ==1 ){
if(isVV)
x += op[0];
else
y += op[0];
currentOp++;
}
//note odd co-ord order
while (currentOp= 4 ){
opCount -= 4;
if ( isHor )
x += op[currentOp];
else
y += op[currentOp];
pt[0]=(float) x;
pt[1]=(float) y;
x += op[currentOp+1];
y += op[currentOp+2];
pt[2]=(float) x;
pt[3]=(float) y;
if ( isHor ){
y += op[currentOp+3];
if ( opCount ==1 )
x += op[currentOp+4];
}else{
x += op[currentOp+3];
if ( opCount == 1 )
y += op[currentOp+4];
}
pt[4]=(float) x;
pt[5]=(float) y;
current_path.curveTo(pt[0],pt[1],pt[2],pt[3],pt[4],pt[5]);
currentOp += 4;
isHor = !isHor;
}
}else{
System.out.println(p+">>>>>"+hintCount+">>>>>>"+key+" "+charCodes1Byte[key]+" <1<<"+op);
for(int j=0;j 0) {
isFontEmbedded = true;
}
glyphs.setFontEmbedded(true);
}
/**
* Handle encoding for type1 fonts
*/
protected final void readType1FontFile(final byte[] content) throws Exception {
LogWriter.writeLog("Embedded Type1 font used " + getBaseFontName());
final BufferedReader br = new BufferedReader(new StringReader(new String(content)));
String line;
while (true) {
line = br.readLine();
if (line == null) {
break;
}
if (line.startsWith("/Encoding 256 array")) {
readDiffEncoding(br);
} else if (line.startsWith("/lenIV")) {
final StringTokenizer vals = new StringTokenizer(line);
vals.nextToken(); //drop first value
skipBytes = Integer.parseInt(vals.nextToken());
} else if (line.contains("/FontMatrix")) {
int startP;
final int endP;
String values = "";
startP = line.indexOf('[');
if (startP != -1) {
endP = line.indexOf(']');
values = line.substring(startP + 1, endP);
} else {
startP = line.indexOf('{');
if (startP != -1) {
endP = line.indexOf('}');
values = line.substring(startP + 1, endP);
}
}
final StringTokenizer matrixValues = new StringTokenizer(values);
for (int i = 0; i < 6; i++) {
FontMatrix[i] = Double.parseDouble(matrixValues.nextToken());
}
}
}
if (br != null) {
try {
br.close();
} catch (final Exception e) {
LogWriter.writeLog("Exception " + e + " closing stream");
}
}
//read the eexec part (which can be binary or ascii
int glyphCount = 0;
if (this.renderPage) {
glyphCount = readEncodedContent(content);
}
this.glyphs.setGlyphCount(glyphCount);
if (!renderPage || glyphCount > 0) {
isFontEmbedded = true;
}
glyphs.setFontEmbedded(true);
}
/**
* read the diff table from a type 1 font
*/
private void readDiffEncoding(final BufferedReader br) throws Exception {
String line, name, rawVal, base, val;
int code, ptr;
while ((line = br.readLine()) != null) {
line = line.trim();
//exit at end
if (line.startsWith("readonly")) {
break;
}
//read each mapping
if (line.startsWith("dup") && line.contains("/")) {
final StringTokenizer info = new StringTokenizer(line, " /");
if (info.countTokens() >= 3) {
info.nextToken(); // discard dup
rawVal = info.nextToken();
ptr = rawVal.indexOf('#');
if (ptr == -1) {
code = Integer.parseInt(rawVal); //code
} else {
base = rawVal.substring(0, ptr);
val = rawVal.substring(ptr + 1, rawVal.length());
code = Integer.parseInt(val, Integer.parseInt(base));
}
name = info.nextToken(); //name
putChar(code, name);
final char c = name.charAt(0);
if (c == 'B' || c == 'C' || c == 'c' || c == 'G') {
int i = 1;
final int l = name.length();
while (!isHex && i < l) {
isHex = Character.isLetter(name.charAt(i++));
}
}
}
}
}
}
/**
* store embedded differences
*/
protected final void putChar(final int charInt, final String mappedChar) {
if (diffs == null) {
diffs = new String[maxCharCount];
}
diffs[charInt] = mappedChar;
if (!hasEncoding && !isCIDROS) {
if (StandardFonts.getUnicodeName(mappedChar) != null) {
putMappedChar(charInt, mappedChar);
} else if (!isHex) { //<--possibly needed for glyphs of format aXX when XX is base10 glyf char (a19, a71)
// }else{ //needed to convert back for HTML5
//System.out.println(mappedChar+" "+charInt+" "+Character.isAlphabetic(charInt)+" "+(char)charInt+" "+this.is1C()+" "+this.isHex+" ");
nonStandardMappings.put(mappedChar, charInt);
}
}
}
/**
* read the encoded part from a type 1 font
*/
private int readEncodedContentNew(final byte[] cont) throws Exception {
int glyphCount = 0;
String line;
final String rd = "rd";
final String nd = "nd";
final int size = cont.length;
int end = -1;
int charstringStart = getStart(cont, size);
if (charstringStart != -1) { //find the end
end = getEnd(cont, size, charstringStart);
}
if (end == -1) {
end = size;
}
final ByteArrayOutputStream bos = new ByteArrayOutputStream();
final int len = (end - charstringStart);
bos.write(cont, charstringStart, len);
bos.close();
//read values from the stream
final BufferedReader br = new BufferedReader(new StringReader(new String(cont)));
while (true) {
line = br.readLine();
if (line == null) {
break;
}
//get new value for n second value
if (line.startsWith("/lenIV")) {
final StringTokenizer vals = new StringTokenizer(line);
vals.nextToken(); //drop first value
skipBytes = Integer.parseInt(vals.nextToken());
//System.out.println(line);
}
}
br.close();
//find dictionary entries
final int l = cont.length;
int p = 0;
charstringStart = -1;
int subrsStart = -1;
int blueValuesStart = -1;
int otherBluesStart = -1;
int familyBluesStart = -1;
int familyOtherBluesStart = -1;
int blueScaleStart = -1;
int blueShiftStart = -1;
int blueFuzzStart = -1;
int stdHWStart = -1;
int stdVWStart = -1;
int stemSnapHStart = -1;
int stemSnapVStart = -1;
int forceBoldStart = -1;
int languageGroupStart = -1;
final char[] charstringsChars = "/CharStrings".toCharArray();
final char[] subrsChars = "/Subrs".toCharArray();
final char[] blueValuesChars = "/BlueValues".toCharArray();
final char[] otherBluesChars = "/OtherBlues".toCharArray();
final char[] familyBluesChars = "/FamilyBlues".toCharArray();
final char[] familyOtherBluesChars = "/FamilyOtherBlues".toCharArray();
final char[] blueScaleChars = "/BlueScale".toCharArray();
final char[] blueShiftChars = "/BlueShift".toCharArray();
final char[] blueFuzzChars = "/BlueFuzz".toCharArray();
final char[] stdHWChars = "/StdHW".toCharArray();
final char[] stdVWChars = "/StdVW".toCharArray();
final char[] stemSnapHChars = "/StemSnapH".toCharArray();
final char[] stemSnapVChars = "/StemSnapV".toCharArray();
final char[] forceBoldChars = "/ForceBold".toCharArray();
final char[] languageGroupChars = "/LanguageGroup".toCharArray();
while (p < l) {
if (p == l) {
break;
}
if (charstringStart == -1 && (p + 11 < l) && checkForString(cont, p, charstringsChars)) {
charstringStart = p + 11;
} else if (subrsStart == -1 && (p + 5 < l) && checkForString(cont, p, subrsChars)) {
subrsStart = p + 6;
} else if (blueValuesStart == -1 && (p + 11 < l) && checkForString(cont, p, blueValuesChars)) {
blueValuesStart = p + 11;
} else if (otherBluesStart == -1 && (p + 11 < l) && checkForString(cont, p, otherBluesChars)) {
otherBluesStart = p + 11;
} else if (familyBluesStart == -1 && (p + 12 < l) && checkForString(cont, p, familyBluesChars)) {
familyBluesStart = p + 12;
} else if (familyOtherBluesStart == -1 && (p + 17 < l) && checkForString(cont, p, familyOtherBluesChars)) {
familyOtherBluesStart = p + 17;
} else if (blueScaleStart == -1 && (p + 10 < l) && checkForString(cont, p, blueScaleChars)) {
blueScaleStart = p + 10;
} else if (blueShiftStart == -1 && (p + 10 < l) && checkForString(cont, p, blueShiftChars)) {
blueShiftStart = p + 10;
} else if (blueFuzzStart == -1 && (p + 9 < l) && checkForString(cont, p, blueFuzzChars)) {
blueFuzzStart = p + 9;
} else if (stdHWStart == -1 && (p + 6 < l) && checkForString(cont, p, stdHWChars)) {
stdHWStart = p + 6;
} else if (stdVWStart == -1 && (p + 6 < l) && checkForString(cont, p, stdVWChars)) {
stdVWStart = p + 6;
} else if (stemSnapHStart == -1 && (p + 10 < l) && checkForString(cont, p, stemSnapHChars)) {
stemSnapHStart = p + 10;
} else if (stemSnapVStart == -1 && (p + 10 < l) && checkForString(cont, p, stemSnapVChars)) {
stemSnapVStart = p + 10;
} else if (forceBoldStart == -1 && (p + 10 < l) && checkForString(cont, p, forceBoldChars)) {
forceBoldStart = p + 10;
} else if (languageGroupStart == -1 && (p + 14 < l) && checkForString(cont, p, languageGroupChars)) {
languageGroupStart = p + 14;
}
if (subrsStart > -1 && charstringStart > -1 &&
blueValuesStart > -1 && otherBluesStart > -1 &&
familyBluesStart > -1 && familyOtherBluesStart > -1 &&
blueScaleStart > -1 && blueShiftStart > -1 && blueFuzzStart > -1 &&
stdHWStart > -1 && stdVWStart > -1 &&
stemSnapHStart > -1 && stemSnapVStart > -1 &&
forceBoldStart > -1 && languageGroupStart > -1) {
break;
}
p++;
}
/*extract charstrings*/
if (charstringStart == -1) {
this.isFontSubstituted = false;
LogWriter.writeLog("No glyph data found");
} else {
glyphCount = extractFontData(skipBytes, cont, charstringStart, rd, l, nd);
}
/*extract subroutines*/
if (subrsStart > -1) {
extractSubroutineData(skipBytes, cont, subrsStart, charstringStart, rd, l, nd);
}
if (blueValuesStart > -1) {
blueValues = readIntArray(cont, blueValuesStart);
}
if (otherBluesStart > -1) {
otherBlues = readIntArray(cont, otherBluesStart);
}
if (familyBluesStart > -1) {
familyBlues = readIntArray(cont, familyBluesStart);
}
if (familyOtherBluesStart > -1) {
familyOtherBlues = readIntArray(cont, familyOtherBluesStart);
}
if (stdHWStart > -1) {
stdHW = readReal(cont, stdHWStart);
}
if (stdVWStart > -1) {
stdVW = readReal(cont, stdVWStart);
}
if (stemSnapHStart > -1) {
stemSnapH = readIntArray(cont, stemSnapHStart);
}
if (stemSnapVStart > -1) {
stemSnapV = readIntArray(cont, stemSnapVStart);
}
if (blueScaleStart > -1) {
blueScale = readReal(cont, blueScaleStart);
}
if (blueShiftStart > -1) {
blueShift = readInteger(cont, blueShiftStart);
}
if (blueFuzzStart > -1) {
blueFuzz = readInteger(cont, blueFuzzStart);
}
if (forceBoldStart > -1) {
int j = forceBoldStart;
int forceBoldEnd = -1;
while (j < l && forceBoldEnd == -1) {
if (checkForString(cont, j, DEF_CHARS)) {
forceBoldEnd = j;
}
j++;
}
final String val = new String(cont, forceBoldStart, forceBoldEnd - forceBoldStart);
try {
forceBold = Boolean.parseBoolean(val);
} catch (final NumberFormatException e) {
LogWriter.writeLog("Exception " + e);
}
}
if (languageGroupStart > -1) {
languageGroup = readInteger(cont, languageGroupStart);
}
return glyphCount;
}
static int getEnd(final byte[] cont, final int size, final int charstringStart) {
int end = -1;
for (int i = charstringStart; i < size - 10; i++) {
if ((cont[i] == 99) && (cont[i + 1] == 108) && (cont[i + 2] == 101) && (cont[i + 3] == 97) && (cont[i + 4] == 114) && (cont[i + 5] == 116) && (cont[i + 6] == 111) && (cont[i + 7] == 109) && (cont[i + 8] == 97) && (cont[i + 9] == 114) && (cont[i + 10] == 107)) {
end = i - 1;
while ((cont[end] == 10) || (cont[end] == 13)) {
end--;
}
i = size;
}
}
return end;
}
static int getStart(final byte[] cont, final int size) {
int charstringStart = -1;
for (int i = 4; i < size; i++) { //find the start of /CharStrings (which is exec
if ((cont[i - 3] == 101) && (cont[i - 2] == 120) && (cont[i - 1] == 101) && (cont[i] == 99)) {
charstringStart = i + 1;
while (cont[charstringStart] == 10 || cont[charstringStart] == 13) {
charstringStart++;
}
i = size;
}
}
return charstringStart;
}
/**
* read the encoded part from a type 1 font
*/
private int readEncodedContent(byte[] cont) throws Exception {
int glyphCount = 0;
String line;
final String rd = "rd";
final String nd = "nd";
final int size = cont.length;
int i;
int cipher;
int plain;
StringBuilder tmp;
int charstringStart = findStart(cont, size);
final int end = findEnd(cont, size, charstringStart);
/* now decode the array */
final int n = 4;
/* workout if binary or ascii - assume true and disprove */
final boolean isAscii = isAscii(cont, charstringStart, n);
if (charstringStart != -1) {
cont = getBytes(cont, charstringStart, end, n, isAscii);
}
//read values from the stream
final BufferedReader br = new BufferedReader(new StringReader(new String(cont)));
while (true) {
line = br.readLine();
if (line == null) {
break;
}
//get new value for n second value
if (line.startsWith("/lenIV")) {
final StringTokenizer vals = new StringTokenizer(line);
vals.nextToken(); //drop first value
skipBytes = Integer.parseInt(vals.nextToken());
//System.out.println(line);
}
}
br.close();
/*extract the contents*/
//find dictionary entries
final int l = cont.length;
int p = 0;
charstringStart = -1;
int subrsStart = -1;
int blueValuesStart = -1;
int otherBluesStart = -1;
int familyBluesStart = -1;
int familyOtherBluesStart = -1;
int blueScaleStart = -1;
int blueShiftStart = -1;
int blueFuzzStart = -1;
int stdHWStart = -1;
int stdVWStart = -1;
int stemSnapHStart = -1;
int stemSnapVStart = -1;
int forceBoldStart = -1;
int languageGroupStart = -1;
final char[] charstringsChars = "/CharStrings".toCharArray();
final char[] subrsChars = "/Subrs".toCharArray();
final char[] blueValuesChars = "/BlueValues".toCharArray();
final char[] otherBluesChars = "/OtherBlues".toCharArray();
final char[] familyBluesChars = "/FamilyBlues".toCharArray();
final char[] familyOtherBluesChars = "/FamilyOtherBlues".toCharArray();
final char[] blueScaleChars = "/BlueScale".toCharArray();
final char[] blueShiftChars = "/BlueShift".toCharArray();
final char[] blueFuzzChars = "/BlueFuzz".toCharArray();
final char[] stdHWChars = "/StdHW".toCharArray();
final char[] stdVWChars = "/StdVW".toCharArray();
final char[] stemSnapHChars = "/StemSnapH".toCharArray();
final char[] stemSnapVChars = "/StemSnapV".toCharArray();
final char[] forceBoldChars = "/ForceBold".toCharArray();
final char[] languageGroupChars = "/LanguageGroup".toCharArray();
while (p < l) {
if (p == l) {
break;
}
if (charstringStart == -1 && (p + 11 < l) && checkForString(cont, p, charstringsChars)) {
charstringStart = p + 11;
} else if (subrsStart == -1 && (p + 5 < l) && checkForString(cont, p, subrsChars)) {
subrsStart = p + 6;
} else if (blueValuesStart == -1 && (p + 11 < l) && checkForString(cont, p, blueValuesChars)) {
blueValuesStart = p + 11;
} else if (otherBluesStart == -1 && (p + 11 < l) && checkForString(cont, p, otherBluesChars)) {
otherBluesStart = p + 11;
} else if (familyBluesStart == -1 && (p + 12 < l) && checkForString(cont, p, familyBluesChars)) {
familyBluesStart = p + 12;
} else if (familyOtherBluesStart == -1 && (p + 17 < l) && checkForString(cont, p, familyOtherBluesChars)) {
familyOtherBluesStart = p + 17;
} else if (blueScaleStart == -1 && (p + 10 < l) && checkForString(cont, p, blueScaleChars)) {
blueScaleStart = p + 10;
} else if (blueShiftStart == -1 && (p + 10 < l) && checkForString(cont, p, blueShiftChars)) {
blueShiftStart = p + 10;
} else if (blueFuzzStart == -1 && (p + 9 < l) && checkForString(cont, p, blueFuzzChars)) {
blueFuzzStart = p + 9;
} else if (stdHWStart == -1 && (p + 6 < l) && checkForString(cont, p, stdHWChars)) {
stdHWStart = p + 6;
} else if (stdVWStart == -1 && (p + 6 < l) && checkForString(cont, p, stdVWChars)) {
stdVWStart = p + 6;
} else if (stemSnapHStart == -1 && (p + 10 < l) && checkForString(cont, p, stemSnapHChars)) {
stemSnapHStart = p + 10;
} else if (stemSnapVStart == -1 && (p + 10 < l) && checkForString(cont, p, stemSnapVChars)) {
stemSnapVStart = p + 10;
} else if (forceBoldStart == -1 && (p + 10 < l) && checkForString(cont, p, forceBoldChars)) {
forceBoldStart = p + 10;
} else if (languageGroupStart == -1 && (p + 14 < l) && checkForString(cont, p, languageGroupChars)) {
languageGroupStart = p + 14;
}
if (subrsStart > -1 && charstringStart > -1 &&
blueValuesStart > -1 && otherBluesStart > -1 &&
familyBluesStart > -1 && familyOtherBluesStart > -1 &&
blueScaleStart > -1 && blueShiftStart > -1 && blueFuzzStart > -1 &&
stdHWStart > -1 && stdVWStart > -1 &&
stemSnapHStart > -1 && stemSnapVStart > -1 &&
forceBoldStart > -1 && languageGroupStart > -1) {
break;
}
p++;
}
/*extract charstrings*/
if (charstringStart == -1) {
this.isFontSubstituted = false;
LogWriter.writeLog("No glyph data found");
} else {
glyphCount = extractFontData(skipBytes, cont, charstringStart, rd, l, nd);
}
/*extract subroutines*/
if (subrsStart > -1) {
extractSubroutineData(skipBytes, cont, subrsStart, charstringStart, rd, l, nd);
}
if (blueValuesStart > -1) {
blueValues = readIntArray(cont, blueValuesStart);
}
if (otherBluesStart > -1) {
otherBlues = readIntArray(cont, otherBluesStart);
}
if (familyBluesStart > -1) {
familyBlues = readIntArray(cont, familyBluesStart);
}
if (familyOtherBluesStart > -1) {
familyOtherBlues = readIntArray(cont, familyOtherBluesStart);
}
if (stdHWStart > -1) {
stdHW = readReal(cont, stdHWStart);
}
if (stdVWStart > -1) {
stdVW = readReal(cont, stdVWStart);
}
if (stemSnapHStart > -1) {
stemSnapH = readIntArray(cont, stemSnapHStart);
}
if (stemSnapVStart > -1) {
stemSnapV = readIntArray(cont, stemSnapVStart);
}
if (blueScaleStart > -1) {
blueScale = readReal(cont, blueScaleStart);
}
if (blueShiftStart > -1) {
blueShift = readInteger(cont, blueShiftStart);
}
if (blueFuzzStart > -1) {
blueFuzz = readInteger(cont, blueFuzzStart);
}
if (forceBoldStart > -1) {
int j = forceBoldStart;
int forceBoldEnd = -1;
while (j < l && forceBoldEnd == -1) {
if (checkForString(cont, j, DEF_CHARS)) {
forceBoldEnd = j;
}
j++;
}
final String val = new String(cont, forceBoldStart, forceBoldEnd - forceBoldStart);
try {
forceBold = Boolean.parseBoolean(val);
} catch (final NumberFormatException e) {
LogWriter.writeLog("Exception " + e);
}
}
if (languageGroupStart > -1) {
languageGroup = readInteger(cont, languageGroupStart);
}
return glyphCount;
}
private byte[] getBytes(byte[] cont, int charstringStart, final int end, final int n, final boolean isAscii) {
int r = 55665;
int i;
int cipher;
StringBuilder tmp;
int plain;
final FastByteArrayOutputStream bos = new FastByteArrayOutputStream(end - charstringStart);
//allow for offset in real pfb file
if (isFontSubstituted && !isAscii) {
charstringStart = charstringStart + 2 + skipBytes;
}
for (i = charstringStart; i < end; i++) {
if (!isAscii) {
cipher = cont[i] & 0xff;
} else {
int chars = 0;
tmp = new StringBuilder();
//get 2 chars for next hex value ignoring
// whitespace/returns,etc
while (chars < 2) {
cipher = cont[i] & 0xff;
i++;
if (cipher != 10 && cipher != 13 && cipher != 9 && cipher != 32) {
tmp.append((char) cipher);
chars++;
}
}
i--;
//convert to hex value
cipher = Integer.parseInt(tmp.toString(), 16);
}
plain = (cipher ^ (r >> 8));
r = ((cipher + r) * c1 + c2) & 0xffff;
if (i > charstringStart + n) {
bos.write(plain);
}
}
cont = bos.toByteArray();
return cont;
}
static boolean isAscii(final byte[] cont, final int charstringStart, final int n) {
int i;
boolean isAscii = true;
for (i = charstringStart; i < charstringStart + (n * 2); i++) {
final char c = (char) (cont[i]);
if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f')) {
//is okay
} else {
isAscii = false;
break;
}
}
return isAscii;
}
static int findEnd(final byte[] cont, final int rawSize, final int charstringStart) {
int i, end = -1;
final int size = rawSize - 10;
if (charstringStart != -1) { //find the end
for (i = charstringStart; i < size; i++) {
if (cont[i] == 99 && cont[i + 1] == 108 && cont[i + 2] == 101 && cont[i + 3] == 97 && cont[i + 4] == 114
&& cont[i + 5] == 116 && cont[i + 6] == 111 && cont[i + 7] == 109 && cont[i + 8] == 97 &&
cont[i + 9] == 114 && cont[i + 10] == 107) {
end = i - 1;
while ((cont[end] == 10) || (cont[end] == 13)) {
end--;
}
i = size;
}
}
}
if (end == -1) {
return rawSize;
} else {
return end;
}
}
static int findStart(final byte[] cont, final int size) {
int charstringStart = -1;
for (int i = 4; i < size; i++) { //find the start of /CharStrings (which is exec
if (cont[i - 3] == 101 && cont[i - 2] == 120 && cont[i - 1] == 101 && cont[i] == 99) {
charstringStart = i + 1;
while (cont[charstringStart] == 10 || cont[charstringStart] == 13) {
charstringStart++;
}
i = size;
}
}
return charstringStart;
}
/**
* Reads an integer
*/
static Integer readInteger(final byte[] data, final int offset) {
final int l = data.length;
int j = offset;
int end = -1;
while (j < l && end == -1) {
if (checkForString(data, j, DEF_CHARS)) {
end = j;
}
j++;
}
final String val = new String(data, offset, end - offset);
try {
return Integer.parseInt(val.trim());
} catch (final NumberFormatException e) {
LogWriter.writeLog("Exception in handling Integer in Type1 " + e);
return null;
}
}
/**
* Reads a real or array containing a single real
*/
static Double readReal(final byte[] data, final int offset) {
final int l = data.length;
int j = offset;
int end = -1;
while (j < l && end == -1) {
if (checkForString(data, j, DEF_CHARS) || data[j] == ']' || data[j] == '\n') {
end = j;
}
j++;
}
String val = new String(data, offset, end - offset);
if (val.contains("[")) {
final String[] stringParts = val.split("\\[");
if (stringParts.length < 2) {
return null;
}
val = stringParts[1];
}
try {
return Double.parseDouble(val);
} catch (final NumberFormatException e) {
LogWriter.writeLog("Exception in handling real in Type1 " + e);
return null;
}
}
/**
* Reads an int array in the format [1 2 3]. Returns null if it can't be read, and stores -1 in the place of any
* values which can't be read.
*
* @param data The data to read from
* @param start The start of the array
* @return An int[] representation of the array
*/
private static int[] readIntArray(final byte[] data, final int start) {
int[] result = null;
final int l = data.length;
int j = start;
int end = -1;
while (j < l && end == -1) {
if (data[j] == ']' || data[j] == '/' || data[j] == '\n') {
end = j;
}
j++;
}
if (end != -1) {
String values = new String(data, start, end - start);
if (values.contains("[")) {
final String[] stringParts = values.split("\\[");
if (stringParts.length < 2) {
return null;
}
values = stringParts[1];
}
values = values.trim();
final String[] stringValues = values.split(" ");
result = new int[stringValues.length];
for (j = 0; j < stringValues.length; j++) {
try {
result[j] = Integer.parseInt(stringValues[j].split("\\.")[0]);
} catch (final NumberFormatException e) {
LogWriter.writeLog("Exception in handling IntArray " + e);
result[j] = -1;
}
}
}
return result;
}
/**
* Checks for a sequence of chars at a given offset in a byte array.
*/
private static boolean checkForString(final byte[] data, final int offset, final char[] chars) {
for (int i = 0; i < chars.length; i++) {
if (data[offset + i] != chars[i]) {
return false;
}
}
return true;
}
private void extractSubroutineData(final int skipBytes, final byte[] cont, int start, final int charStart, final String rd, final int l, final String nd) {
final int count;
// //move to start of first value
start = StreamReaderUtils.skipSpaces(cont, start);
//read the count
StringBuilder tmp = new StringBuilder();
while (true) {
final char c = (char) cont[start];
if (c == ' ') {
break;
}
tmp.append(c);
start++;
}
count = Integer.parseInt(tmp.toString());
for (int i = 0; i < count; i++) {
//read the dup
while ((start < l)) {
if (((cont[start - 2] == 100) && (cont[start - 1] == 117) && (cont[start] == 112)) | (start == charStart)) {
break;
}
start++;
}
if (start == charStart) {
i = count;
} else {
//move to start of first value
while ((cont[start + 1] == 32)) {
start++;
}
//read the count
final StringBuilder glyph = new StringBuilder("subrs");
while (true) {
start++;
final char c = (char) cont[start];
if (c == ' ') {
break;
}
glyph.append(c);
}
//read the byte count
tmp = new StringBuilder();
while (true) {
start++;
final char c = (char) cont[start];
if (c == ' ') {
break;
}
tmp.append(c);
}
final int byteCount = Integer.parseInt(tmp.toString());
//skip any more spaces
while ((cont[start] == 32)) {
start++;
}
//skip RD and blank space and random bytes
start = start + rd.length() + 1;
final byte[] stream = getStream(skipBytes, start, byteCount, cont);
//store table
glyphs.setCharString(glyph.toString(), stream, i);
start = start + byteCount + nd.length();
//move to start of next value
//while((start<=cont.length)&&(cont[start] != 47))
// start++;
}
}
}
private int extractFontData(final int skipBytes, final byte[] cont, int start, final String rd, final int l, final String nd) {
final int total = cont.length;
int glyphCount = 0;
//move to start of first value
while (start < total && cont[start] != 47) {
start++;
}
int end = start;
// System.out.println("----->\n");
// for(int aa=start;aa> 8));
//here�
r = ((cipher + r) * c1 + c2) & 0xffff;
if (i >= skipBytes) {
bos.write(plain);
// System.out.println(plain);
//else
// System.out.println("SKIP="+plain);
}
}
return bos.toByteArray();
}
}