/* * Copyright 2006-2017 ICEsoft Technologies Canada Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an "AS * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. See the License for the specific language * governing permissions and limitations under the License. */ package org.icepdf.core.pobjects; import java.util.logging.Logger; /** * <p>A <code>name</code> class is an atomic symbol uniquely defined by a sequence of * characters. Uniquely defined means that any two name objects made up of the * same sequence of characters are identical. Atomic means * that a name has no internal structure, although it is defined by a sequence * of characters, those characters are not "elements" of the name. </p> * <br> * <p>A slash character (/) introduces a name. The slash is not part of the name * itself, but a prefix indicating that the following sequence of characters * constitutes a name. There can be no white-space characters between the slash * and the first character in the name. The name may include any regular * characters, but no delimiter or white-space characters. Uppercase and * lowercase letters are considered distinct forexample, * /A and /a are different names.</p> * <br> * <p>Names are similar to References in that objects in a PDF document can be * accessed by their use. The Library class can result in any Name object and return * the corresponding PDF object.</p> * * @since 1.1 */ public class Name { private static final Logger logger = Logger.getLogger(Name.class.toString()); private static final int HEX_CHAR = 0X23; // String representing the name of the name private String name; /** * Create a new instance of a Name object. * * @param name the name value of the Name object */ public Name(String name) { if (name != null) { this.name = convertHexChars(new StringBuilder(name)); } } /** * Create a new instance of a Name object. * * @param name the name value of the Name object */ public Name(StringBuilder name) { this.name = convertHexChars(name); } /** * Gets the name of the Name object. * * @return name of the object */ public String getName() { return name; } /** * Gets the string value of the Name object. This is the same as getName() * * @return string representation of the name. * @see #getName() */ public String toString() { return name; } /** * Indicates whether some other Name object is "equal to" this one * * @param obj name object that this Name object is compared against * @return true, if this object is the same as the obj argument; * false, otherwise. */ public boolean equals(Object obj) { if (obj instanceof Name) { return equals((Name) obj); } else { return obj != null && name.equals(obj); } } /** * Indicates whether some other Name object is "equal to" this one * * @param obj name object that this Name object is compared against * @return true, if this object is the same as the obj argument; * false, otherwise. */ public boolean equals(Name obj) { return obj != null && name.equals(obj.getName()); } /** * Indicates whether some other String object is "equal to" this one * * @param obj string object that this Name object is compared against * @return true, if this object is the same as the obj argument; * false, otherwise. */ public boolean equals(String obj) { return obj != null && name.equals(obj); } /** * Returns a hash code value for the Name object. This hash is based * on the String representation of name of the Name object. * * @return a hash code value for this object. */ public int hashCode() { return name.hashCode(); } /** * Utility Method converting Name object hext notation to ascii. For * example #41 should be represented as 'A'. The hex format will always * be #XX where XX is a 2 digit hex value. The spec says that # can't be * used in a string but I guess we'll see. * * @param name PDF name object string to be checked for hex codes. * @return full ascii encoded name string. */ private String convertHexChars(StringBuilder name) { // we need to search for an instance of # and try and convert to hex try { for (int i = 0; i < name.length(); i++) { if (name.charAt(i) == HEX_CHAR) { // convert digits to hex. String hex = name.substring(i + 1, i + 3); name.delete(i, i + 3); // convert digits to hex. int charDd = Integer.parseInt(hex, 16); if (charDd <= 127) { name.insert(i, (char) charDd); } else { name.insert(i, convert(hex)); } } } } catch (Throwable e) { logger.finer("Error parsing hexadecimal characters."); // we are going to bail on any exception and just return the original // string. return name.toString(); } return name.toString(); } /** * Converts a hex string to formatted unicode string. * * @param hex 2-digit hex number. * @return hex represented as unicode. */ private String convert(String hex) { StringBuilder output = new StringBuilder(); output.append("\\u"); // standard unicode format. for (int j = 0, max = 4 - hex.length(); j < max; j++) { output.append("0"); } output.append(hex.toLowerCase()); return output.toString(); } }