/* * $Id: NameTable.java,v 1.4 2009-02-12 13:53:57 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.font.ttf; import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.util.*; /** * * @author jon */ public class NameTable extends TrueTypeTable { /** * Values for platformID */ public static final short PLATFORMID_UNICODE = 0; public static final short PLATFORMID_MACINTOSH = 1; public static final short PLATFORMID_MICROSOFT = 3; /** * Values for platformSpecificID if platform is Mac */ public static final short ENCODINGID_MAC_ROMAN = 0; /** * Values for platformSpecificID if platform is Unicode */ public static final short ENCODINGID_UNICODE_DEFAULT = 0; public static final short ENCODINGID_UNICODE_V11 = 1; public static final short ENCODINGID_UNICODE_V2 = 3; /** * Values for language ID if platform is Mac */ public static final short LANGUAGEID_MAC_ENGLISH = 0; /** * Values for nameID */ public static final short NAMEID_COPYRIGHT = 0; public static final short NAMEID_FAMILY = 1; public static final short NAMEID_SUBFAMILY = 2; public static final short NAMEID_SUBFAMILY_UNIQUE = 3; public static final short NAMEID_FULL_NAME = 4; public static final short NAMEID_VERSION = 5; public static final short NAMEID_POSTSCRIPT_NAME = 6; public static final short NAMEID_TRADEMARK = 7; /** * The format of this table */ private short format; /** * The actual name records */ private SortedMap<NameRecord,String> records; /** Creates a new instance of NameTable */ protected NameTable() { super (TrueTypeTable.NAME_TABLE); records = Collections.synchronizedSortedMap(new TreeMap<NameRecord,String>()); } /** * Add a record to the table */ public void addRecord(short platformID, short platformSpecificID, short languageID, short nameID, String value) { NameRecord rec = new NameRecord(platformID, platformSpecificID, languageID, nameID); records.put(rec, value); } /** * Get a record from the table */ public String getRecord(short platformID, short platformSpecificID, short languageID, short nameID) { NameRecord rec = new NameRecord(platformID, platformSpecificID, languageID, nameID); return (String) records.get(rec); } /** * Remove a record from the table */ public void removeRecord(short platformID, short platformSpecificID, short languageID, short nameID) { NameRecord rec = new NameRecord(platformID, platformSpecificID, languageID, nameID); records.remove(rec); } /** * Determine if we have any records with a given platform ID */ public boolean hasRecords(short platformID) { for (Iterator i = records.keySet().iterator(); i.hasNext(); ) { NameRecord rec = (NameRecord) i.next(); if (rec.platformID == platformID) { return true; } } return false; } /** * Determine if we have any records with a given platform ID and * platform-specific ID */ public boolean hasRecords(short platformID, short platformSpecificID) { for (Iterator i = records.keySet().iterator(); i.hasNext(); ) { NameRecord rec = (NameRecord) i.next(); if (rec.platformID == platformID && rec.platformSpecificID == platformSpecificID) { return true; } } return false; } /** * Read the table from data */ public void setData(ByteBuffer data) { //read table header setFormat(data.getShort()); int count = data.getShort(); int stringOffset = data.getShort(); // read the records for (int i = 0; i < count; i++) { short platformID = data.getShort(); short platformSpecificID = data.getShort(); short languageID = data.getShort(); short nameID = data.getShort(); int length = data.getShort() & 0xFFFF; int offset = data.getShort() & 0xFFFF; // read the String data data.mark(); data.position(stringOffset + offset); ByteBuffer stringBuf = data.slice(); stringBuf.limit(length); data.reset(); // choose the character set String charsetName = getCharsetName(platformID, platformSpecificID); Charset charset = Charset.forName(charsetName); // parse the data as a string String value = charset.decode(stringBuf).toString(); // add to the mix addRecord(platformID, platformSpecificID, languageID, nameID, value); } } /** * Get the data in this table as a buffer */ public ByteBuffer getData() { // alocate the output buffer ByteBuffer buf = ByteBuffer.allocate(getLength()); // the start of string data short headerLength = (short) (6 + (12 * getCount())); // write the header buf.putShort(getFormat()); buf.putShort(getCount()); buf.putShort(headerLength); // the offset from the start of the strings table short curOffset = 0; // add the size of each record for (Iterator i = records.keySet().iterator(); i.hasNext();) { NameRecord rec = (NameRecord) i.next(); String value = (String) records.get(rec); // choose the charset String charsetName = getCharsetName(rec.platformID, rec.platformSpecificID); Charset charset = Charset.forName(charsetName); // encode ByteBuffer strBuf = charset.encode(value); short strLen = (short) (strBuf.remaining() & 0xFFFF); // write the IDs buf.putShort(rec.platformID); buf.putShort(rec.platformSpecificID); buf.putShort(rec.languageID); buf.putShort(rec.nameID); // write the size and offset buf.putShort(strLen); buf.putShort(curOffset); // remember or current position buf.mark(); // move to the current offset and write the data buf.position(headerLength + curOffset); buf.put(strBuf); // reset stuff buf.reset(); // increment offset curOffset += strLen; } // reset the pointer on the buffer buf.position(headerLength + curOffset); buf.flip(); return buf; } /** * Get the length of this table */ public int getLength() { // start with the size of the fixed header plus the size of the // records int length = 6 + (12 * getCount()); // add the size of each record for (Iterator i = records.keySet().iterator(); i.hasNext();) { NameRecord rec = (NameRecord) i.next(); String value = (String) records.get(rec); // choose the charset String charsetName = getCharsetName(rec.platformID, rec.platformSpecificID); Charset charset = Charset.forName(charsetName); // encode ByteBuffer buf = charset.encode(value); // add the size of the coded buffer length += buf.remaining(); } return length; } /** * Get the format of this table */ public short getFormat() { return format; } /** * Set the format of this table */ public void setFormat(short format) { this.format = format; } /** * Get the number of records in the table */ public short getCount() { return (short) records.size(); } /** * Get the charset name for a given platform, encoding and language */ public static String getCharsetName(int platformID, int encodingID) { String charset = "US-ASCII"; switch (platformID) { case PLATFORMID_UNICODE: charset = "UTF-16"; break; case PLATFORMID_MICROSOFT: charset = "UTF-16"; break; } return charset; } public Collection<String> getNames() { return Collections.unmodifiableCollection(records.values()); } /** Get a pretty string */ public String toString() { StringBuffer buf = new StringBuffer(); String indent = " "; buf.append(indent + "Format: " + getFormat() + "\n"); buf.append(indent + "Count : " + getCount() + "\n"); for (Iterator i = records.keySet().iterator(); i.hasNext();) { NameRecord rec = (NameRecord) i.next(); buf.append(indent + " platformID: " + rec.platformID); buf.append(" platformSpecificID: " + rec.platformSpecificID); buf.append(" languageID: " + rec.languageID); buf.append(" nameID: " + rec.nameID + "\n"); buf.append(indent + " " + records.get(rec) + "\n"); } return buf.toString(); } /** * A class to hold the data associated with each record */ class NameRecord implements Comparable { /** * Platform ID */ short platformID; /** * Platform Specific ID (Encoding) */ short platformSpecificID; /** * Language ID */ short languageID; /** * Name ID */ short nameID; /** * Create a new record */ NameRecord(short platformID, short platformSpecificID, short languageID, short nameID) { this.platformID = platformID; this.platformSpecificID = platformSpecificID; this.languageID = languageID; this.nameID = nameID; } /** * Compare two records */ public boolean equals(Object o) { return (compareTo(o) == 0); } /** * Compare two records */ public int compareTo(Object obj) { if (!(obj instanceof NameRecord)) { return -1; } NameRecord rec = (NameRecord) obj; if (platformID > rec.platformID) { return 1; } else if (platformID < rec.platformID) { return -1; } else if (platformSpecificID > rec.platformSpecificID) { return 1; } else if (platformSpecificID < rec.platformSpecificID) { return -1; } else if (languageID > rec.languageID) { return 1; } else if (languageID < rec.languageID) { return -1; } else if (nameID > rec.nameID) { return 1; } else if (nameID < rec.nameID) { return -1; } else { return 0; } } } }