/**
* ===========================================
* LibFonts : a free Java font reading library
* ===========================================
*
* Project Info: http://reporting.pentaho.org/libfonts/
*
* (C) Copyright 2006-2007, by Pentaho Corporation and Contributors.
*
* This library is free software; you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Foundation;
* either version 2.1 of the License, or (at your option) any later version.
*
* This library 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 GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*
* [Java is a trademark or registered trademark of Sun Microsystems, Inc.
* in the United States and other countries.]
*
* ------------
* $Id: AfmFont.java 3523 2007-10-16 11:03:09Z tmorgner $
* ------------
* (C) Copyright 2006-2007, by Pentaho Corporation.
*/
package org.jfree.fonts.afm;
import java.io.IOException;
import java.io.File;
import org.jfree.fonts.io.FontDataInputSource;
import org.jfree.fonts.io.FileFontDataInputSource;
/**
* An AFM font is a simple text file.
*
* @author Thomas Morgner
*/
public class AfmFont
{
private static final int PRE_HEADER = 0;
private static final int IN_HEADER = 1;
private static final int IN_METRICS = 2;
private static final int IN_KERNDATA = 3;
private static final int IN_COMPOSITES = 4;
private static final int END_OF_FILE = 5;
private static final int IN_DIRECTION = 6;
private AfmHeader header;
private AfmDirectionSection[] directionSections;
private AfmCharMetricsSection charMetricsSection;
private AfmKernDataSection kernDataSection;
private AfmCompositeCharDataSection compositeCharDataSection;
private boolean embeddable;
private String fontName;
private String familyName;
private String filename;
private FontDataInputSource input;
public AfmFont(final File font, final boolean embeddable) throws IOException
{
final FontDataInputSource fis = new FileFontDataInputSource(font);
initialize(fis, embeddable);
fis.dispose();
}
public AfmFont(final FontDataInputSource inputSource,
final boolean embeddable) throws IOException
{
initialize(inputSource, embeddable);
}
private void initialize(final FontDataInputSource inputSource, final boolean embeddable)
throws IOException
{
if (inputSource == null)
{
throw new NullPointerException();
}
this.filename = inputSource.getFileName();
this.input = inputSource;
this.embeddable = embeddable;
header = new AfmHeader();
directionSections = new AfmDirectionSection[2];
directionSections[0] = new AfmDirectionSection();
directionSections[1] = new AfmDirectionSection();
charMetricsSection = new AfmCharMetricsSection();
kernDataSection = new AfmKernDataSection();
parseFontFile(inputSource);
fontName = header.getFontName();
if (fontName == null)
{
throw new IOException("This font does not define a font-name, therefore it is invalid.");
}
familyName = header.getFamilyName();
if (familyName == null)
{
familyName = fontName;
}
}
private void parseFontFile(final FontDataInputSource inputSource)
throws IOException
{
int parseState = PRE_HEADER;
int sectionType = 0;
final FontDataAsciiReader reader = new FontDataAsciiReader(inputSource);
String line;
while ((line = reader.readLine()) != null)
{
if (line.length() == 0)
{
continue;
}
switch (parseState)
{
case PRE_HEADER:
{
if (line.startsWith("StartFontMetrics") == false)
{
throw new IOException("Expected 'StartMetrics' as initial command line.");
}
parseState = IN_HEADER;
break;
}
case IN_HEADER:
{
if (line.startsWith("EndFontMetrics"))
{
parseState = END_OF_FILE;
}
else if (line.startsWith("StartDirection"))
{
parseState = IN_DIRECTION;
sectionType = AfmParseUtilities.parseInt("StartDirection ", line);
}
else if (line.startsWith("StartCharMetrics"))
{
parseState = IN_METRICS;
sectionType = AfmParseUtilities.parseInt("StartCharMetrics ", line);
}
else if (line.startsWith("StartKernData"))
{
parseState = IN_KERNDATA;
}
else if (line.startsWith("StartComposites"))
{
parseState = IN_COMPOSITES;
compositeCharDataSection = new AfmCompositeCharDataSection();
}
else
{
header.addData(line);
directionSections[0].add(line);
}
break;
}
case IN_METRICS:
{
if (line.startsWith("EndCharMetrics"))
{
parseState = IN_HEADER;
sectionType = 0;
}
else
{
charMetricsSection.add(line);
}
break;
}
case IN_KERNDATA:
{
if (line.startsWith("EndKernData"))
{
parseState = IN_HEADER;
sectionType = 0;
}
else
{
kernDataSection.add(line);
}
break;
}
case IN_COMPOSITES:
{
if (line.startsWith("EndComposites"))
{
parseState = IN_HEADER;
sectionType = 0;
}
else
{
compositeCharDataSection.add(line);
}
break;
}
case END_OF_FILE:
{
// Extra lines after the 'EndFontMetrics' line are ignored.
break;
}
case IN_DIRECTION:
{
if (line.startsWith("EndDirection"))
{
parseState = IN_HEADER;
sectionType = 0;
}
else
{
switch(sectionType)
{
case 0:
{
directionSections[0].add(line);
break;
}
case 1:
{
directionSections[1].add(line);
break;
}
case 2:
{
directionSections[0].add(line);
directionSections[1].add(line);
break;
}
default:
{
throw new IllegalStateException("The Type " + sectionType + " for the Direction-section was invalid.");
}
}
}
break;
}
default:
{
throw new IllegalStateException("In Parse State " + parseState + ": Encountered line " + line);
}
}
}
}
public int getMetricsSets()
{
return header.getMetricsSets();
}
public AfmDirectionSection getDirectionSection(final int index)
{
return directionSections[index];
}
public FontDataInputSource getInput()
{
return input;
}
public AfmHeader getHeader()
{
return header;
}
public String getFilename()
{
return filename;
}
public String getFamilyName()
{
return familyName;
}
public String getFontName()
{
return fontName;
}
public boolean isEmbeddable()
{
return embeddable;
}
public void dispose()
{
input.dispose();
}
}