/* Copyright (C) 2009 Mobile Sorcery AB
This program is free software; you can redistribute it and/or modify it
under the terms of the Eclipse Public License v1.0.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the Eclipse Public License v1.0 for
more details.
You should have received a copy of the Eclipse Public License v1.0 along
with this program. It is also available at http://www.eclipse.org/legal/epl-v10.html
*/
package com.mobilesorcery.sdk.fontsupport.internal.wizard;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.MessageFormat;
import com.mobilesorcery.sdk.core.Util;
public class BinaryBMFontParser {
public final static int INFO_TYPE = 1;
public final static int COMMON_TYPE = 2;
public final static int PAGES_TYPE = 3;
public final static int CHARS_TYPE = 4;
public final static int KERNING_TYPE = 5;
private static final int KERNING_PAIR_SIZE = 6;
public BMFontInfo parse(File bmFontFile) throws IOException {
FileInputStream input = new FileInputStream(bmFontFile);
try {
return parse(input);
} finally {
input.close();
}
}
private BMFontInfo parse(InputStream input) throws IOException {
BMFontInfo result = new BMFontInfo();
byte[] magic = new byte[4];
if (input.read(magic) != 4) {
throw new IOException(Messages.BinaryBMFontParser_0 +
Messages.BinaryBMFontParser_1);
}
if (magic[0] != 'B' || magic[1] != 'M' || magic[2] != 'F') {
throw new IOException(Messages.BinaryBMFontParser_2 +
Messages.BinaryBMFontParser_3);
}
int version = magic[3];
result.setVersion(version);
for (BMFontInfoBlock block = parseBlock(result, input); block != null; block = parseBlock(result, input)) {
result.addBlock(block);
}
return result;
}
public final static void main(String[] args) throws Exception {
BinaryBMFontParser parser = new BinaryBMFontParser();
BMFontInfo info = parser.parse(new File(Messages.BinaryBMFontParser_4));
System.err.println(info.getFirst(BinaryBMFontParser.PAGES_TYPE));
}
private BMFontInfoBlock parseBlock(BMFontInfo info, InputStream input) throws IOException {
int type = input.read();
if (type == -1) {
return null;
}
int blockSize = Util.readInt(input);
BMFontInfoBlock block = new BMFontInfoBlock(type);
switch (type) {
case INFO_TYPE:
case COMMON_TYPE:
case CHARS_TYPE:
int bytesToSkip = blockSize - 4;
if(info.getVersion() == 3) {
// In version 3 the space for the block size is not included
bytesToSkip = blockSize;
}
input.skip(bytesToSkip);
break;
case PAGES_TYPE:
parsePagesBlock(block, input);
break;
case KERNING_TYPE:
parseKerningBlock(info, block, blockSize, input);
break;
default:
throw new IOException(MessageFormat.format(Messages.BinaryBMFontParser_5, type));
}
return block;
}
private void parseKerningBlock(BMFontInfo info, BMFontInfoBlock block, int blockSize, InputStream input) throws IOException {
int kerningPairs = blockSize / KERNING_PAIR_SIZE;
for (int i = 0; i < kerningPairs; i++) {
int first = Util.readShort(input) & 0xffff;
int second = Util.readShort(input) & 0xffff;
int amount = Util.readShort(input);
info.setKerning(first, second, amount);
}
}
private void parsePagesBlock(BMFontInfoBlock block, InputStream input) throws IOException {
String pageName = readZS(input);
block.setString(BMFontInfoBlock.PAGE_NAME, pageName);
}
private String readZS(InputStream input) throws IOException {
StringBuffer pageName = new StringBuffer();
for (int read = input.read(); read != 0; read = input.read()) {
if (read == -1) {
throw new IOException(Messages.BinaryBMFontParser_6);
}
pageName.append((char) read);
}
return pageName.toString();
}
}