001: /*
002: * $Id: CmapTable.java,v 1.2 2007/12/20 18:33:31 rbair Exp $
003: *
004: * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
005: * Santa Clara, California 95054, U.S.A. All rights reserved.
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation; either
010: * version 2.1 of the License, or (at your option) any later version.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this library; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
020: */
021:
022: package com.sun.pdfview.font.ttf;
023:
024: import java.nio.ByteBuffer;
025: import java.util.Collection;
026: import java.util.Collections;
027: import java.util.Iterator;
028: import java.util.SortedMap;
029: import java.util.TreeMap;
030:
031: /**
032: * Represents the TTF "cmap" table
033: *
034: * @author jkaplan
035: */
036: public class CmapTable extends TrueTypeTable {
037:
038: /** Holds value of property version. */
039: private short version;
040:
041: /**
042: * Holds the CMap subtables, sorted properly
043: */
044: private SortedMap subtables;
045:
046: /** Creates a new instance of CmapTable */
047: protected CmapTable() {
048: super (TrueTypeTable.CMAP_TABLE);
049:
050: setVersion((short) 0x0);
051:
052: subtables = Collections.synchronizedSortedMap(new TreeMap());
053: }
054:
055: /**
056: * Add a CMap
057: */
058: public void addCMap(short platformID, short platformSpecificID,
059: CMap cMap) {
060: CmapSubtable key = new CmapSubtable(platformID,
061: platformSpecificID);
062: subtables.put(key, cMap);
063: }
064:
065: /**
066: * Get a CMap by platform and specific ID
067: */
068: public CMap getCMap(short platformID, short platformSpecificID) {
069: CmapSubtable key = new CmapSubtable(platformID,
070: platformSpecificID);
071: return (CMap) subtables.get(key);
072: }
073:
074: /**
075: * Get all CMaps
076: */
077: public CMap[] getCMaps() {
078: Collection c = subtables.values();
079: CMap[] maps = new CMap[c.size()];
080:
081: c.toArray(maps);
082:
083: return maps;
084: }
085:
086: /**
087: * Remove a CMap
088: */
089: public void removeCMap(short platformID, short platformSpecificID) {
090: CmapSubtable key = new CmapSubtable(platformID,
091: platformSpecificID);
092: subtables.remove(key);
093: }
094:
095: @Override
096: public void setData(ByteBuffer data) {
097: setVersion(data.getShort());
098:
099: short numberSubtables = data.getShort();
100:
101: for (int i = 0; i < numberSubtables; i++) {
102: short platformID = data.getShort();
103: short platformSpecificID = data.getShort();
104: int offset = data.getInt();
105:
106: data.mark();
107:
108: // get the position from the start of this buffer
109: data.position(offset);
110:
111: ByteBuffer mapData = data.slice();
112:
113: data.reset();
114:
115: try {
116: CMap cMap = CMap.getMap(mapData);
117: if (cMap != null) {
118: addCMap(platformID, platformSpecificID, cMap);
119: }
120: } catch (Exception ex) {
121: System.out.println("Error reading map. PlatformID="
122: + platformID + ", PlatformSpecificID="
123: + platformSpecificID);
124: System.out.println("Reason: " + ex);
125: }
126: }
127: }
128:
129: @Override
130: public ByteBuffer getData() {
131: ByteBuffer buf = ByteBuffer.allocate(getLength());
132:
133: // write the table header
134: buf.putShort(getVersion());
135: buf.putShort((short) subtables.size());
136:
137: // the current offset to write to, starts at the end of the
138: // subtables
139: int curOffset = 4 + (subtables.size() * 8);
140:
141: // write the subtables
142: for (Iterator i = subtables.keySet().iterator(); i.hasNext();) {
143: CmapSubtable cms = (CmapSubtable) i.next();
144: CMap map = (CMap) subtables.get(cms);
145:
146: buf.putShort(cms.platformID);
147: buf.putShort(cms.platformSpecificID);
148: buf.putInt(curOffset);
149:
150: curOffset += map.getLength();
151: }
152:
153: // write the tables
154: for (Iterator i = subtables.values().iterator(); i.hasNext();) {
155: CMap map = (CMap) i.next();
156: buf.put(map.getData());
157: }
158:
159: // reset the position to the start of the buffer
160: buf.flip();
161:
162: return buf;
163: }
164:
165: /**
166: * Get the size of the table, in bytes
167: */
168: @Override
169: public int getLength() {
170: // start with the size of the fixed data
171: int length = 4;
172:
173: // add the size of the subtables
174: length += subtables.size() * 8;
175:
176: // add the size of the dynamic data
177: for (Iterator i = subtables.values().iterator(); i.hasNext();) {
178: // add the size of the subtable data
179: CMap map = (CMap) i.next();
180: length += map.getLength();
181: }
182:
183: return length;
184: }
185:
186: /** Getter for property version.
187: * @return Value of property version.
188: *
189: */
190: public short getVersion() {
191: return this .version;
192: }
193:
194: /** Setter for property version.
195: * @param version New value of property version.
196: *
197: */
198: public void setVersion(short version) {
199: this .version = version;
200: }
201:
202: /**
203: * Get the number of tables
204: */
205: public short getNumberSubtables() {
206: return (short) subtables.size();
207: }
208:
209: /** Print a pretty string */
210: @Override
211: public String toString() {
212: StringBuffer buf = new StringBuffer();
213: String indent = " ";
214:
215: buf.append(indent + "Version: " + this .getVersion() + "\n");
216: buf.append(indent + "NumMaps: " + this .getNumberSubtables()
217: + "\n");
218:
219: for (Iterator i = subtables.keySet().iterator(); i.hasNext();) {
220: CmapSubtable key = (CmapSubtable) i.next();
221:
222: buf.append(indent + "Map: platformID: " + key.platformID
223: + " PlatformSpecificID: " + key.platformSpecificID
224: + "\n");
225:
226: CMap map = (CMap) subtables.get(key);
227:
228: buf.append(map.toString());
229: }
230:
231: return buf.toString();
232: }
233:
234: class CmapSubtable implements Comparable {
235: /**
236: * The platformID for this subtable
237: */
238: short platformID;
239:
240: /**
241: * The platform-specific id
242: */
243: short platformSpecificID;
244:
245: /**
246: * Create a Cmap subtable
247: */
248: protected CmapSubtable(short platformID,
249: short platformSpecificID) {
250: this .platformID = platformID;
251: this .platformSpecificID = platformSpecificID;
252: }
253:
254: /**
255: * Compare two subtables
256: */
257: @Override
258: public boolean equals(Object obj) {
259: return (compareTo(obj) == 0);
260: }
261:
262: /**
263: * Sort ascending by platform ID and then specific ID
264: */
265: public int compareTo(Object obj) {
266: if (!(obj instanceof CmapSubtable)) {
267: return -1;
268: }
269:
270: CmapSubtable cms = (CmapSubtable) obj;
271: if (platformID < cms.platformID) {
272: return -1;
273: } else if (platformID > cms.platformID) {
274: return 1;
275: } else {
276: if (platformSpecificID < cms.platformSpecificID) {
277: return -1;
278: } else if (platformSpecificID > cms.platformSpecificID) {
279: return 1;
280: } else {
281: return 0;
282: }
283: }
284: }
285: }
286:
287: }
|