001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Scott Ferguson
028: */
029:
030: package com.caucho.quercus.lib.pdf;
031:
032: import com.caucho.util.L10N;
033: import com.caucho.vfs.MergePath;
034: import com.caucho.vfs.Path;
035: import com.caucho.vfs.ReadStream;
036:
037: import java.io.FileNotFoundException;
038: import java.io.IOException;
039:
040: /**
041: * parses afm
042: */
043: public class AfmParser {
044: private static final L10N L = new L10N(AfmParser.class);
045:
046: private static final String END_OF_FILE = "end of file";
047:
048: private ReadStream _is;
049:
050: /**
051: * Parses the AFM
052: */
053: public Font parse(String name) throws IOException {
054: MergePath mergePath = new MergePath();
055: mergePath.addClassPath();
056:
057: Path path = mergePath.lookup("com/caucho/quercus/lib/pdf/font/"
058: + name + ".afm");
059:
060: if (!path.canRead())
061: throw new FileNotFoundException(L.l("Can't find font {0}",
062: name));
063:
064: _is = path.openRead();
065:
066: try {
067: return parseTop();
068: } finally {
069: _is.close();
070: }
071: }
072:
073: private Font parseTop() throws IOException {
074: Font font = new Font();
075:
076: while (skipWhitespace()) {
077: String id = parseIdentifier();
078:
079: if ("FontName".equals(id)) {
080: font.setFontName(parseString());
081: } else if ("Weight".equals(id)) {
082: font.setWeight(parseString());
083: } else if ("FontBBox".equals(id)) {
084: font.setBBox(parseNumber(), parseNumber(),
085: parseNumber(), parseNumber());
086: } else if ("CapHeight".equals(id)) {
087: font.setCapHeight(parseNumber());
088: } else if ("XHeight".equals(id)) {
089: font.setXHeight(parseNumber());
090: } else if ("Ascender".equals(id)) {
091: font.setAscender(parseNumber());
092: } else if ("Descender".equals(id)) {
093: font.setDescender(parseNumber());
094: } else if ("UnderlinePosition".equals(id)) {
095: font.setUnderlinePosition(parseNumber());
096: } else if ("UnderlineThickness".equals(id)) {
097: font.setUnderlineThickness(parseNumber());
098: } else if ("C".equals(id)) {
099: font.addChar(parseCharacter());
100: }
101:
102: skipToEndOfLine();
103: }
104:
105: return font;
106: }
107:
108: private FontChar parseCharacter() throws IOException {
109: int code = parseInteger();
110:
111: skipWhitespace();
112:
113: int ch;
114:
115: if ((ch = _is.read()) != ';')
116: throw new IOException("Expected ';'");
117:
118: String wx = parseString();
119:
120: if (!"WX".equals(wx))
121: throw new IOException("Expected 'WX'");
122:
123: double width = parseNumber();
124:
125: return new FontChar(code, width);
126: }
127:
128: private String parseString() throws IOException {
129: skipWhitespace();
130:
131: StringBuilder sb = new StringBuilder();
132: int ch;
133:
134: while ((ch = _is.read()) >= 0 && !Character.isWhitespace(ch)) {
135: sb.append((char) ch);
136: }
137:
138: if (ch >= 0)
139: _is.unread();
140:
141: return sb.toString();
142: }
143:
144: private int parseInteger() throws IOException {
145: skipWhitespace();
146:
147: int value = 0;
148: int sign = 1;
149:
150: int ch = _is.read();
151:
152: if (ch == '-') {
153: sign = -1;
154: ch = _is.read();
155: }
156:
157: for (; '0' <= ch && ch <= '9'; ch = _is.read()) {
158: value = 10 * value + ch - '0';
159: }
160:
161: if (ch >= 0)
162: _is.unread();
163:
164: return sign * value;
165: }
166:
167: private double parseNumber() throws IOException {
168: skipWhitespace();
169:
170: StringBuilder sb = new StringBuilder();
171: int ch;
172:
173: while ('0' <= (ch = _is.read()) && ch <= '9' || ch == '.'
174: || ch == '-' || ch == '+') {
175: sb.append((char) ch);
176: }
177:
178: if (ch >= 0)
179: _is.unread();
180:
181: if (sb.length() == 0)
182: return 0;
183:
184: return Double.parseDouble(sb.toString());
185: }
186:
187: private String parseIdentifier() throws IOException {
188: StringBuilder sb = new StringBuilder();
189:
190: int ch;
191:
192: while (Character.isLetterOrDigit((ch = _is.read()))) {
193: sb.append((char) ch);
194: }
195:
196: _is.unread();
197:
198: return sb.toString();
199: }
200:
201: private void skipToEndOfLine() throws IOException {
202: int ch;
203:
204: while ((ch = _is.read()) >= 0 && ch != '\n') {
205: }
206: }
207:
208: private boolean skipWhitespace() throws IOException {
209: int ch;
210:
211: while ((ch = _is.read()) == ' ' || ch == '\t') {
212: }
213:
214: if (ch >= 0)
215: _is.unread();
216:
217: return ch >= 0;
218: }
219: }
|