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 package org.apache.fontbox.cmap; 18 19 import java.io.IOException; 20 21 import java.util.ArrayList; 22 import java.util.HashMap; 23 import java.util.List; 24 import java.util.Map; 25 import java.util.Iterator; 26 27 /** 28 * This class represents a CMap file. 29 * 30 * @author Ben Litchfield (ben@benlitchfield.com) 31 * @version $Revision: 1.3 $ 32 */ 33 public class CMap 34 { 35 private List<CodespaceRange> codeSpaceRanges = new ArrayList<CodespaceRange>(); 36 private Map<Integer,String> singleByteMappings = new HashMap<Integer,String>(); 37 private Map<Integer,String> doubleByteMappings = new HashMap<Integer,String>(); 38 39 /** 40 * Creates a new instance of CMap. 41 */ 42 public CMap() 43 { 44 //default constructor 45 } 46 47 /** 48 * This will tell if this cmap has any one byte mappings. 49 * 50 * @return true If there are any one byte mappings, false otherwise. 51 */ 52 public boolean hasOneByteMappings() 53 { 54 return singleByteMappings.size() > 0; 55 } 56 57 /** 58 * This will tell if this cmap has any two byte mappings. 59 * 60 * @return true If there are any two byte mappings, false otherwise. 61 */ 62 public boolean hasTwoByteMappings() 63 { 64 return doubleByteMappings.size() > 0; 65 } 66 67 /** 68 * This will perform a lookup into the map. 69 * 70 * @param code The code used to lookup. 71 * @param offset The offset into the byte array. 72 * @param length The length of the data we are getting. 73 * 74 * @return The string that matches the lookup. 75 */ 76 public String lookup( byte[] code, int offset, int length ) 77 { 78 String result = null; 79 Integer key = null; 80 if( length == 1 ) 81 { 82 83 key = new Integer( (code[offset]+256)%256 ); 84 result = singleByteMappings.get( key ); 85 } 86 else if( length == 2 ) 87 { 88 int intKey = (code[offset]+256)%256; 89 intKey <<= 8; 90 intKey += (code[offset+1]+256)%256; 91 key = new Integer( intKey ); 92 93 result = doubleByteMappings.get( key ); 94 } 95 96 return result; 97 } 98 99 /** 100 * This will add a mapping. 101 * 102 * @param src The src to the mapping. 103 * @param dest The dest to the mapping. 104 * 105 * @throws IOException if the src is invalid. 106 */ 107 public void addMapping( byte[] src, String dest ) throws IOException 108 { 109 if( src.length == 1 ) 110 { 111 singleByteMappings.put( new Integer( 0xFF & src[0] ), dest ); 112 } 113 else if( src.length == 2 ) 114 { 115 int intSrc = src[0]&0xFF; 116 intSrc <<= 8; 117 intSrc |= (src[1]&0xFF); 118 doubleByteMappings.put( new Integer( intSrc ), dest ); 119 } 120 else 121 { 122 throw new IOException( "Mapping code should be 1 or two bytes and not " + src.length ); 123 } 124 } 125 126 127 /** 128 * This will add a codespace range. 129 * 130 * @param range A single codespace range. 131 */ 132 public void addCodespaceRange( CodespaceRange range ) 133 { 134 codeSpaceRanges.add( range ); 135 } 136 137 /** 138 * Getter for property codeSpaceRanges. 139 * 140 * @return Value of property codeSpaceRanges. 141 */ 142 public List<CodespaceRange> getCodeSpaceRanges() 143 { 144 return codeSpaceRanges; 145 } 146 147 /** 148 * Implementation of the usecmap operator. This will 149 * copy all of the mappings from one cmap to another. 150 * 151 * @param cmap The cmap to load mappings from. 152 */ 153 public void useCmap( CMap cmap ) 154 { 155 this.codeSpaceRanges.addAll( cmap.codeSpaceRanges ); 156 this.singleByteMappings.putAll( cmap.singleByteMappings ); 157 this.doubleByteMappings.putAll( cmap.doubleByteMappings ); 158 } 159 160 /** 161 * Check whether the given byte array is in codespace ranges or not. 162 * 163 * @param code The byte array to look for in the codespace range. 164 * 165 * @return true if the given byte array is in the codespace range. 166 */ 167 public boolean isInCodeSpaceRanges( byte[] code ) 168 { 169 return isInCodeSpaceRanges(code, 0, code.length); 170 } 171 172 /** 173 * Check whether the given byte array is in codespace ranges or not. 174 * 175 * @param code The byte array to look for in the codespace range. 176 * @param offset The starting offset within the byte array. 177 * @param length The length of the part of the array. 178 * 179 * @return true if the given byte array is in the codespace range. 180 */ 181 public boolean isInCodeSpaceRanges( byte[] code, int offset, int length ) 182 { 183 Iterator<CodespaceRange> it = codeSpaceRanges.iterator(); 184 while ( it.hasNext() ) 185 { 186 CodespaceRange range = it.next(); 187 if ( range != null && range.isInRange(code, offset, length) ) 188 { 189 return true; 190 } 191 } 192 return false; 193 } 194 }