1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 /* $Id$ */
19 
20 package org.apache.fop.fonts.type1;
21 
22 import java.io.IOException;
23 import java.util.Map;
24 import java.util.Stack;
25 import java.util.regex.Matcher;
26 import java.util.regex.Pattern;
27 
28 import org.apache.commons.logging.Log;
29 import org.apache.commons.logging.LogFactory;
30 
31 import org.apache.xmlgraphics.fonts.Glyphs;
32 
33 import org.apache.fop.fonts.NamedCharacter;
34 import org.apache.fop.fonts.type1.AFMParser.ValueHandler;
35 
36 /**
37  * A handler that parses the various types of character metrics in an AFM file.
38  */
39 abstract class CharMetricsHandler {
40 
41     private static final Log LOG = LogFactory.getLog(CharMetricsHandler.class);
42 
43     private static final String WHITE_SPACE = "\\s*";
44     private static final String OPERATOR = "([A-Z0-9]{1,3})";
45     private static final String OPERANDS = "(.*)";
46 
47     private static final Pattern METRICS_REGEX = Pattern.compile(
48              WHITE_SPACE + OPERATOR + WHITE_SPACE + OPERANDS + WHITE_SPACE);
49     private static final Pattern SPLIT_REGEX = Pattern.compile(WHITE_SPACE + ";" + WHITE_SPACE);
50 
CharMetricsHandler()51     private CharMetricsHandler() {
52     }
53 
parse(String line, Stack<Object> stack, String afmFileName)54     abstract AFMCharMetrics parse(String line, Stack<Object> stack, String afmFileName)
55             throws IOException;
56 
getHandler(Map<String, ValueHandler> valueParsers, String line)57     static CharMetricsHandler getHandler(Map<String, ValueHandler> valueParsers,
58             String line) {
59         if (line != null && line.contains(AdobeStandardEncoding.NAME)) {
60             return new AdobeStandardCharMetricsHandler(valueParsers);
61         } else {
62             return new DefaultCharMetricsHandler(valueParsers);
63         }
64     }
65 
66     private static final class DefaultCharMetricsHandler extends CharMetricsHandler {
67         private final Map<String, ValueHandler> valueParsers;
68 
69 
DefaultCharMetricsHandler(Map<String, ValueHandler> valueParsers)70         private DefaultCharMetricsHandler(Map<String, ValueHandler> valueParsers) {
71             this.valueParsers = valueParsers;
72         }
73 
parse(String line, Stack<Object> stack, String afmFileName)74         AFMCharMetrics parse(String line, Stack<Object> stack, String afmFileName)
75                 throws IOException {
76             AFMCharMetrics chm = new AFMCharMetrics();
77             stack.push(chm);
78             String[] metrics = SPLIT_REGEX.split(line);
79             for (String metric : metrics) {
80                 Matcher matcher = METRICS_REGEX.matcher(metric);
81                 if (matcher.matches()) {
82                     String operator = matcher.group(1);
83                     String operands = matcher.group(2);
84                     ValueHandler handler = valueParsers.get(operator);
85                     if (handler != null) {
86                         handler.parse(operands, 0, stack);
87                     }
88                 }
89             }
90             stack.pop();
91             return chm;
92         }
93     }
94 
95     private static final class AdobeStandardCharMetricsHandler extends CharMetricsHandler {
96         private final DefaultCharMetricsHandler defaultHandler;
97 
AdobeStandardCharMetricsHandler(Map<String, ValueHandler> valueParsers)98         private AdobeStandardCharMetricsHandler(Map<String, ValueHandler> valueParsers) {
99             defaultHandler = new DefaultCharMetricsHandler(valueParsers);
100         }
101 
parse(String line, Stack<Object> stack, String afmFileName)102         AFMCharMetrics parse(String line, Stack<Object> stack, String afmFileName)
103                 throws IOException {
104             AFMCharMetrics chm = defaultHandler.parse(line, stack, afmFileName);
105             NamedCharacter namedChar = chm.getCharacter();
106             if (namedChar != null) {
107                 String charName = namedChar.getName();
108                 int codePoint = AdobeStandardEncoding.getAdobeCodePoint(charName);
109                 if (chm.getCharCode() != codePoint && !Glyphs.NOTDEF.equals(charName)) {
110                     LOG.info(afmFileName + ": named character '" + charName + "'"
111                             + " has an incorrect code point: " + chm.getCharCode()
112                             + ". Changed to " + codePoint);
113                     chm.setCharCode(codePoint);
114                 }
115             }
116             return chm;
117         }
118     }
119 
120 }
121