001: /*
002: * Copyright (c) 2007, intarsys consulting GmbH
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * - Redistributions of source code must retain the above copyright notice,
008: * this list of conditions and the following disclaimer.
009: *
010: * - Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: *
014: * - Neither the name of intarsys nor the names of its contributors may be used
015: * to endorse or promote products derived from this software without specific
016: * prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
021: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
022: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
023: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
024: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
025: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
026: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
027: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
028: * POSSIBILITY OF SUCH DAMAGE.
029: */
030: package de.intarsys.pdf.cos;
031:
032: import java.io.UnsupportedEncodingException;
033: import java.util.Arrays;
034:
035: /**
036: * A name object.
037: */
038: public class COSName extends COSPrimitiveObject {
039: static public COSName constant(String name) {
040: return (COSName) COSName.create(name).beConstant();
041: }
042:
043: static public COSName create(byte[] bytes) {
044: return new COSName(bytes);
045: }
046:
047: static public COSName create(String name) {
048: byte[] bytes = null;
049: try {
050: bytes = name.getBytes("UTF-8"); //$NON-NLS-1$
051: } catch (UnsupportedEncodingException e) {
052: char[] chars = name.toCharArray();
053: bytes = new byte[chars.length];
054: for (int i = 0; i < chars.length; i++) {
055: bytes[i] = (byte) chars[i];
056: }
057: }
058: return new COSName(bytes);
059: }
060:
061: /** if string representation is needed it is lazy computed on base of UTF 8 */
062: private String string;
063:
064: /** the underlying byte representation */
065: private final byte[] bytes;
066:
067: /** cached hash value */
068: private int hash;
069:
070: /**
071: * COSName constructor.
072: *
073: * @param newName
074: * The name value for the object.
075: */
076: protected COSName(byte[] newName) {
077: super ();
078: bytes = newName;
079: computeHash();
080: }
081:
082: protected COSName(COSObject object) {
083: super (object);
084: COSName name = (COSName) object;
085: this .string = name.string;
086: this .bytes = name.bytes;
087: this .hash = name.hash;
088: }
089:
090: /*
091: * (non-Javadoc)
092: *
093: * @see de.intarsys.pdf.cos.COSObject#accept(de.intarsys.pdf.cos.ICOSObjectVisitor)
094: */
095: public java.lang.Object accept(ICOSObjectVisitor visitor)
096: throws COSVisitorException {
097: return visitor.visitFromName(this );
098: }
099:
100: /*
101: * (non-Javadoc)
102: *
103: * @see de.intarsys.pdf.cos.COSObject#asName()
104: */
105: public COSName asName() {
106: return this ;
107: }
108:
109: /*
110: * (non-Javadoc)
111: *
112: * @see de.intarsys.pdf.cos.COSObject#basicToString()
113: */
114: protected String basicToString() {
115: return "/" + stringValue(); //$NON-NLS-1$
116: }
117:
118: /**
119: * The bytes that make up this name (without "/")
120: *
121: * @return The bytes that make up this name (without "/")
122: */
123: public byte[] byteValue() {
124: return bytes;
125: }
126:
127: private void computeHash() {
128: int h = 0;
129: for (int i = 0; i < bytes.length; i++) {
130: h = (31 * h) + bytes[i];
131: }
132: hash = h;
133: }
134:
135: /*
136: * (non-Javadoc)
137: *
138: * @see de.intarsys.pdf.cos.COSObject#copyBasic(de.intarsys.pdf.cos.COSDocument)
139: */
140: protected COSObject copyBasic() {
141: return create(byteValue());
142: }
143:
144: protected String decode() {
145: /*
146: * UTF-8 Test: a UTF-8 encoded character starts with 110xxxxx or
147: * 1110xxxx or 11110xxx followed by 1 to 3 bytes in form: 10xxxxxx. This
148: * algorithm looks for the UTF-8 start and 1 followup character. If one
149: * sequence is found, UTF-8 is assumed, otherwise not. F8: 1111 1000 F0:
150: * 1111 0000 E0: 1110 0000 C0: 1100 0000 08: 1000 0000
151: */
152: boolean utf8 = false;
153: for (int i = 0; i < bytes.length; i++) {
154: if (bytes[i] < 0) {
155: int test = bytes[i] & 0x00F8;
156: if ((test == 0x00C0) || (test == 0x00E0)
157: || (test == 0x00F0)) {
158: if ((i + 1) == bytes.length) {
159: break;
160: }
161: i++;
162: if ((bytes[i] & 0x00C0) == 0x0080) {
163: utf8 = true;
164: }
165: break;
166: }
167: }
168: }
169:
170: if (utf8) {
171: try {
172: return new String(bytes, "UTF-8"); //$NON-NLS-1$
173: } catch (UnsupportedEncodingException e) {
174: return new String(bytes);
175: }
176: } else {
177: return new String(bytes);
178: }
179: }
180:
181: /*
182: * (non-Javadoc)
183: *
184: * @see java.lang.Object#equals(java.lang.Object)
185: */
186: public boolean equals(Object o) {
187: if (this == o) {
188: return true;
189: }
190: if (!(o instanceof COSName)) {
191: return false;
192: }
193: return Arrays.equals(bytes, ((COSName) o).byteValue());
194: }
195:
196: /*
197: * (non-Javadoc)
198: *
199: * @see java.lang.Object#hashCode()
200: */
201: public int hashCode() {
202: return hash;
203: }
204:
205: /*
206: * (non-Javadoc)
207: *
208: * @see de.intarsys.pdf.cos.COSObject#restoreState(java.lang.Object)
209: */
210: public void restoreState(Object object) {
211: super .restoreState(object);
212: COSName name = (COSName) object;
213: this .string = name.string;
214: this .hash = name.hash;
215: }
216:
217: /*
218: * (non-Javadoc)
219: *
220: * @see de.intarsys.tools.objectsession.ISaveStateSupport#saveState()
221: */
222: public Object saveState() {
223: return new COSName(this );
224: }
225:
226: /**
227: * The string value that makes up this name (without "/")
228: *
229: * @return The string value that makes up this name (without "/")
230: */
231: public java.lang.String stringValue() {
232: if (string == null) {
233: string = decode();
234: }
235: return string;
236: }
237: }
|