001: /**
002: * Copyright (c) 2004-2005, www.pdfbox.org
003: * All rights reserved.
004: *
005: * Redistribution and use in source and binary forms, with or without
006: * modification, are permitted provided that the following conditions are met:
007: *
008: * 1. Redistributions of source code must retain the above copyright notice,
009: * this list of conditions and the following disclaimer.
010: * 2. 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: * 3. Neither the name of pdfbox; nor the names of its
014: * contributors may be used to endorse or promote products derived from this
015: * software without specific prior written permission.
016: *
017: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
018: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
019: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
020: * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
021: * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
022: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
023: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
024: * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
025: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
026: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
027: *
028: * http://www.pdfbox.org
029: *
030: */package org.pdfbox.pdmodel.common;
031:
032: import java.io.IOException;
033: import java.lang.reflect.Constructor;
034: import java.util.ArrayList;
035: import java.util.Collections;
036: import java.util.HashMap;
037: import java.util.List;
038: import java.util.Map;
039:
040: import org.pdfbox.cos.COSArray;
041: import org.pdfbox.cos.COSBase;
042: import org.pdfbox.cos.COSDictionary;
043: import org.pdfbox.cos.COSString;
044:
045: /**
046: * This class represends a PDF Name tree. See the PDF Reference 1.5 section 3.8.5
047: * for more details.
048: *
049: * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
050: * @version $Revision: 1.4 $
051: */
052: public class PDNameTreeNode implements COSObjectable {
053: private COSDictionary node;
054: private Class valueType = null;
055:
056: /**
057: * Constructor.
058: *
059: * @param valueClass The PD Model type of object that is the value.
060: */
061: public PDNameTreeNode(Class valueClass) {
062: node = new COSDictionary();
063: valueType = valueClass;
064: }
065:
066: /**
067: * Constructor.
068: *
069: * @param dict The dictionary that holds the name information.
070: * @param valueClass The PD Model type of object that is the value.
071: */
072: public PDNameTreeNode(COSDictionary dict, Class valueClass) {
073: node = dict;
074: valueType = valueClass;
075: }
076:
077: /**
078: * Convert this standard java object to a COS object.
079: *
080: * @return The cos object that matches this Java object.
081: */
082: public COSBase getCOSObject() {
083: return node;
084: }
085:
086: /**
087: * Convert this standard java object to a COS object.
088: *
089: * @return The cos object that matches this Java object.
090: */
091: public COSDictionary getCOSDictionary() {
092: return node;
093: }
094:
095: /**
096: * Return the children of this node. This list will contain PDNameTreeNode objects.
097: *
098: * @return The list of children or null if there are no children.
099: */
100: public List getKids() {
101:
102: List retval = null;
103: COSArray kids = (COSArray) node.getDictionaryObject("Kids");
104: if (kids != null) {
105: List pdObjects = new ArrayList();
106: for (int i = 0; i < kids.size(); i++) {
107: pdObjects.add(createChildNode((COSDictionary) kids
108: .getObject(i)));
109: }
110: retval = new COSArrayList(pdObjects, kids);
111: }
112:
113: return retval;
114: }
115:
116: /**
117: * Set the children of this named tree.
118: *
119: * @param kids The children of this named tree.
120: */
121: public void setKids(List kids) {
122: node.setItem("Kids", COSArrayList.converterToCOSArray(kids));
123: }
124:
125: /**
126: * The name to retrieve.
127: *
128: * @param name The name in the tree.
129: *
130: * @return The value of the name in the tree.
131: *
132: * @throws IOException If an there is a problem creating the destinations.
133: */
134: public Object getValue(String name) throws IOException {
135: Object retval = null;
136: Map names = getNames();
137: if (names != null) {
138: retval = names.get(name);
139: } else {
140: List kids = getKids();
141: for (int i = 0; i < kids.size() && retval == null; i++) {
142: PDNameTreeNode childNode = (PDNameTreeNode) kids.get(i);
143: if (childNode.getLowerLimit().compareTo(name) <= 0
144: && childNode.getUpperLimit().compareTo(name) >= 0) {
145: retval = childNode.getValue(name);
146: }
147: }
148: }
149: return retval;
150: }
151:
152: /**
153: * This will return a map of names. The key will be a java.lang.String the value will
154: * depend on where this class is being used.
155: *
156: * @return A map of cos objects.
157: *
158: * @throws IOException If there is an error while creating the sub types.
159: */
160: public Map getNames() throws IOException {
161: Map names = null;
162: COSArray namesArray = (COSArray) node
163: .getDictionaryObject("Names");
164: if (namesArray != null) {
165: names = new HashMap();
166: for (int i = 0; i < namesArray.size(); i += 2) {
167: COSString key = (COSString) namesArray.getObject(i);
168: COSBase cosValue = namesArray.getObject(i + 1);
169: Object pdValue = convertCOSToPD(cosValue);
170:
171: names.put(key.getString(), pdValue);
172: }
173: names = Collections.unmodifiableMap(names);
174: }
175:
176: return names;
177: }
178:
179: /**
180: * Method to convert the COS value in the name tree to the PD Model object. The
181: * default implementation will simply use reflection to create the correct object
182: * type. Subclasses can do whatever they want.
183: *
184: * @param base The COS object to convert.
185: * @return The converted PD Model object.
186: * @throws IOException If there is an error during creation.
187: */
188: protected Object convertCOSToPD(COSBase base) throws IOException {
189: Object retval = null;
190: try {
191: Constructor ctor = valueType
192: .getConstructor(new Class[] { base.getClass() });
193: retval = ctor.newInstance(new Object[] { base });
194: } catch (Throwable t) {
195: throw new IOException(
196: "Error while trying to create value in named tree:"
197: + t.getMessage());
198:
199: }
200: return retval;
201: }
202:
203: /**
204: * Create a child node object.
205: *
206: * @param dic The dictionary for the child node object to refer to.
207: * @return The new child node object.
208: */
209: protected PDNameTreeNode createChildNode(COSDictionary dic) {
210: return new PDNameTreeNode(dic, valueType);
211: }
212:
213: /**
214: * Set the names of for this node. The keys should be java.lang.String and the
215: * values must be a COSObjectable. This method will set the appropriate upper and lower
216: * limits based on the keys in the map.
217: *
218: * @param names The map of names to objects.
219: */
220: public void setNames(Map names) {
221: if (names == null) {
222: node.setItem("Names", (COSObjectable) null);
223: node.setItem("Limits", (COSObjectable) null);
224: } else {
225: List keys = new ArrayList(names.keySet());
226: Collections.sort(keys);
227: COSArray array = new COSArray();
228: for (int i = 0; i < keys.size(); i++) {
229: String key = (String) keys.get(i);
230: array.add(new COSString(key));
231: COSObjectable obj = (COSObjectable) names.get(key);
232: array.add(obj);
233: }
234: String lower = null;
235: String upper = null;
236: if (keys.size() > 0) {
237: lower = (String) keys.get(0);
238: upper = (String) keys.get(keys.size() - 1);
239: }
240: setUpperLimit(upper);
241: setLowerLimit(lower);
242: node.setItem("Names", array);
243: }
244: }
245:
246: /**
247: * Get the highest value for a key in the name map.
248: *
249: * @return The highest value for a key in the map.
250: */
251: public String getUpperLimit() {
252: String retval = null;
253: COSArray arr = (COSArray) node.getDictionaryObject("Limits");
254: if (arr != null) {
255: retval = arr.getString(1);
256: }
257: return retval;
258: }
259:
260: /**
261: * Set the highest value for the key in the map.
262: *
263: * @param upper The new highest value for a key in the map.
264: */
265: private void setUpperLimit(String upper) {
266: COSArray arr = (COSArray) node.getDictionaryObject("Limits");
267: if (arr == null) {
268: arr = new COSArray();
269: arr.add(null);
270: arr.add(null);
271: }
272: arr.setString(1, upper);
273: }
274:
275: /**
276: * Get the lowest value for a key in the name map.
277: *
278: * @return The lowest value for a key in the map.
279: */
280: public String getLowerLimit() {
281: String retval = null;
282: COSArray arr = (COSArray) node.getDictionaryObject("Limits");
283: if (arr != null) {
284: retval = arr.getString(0);
285: }
286: return retval;
287: }
288:
289: /**
290: * Set the lowest value for the key in the map.
291: *
292: * @param lower The new lowest value for a key in the map.
293: */
294: private void setLowerLimit(String lower) {
295: COSArray arr = (COSArray) node.getDictionaryObject("Limits");
296: if (arr == null) {
297: arr = new COSArray();
298: arr.add(null);
299: arr.add(null);
300: }
301: arr.setString(0, lower);
302: }
303: }
|