package com.v7lin.android.env.font;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.HashMap;
import java.util.Map;
import android.annotation.SuppressLint;
/**
* ttf font parser
*
* @author v7lin E-mail:v7lin@qq.com
*/
@SuppressLint("UseSparseArrays")
public class TTFParser {
public static int COPYRIGHT = 0;
public static int FAMILY_NAME = 1;
public static int FONT_SUBFAMILY_NAME = 2;
public static int UNIQUE_FONT_IDENTIFIER = 3;
public static int FULL_FONT_NAME = 4;
public static int VERSION = 5;
public static int POSTSCRIPT_NAME = 6;
public static int TRADEMARK = 7;
public static int MANUFACTURER = 8;
public static int DESIGNER = 9;
public static int DESCRIPTION = 10;
public static int URL_VENDOR = 11;
public static int URL_DESIGNER = 12;
public static int LICENSE_DESCRIPTION = 13;
public static int LICENSE_INFO_URL = 14;
private Map<Integer, String> fontProperties = new HashMap<Integer, String>();
/**
* 获取ttf font name
*
* @return
*/
public String getFontName() {
if (fontProperties.containsKey(FULL_FONT_NAME)) {
return fontProperties.get(FULL_FONT_NAME);
} else if (fontProperties.containsKey(FAMILY_NAME)) {
return fontProperties.get(FAMILY_NAME);
} else {
return null;
}
}
/**
* 获取ttf属性
*
* @param nameID
* 属性标记,见静态变量
*
* @return 属性值
*/
public String getFontPropertie(int nameID) {
if (fontProperties.containsKey(nameID)) {
return fontProperties.get(nameID);
} else {
return null;
}
}
/**
* 获取ttf属性集合
*
* @return 属性集合(MAP)
*/
public Map<Integer, String> getFontProperties() {
return fontProperties;
}
/**
* 执行解析 —— 毫秒级别
*
* @param fileName
* ttf文件名
*
* @throws IOException
*/
public void parse(String fileName) throws IOException {
fontProperties.clear();
RandomAccessFile f = null;
try {
f = new RandomAccessFile(fileName, "r");
parseInner(f);
} finally {
try {
f.close();
} catch (Exception e) {
// ignore;
}
}
}
private void parseInner(RandomAccessFile randomAccessFile) throws IOException {
int majorVersion = randomAccessFile.readShort();
int minorVersion = randomAccessFile.readShort();
int numOfTables = randomAccessFile.readShort();
if (majorVersion != 1 || minorVersion != 0) {
return;
}
// jump to TableDirectory struct
randomAccessFile.seek(12);
boolean found = false;
byte[] buff = new byte[4];
TableDirectory tableDirectory = new TableDirectory();
for (int i = 0; i < numOfTables; i++) {
randomAccessFile.read(buff);
tableDirectory.name = new String(buff);
tableDirectory.checkSum = randomAccessFile.readInt();
tableDirectory.offset = randomAccessFile.readInt();
tableDirectory.length = randomAccessFile.readInt();
if ("name".equalsIgnoreCase(tableDirectory.name)) {
found = true;
break;
} else if (tableDirectory.name == null || tableDirectory.name.length() == 0) {
break;
}
}
// not found table of name
if (!found) {
return;
}
randomAccessFile.seek(tableDirectory.offset);
NameTableHeader nameTableHeader = new NameTableHeader();
nameTableHeader.fSelector = randomAccessFile.readShort();
nameTableHeader.nRCount = randomAccessFile.readShort();
nameTableHeader.storageOffset = randomAccessFile.readShort();
NameRecord nameRecord = new NameRecord();
for (int i = 0; i < nameTableHeader.nRCount; i++) {
nameRecord.platformID = randomAccessFile.readShort();
nameRecord.encodingID = randomAccessFile.readShort();
nameRecord.languageID = randomAccessFile.readShort();
nameRecord.nameID = randomAccessFile.readShort();
nameRecord.stringLength = randomAccessFile.readShort();
nameRecord.stringOffset = randomAccessFile.readShort();
long pos = randomAccessFile.getFilePointer();
byte[] bf = new byte[nameRecord.stringLength];
long vpos = tableDirectory.offset + nameRecord.stringOffset + nameTableHeader.storageOffset;
randomAccessFile.seek(vpos);
randomAccessFile.read(bf);
String temp = new String(bf, "utf-16");//new String(bf, Charset.forName("utf-16"));
fontProperties.put(nameRecord.nameID, temp);
randomAccessFile.seek(pos);
}
}
@Override
public String toString() {
return fontProperties.toString();
}
@SuppressWarnings("unused")
private static class TableDirectory {
String name; // table name
int checkSum; // Check sum
int offset; // Offset from beginning of file
int length; // length of the table in bytes
}
@SuppressWarnings("unused")
private static class NameTableHeader {
int fSelector; // format selector. Always 0
int nRCount; // Name Records count
int storageOffset; // Offset for strings storage,
}
@SuppressWarnings("unused")
private static class NameRecord {
int platformID;
int encodingID;
int languageID;
int nameID;
int stringLength;
int stringOffset; // from start of storage area
}
}