001: /*
002: * $Id: NameTable.java,v 1.2 2007/12/20 18:33:30 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.nio.charset.Charset;
026: import java.util.Collections;
027: import java.util.Iterator;
028: import java.util.SortedMap;
029: import java.util.TreeMap;
030:
031: /**
032: *
033: * @author jon
034: */
035: public class NameTable extends TrueTypeTable {
036: /**
037: * Values for platformID
038: */
039: public static final short PLATFORMID_UNICODE = 0;
040: public static final short PLATFORMID_MACINTOSH = 1;
041: public static final short PLATFORMID_MICROSOFT = 3;
042:
043: /**
044: * Values for platformSpecificID if platform is Mac
045: */
046: public static final short ENCODINGID_MAC_ROMAN = 0;
047:
048: /**
049: * Values for platformSpecificID if platform is Unicode
050: */
051: public static final short ENCODINGID_UNICODE_DEFAULT = 0;
052: public static final short ENCODINGID_UNICODE_V11 = 1;
053: public static final short ENCODINGID_UNICODE_V2 = 3;
054:
055: /**
056: * Values for language ID if platform is Mac
057: */
058: public static final short LANGUAGEID_MAC_ENGLISH = 0;
059:
060: /**
061: * Values for nameID
062: */
063: public static final short NAMEID_COPYRIGHT = 0;
064: public static final short NAMEID_FAMILY = 1;
065: public static final short NAMEID_SUBFAMILY = 2;
066: public static final short NAMEID_SUBFAMILY_UNIQUE = 3;
067: public static final short NAMEID_FULL_NAME = 4;
068: public static final short NAMEID_VERSION = 5;
069: public static final short NAMEID_POSTSCRIPT_NAME = 6;
070: public static final short NAMEID_TRADEMARK = 7;
071: /**
072: * The format of this table
073: */
074: private short format;
075:
076: /**
077: * The actual name records
078: */
079: private SortedMap records;
080:
081: /** Creates a new instance of NameTable */
082: protected NameTable() {
083: super (TrueTypeTable.NAME_TABLE);
084:
085: records = Collections.synchronizedSortedMap(new TreeMap());
086: }
087:
088: /**
089: * Add a record to the table
090: */
091: public void addRecord(short platformID, short platformSpecificID,
092: short languageID, short nameID, String value) {
093: NameRecord rec = new NameRecord(platformID, platformSpecificID,
094: languageID, nameID);
095: records.put(rec, value);
096: }
097:
098: /**
099: * Get a record from the table
100: */
101: public String getRecord(short platformID, short platformSpecificID,
102: short languageID, short nameID) {
103:
104: NameRecord rec = new NameRecord(platformID, platformSpecificID,
105: languageID, nameID);
106: return (String) records.get(rec);
107: }
108:
109: /**
110: * Remove a record from the table
111: */
112: public void removeRecord(short platformID,
113: short platformSpecificID, short languageID, short nameID) {
114: NameRecord rec = new NameRecord(platformID, platformSpecificID,
115: languageID, nameID);
116: records.remove(rec);
117: }
118:
119: /**
120: * Determine if we have any records with a given platform ID
121: */
122: public boolean hasRecords(short platformID) {
123: for (Iterator i = records.keySet().iterator(); i.hasNext();) {
124: NameRecord rec = (NameRecord) i.next();
125:
126: if (rec.platformID == platformID) {
127: return true;
128: }
129: }
130:
131: return false;
132: }
133:
134: /**
135: * Determine if we have any records with a given platform ID and
136: * platform-specific ID
137: */
138: public boolean hasRecords(short platformID, short platformSpecificID) {
139: for (Iterator i = records.keySet().iterator(); i.hasNext();) {
140: NameRecord rec = (NameRecord) i.next();
141:
142: if (rec.platformID == platformID
143: && rec.platformSpecificID == platformSpecificID) {
144: return true;
145: }
146: }
147:
148: return false;
149: }
150:
151: /**
152: * Read the table from data
153: */
154: public void setData(ByteBuffer data) {
155: //read table header
156: setFormat(data.getShort());
157: int count = data.getShort();
158: int stringOffset = data.getShort();
159:
160: // read the records
161: for (int i = 0; i < count; i++) {
162: short platformID = data.getShort();
163: short platformSpecificID = data.getShort();
164: short languageID = data.getShort();
165: short nameID = data.getShort();
166:
167: int length = data.getShort();
168: int offset = data.getShort();
169:
170: // read the String data
171: data.mark();
172: data.position(stringOffset + offset);
173:
174: ByteBuffer stringBuf = data.slice();
175: stringBuf.limit(length);
176:
177: data.reset();
178:
179: // choose the character set
180: String charsetName = getCharsetName(platformID,
181: platformSpecificID);
182: Charset charset = Charset.forName(charsetName);
183:
184: // parse the data as a string
185: String value = charset.decode(stringBuf).toString();
186:
187: // add to the mix
188: addRecord(platformID, platformSpecificID, languageID,
189: nameID, value);
190: }
191: }
192:
193: /**
194: * Get the data in this table as a buffer
195: */
196: public ByteBuffer getData() {
197: // alocate the output buffer
198: ByteBuffer buf = ByteBuffer.allocate(getLength());
199:
200: // the start of string data
201: short headerLength = (short) (6 + (12 * getCount()));
202:
203: // write the header
204: buf.putShort(getFormat());
205: buf.putShort(getCount());
206: buf.putShort(headerLength);
207:
208: // the offset from the start of the strings table
209: short curOffset = 0;
210:
211: // add the size of each record
212: for (Iterator i = records.keySet().iterator(); i.hasNext();) {
213: NameRecord rec = (NameRecord) i.next();
214: String value = (String) records.get(rec);
215:
216: // choose the charset
217: String charsetName = getCharsetName(rec.platformID,
218: rec.platformSpecificID);
219: Charset charset = Charset.forName(charsetName);
220:
221: // encode
222: ByteBuffer strBuf = charset.encode(value);
223: short strLen = (short) strBuf.remaining();
224:
225: // write the IDs
226: buf.putShort(rec.platformID);
227: buf.putShort(rec.platformSpecificID);
228: buf.putShort(rec.languageID);
229: buf.putShort(rec.nameID);
230:
231: // write the size and offset
232: buf.putShort(strLen);
233: buf.putShort(curOffset);
234:
235: // remember or current position
236: buf.mark();
237:
238: // move to the current offset and write the data
239: buf.position(headerLength + curOffset);
240: buf.put(strBuf);
241:
242: // reset stuff
243: buf.reset();
244:
245: // increment offset
246: curOffset += strLen;
247: }
248:
249: // reset the pointer on the buffer
250: buf.position(headerLength + curOffset);
251: buf.flip();
252:
253: return buf;
254: }
255:
256: /**
257: * Get the length of this table
258: */
259: public int getLength() {
260: // start with the size of the fixed header plus the size of the
261: // records
262: int length = 6 + (12 * getCount());
263:
264: // add the size of each record
265: for (Iterator i = records.keySet().iterator(); i.hasNext();) {
266: NameRecord rec = (NameRecord) i.next();
267: String value = (String) records.get(rec);
268:
269: // choose the charset
270: String charsetName = getCharsetName(rec.platformID,
271: rec.platformSpecificID);
272: Charset charset = Charset.forName(charsetName);
273:
274: // encode
275: ByteBuffer buf = charset.encode(value);
276:
277: // add the size of the coded buffer
278: length += buf.remaining();
279: }
280:
281: return length;
282: }
283:
284: /**
285: * Get the format of this table
286: */
287: public short getFormat() {
288: return format;
289: }
290:
291: /**
292: * Set the format of this table
293: */
294: public void setFormat(short format) {
295: this .format = format;
296: }
297:
298: /**
299: * Get the number of records in the table
300: */
301: public short getCount() {
302: return (short) records.size();
303: }
304:
305: /**
306: * Get the charset name for a given platform, encoding and language
307: */
308: public static String getCharsetName(int platformID, int encodingID) {
309: String charset = "US-ASCII";
310:
311: switch (platformID) {
312: case PLATFORMID_UNICODE:
313: charset = "UTF-16";
314: break;
315: case PLATFORMID_MICROSOFT:
316: charset = "UTF-16";
317: break;
318: }
319:
320: return charset;
321: }
322:
323: /** Get a pretty string */
324: public String toString() {
325: StringBuffer buf = new StringBuffer();
326: String indent = " ";
327:
328: buf.append(indent + "Format: " + getFormat() + "\n");
329: buf.append(indent + "Count : " + getCount() + "\n");
330:
331: for (Iterator i = records.keySet().iterator(); i.hasNext();) {
332: NameRecord rec = (NameRecord) i.next();
333:
334: buf.append(indent + " platformID: " + rec.platformID);
335: buf
336: .append(" platformSpecificID: "
337: + rec.platformSpecificID);
338: buf.append(" languageID: " + rec.languageID);
339: buf.append(" nameID: " + rec.nameID + "\n");
340: buf.append(indent + " " + records.get(rec) + "\n");
341: }
342:
343: return buf.toString();
344: }
345:
346: /**
347: * A class to hold the data associated with each record
348: */
349: class NameRecord implements Comparable {
350: /**
351: * Platform ID
352: */
353: short platformID;
354:
355: /**
356: * Platform Specific ID (Encoding)
357: */
358: short platformSpecificID;
359:
360: /**
361: * Language ID
362: */
363: short languageID;
364:
365: /**
366: * Name ID
367: */
368: short nameID;
369:
370: /**
371: * Create a new record
372: */
373: NameRecord(short platformID, short platformSpecificID,
374: short languageID, short nameID) {
375: this .platformID = platformID;
376: this .platformSpecificID = platformSpecificID;
377: this .languageID = languageID;
378: this .nameID = nameID;
379: }
380:
381: /**
382: * Compare two records
383: */
384: public boolean equals(Object o) {
385: return (compareTo(o) == 0);
386: }
387:
388: /**
389: * Compare two records
390: */
391: public int compareTo(Object obj) {
392: if (!(obj instanceof NameRecord)) {
393: return -1;
394: }
395:
396: NameRecord rec = (NameRecord) obj;
397:
398: if (platformID > rec.platformID) {
399: return 1;
400: } else if (platformID < rec.platformID) {
401: return -1;
402: } else if (platformSpecificID > rec.platformSpecificID) {
403: return 1;
404: } else if (platformSpecificID < rec.platformSpecificID) {
405: return -1;
406: } else if (languageID > rec.languageID) {
407: return 1;
408: } else if (languageID < rec.languageID) {
409: return -1;
410: } else if (nameID > rec.nameID) {
411: return 1;
412: } else if (nameID < rec.nameID) {
413: return -1;
414: } else {
415: return 0;
416: }
417: }
418:
419: }
420: }
|