1 /* ==================================================================== 2 * The Apache Software License, Version 1.1 3 * 4 * Copyright (c) 2000 The Apache Software Foundation. All rights 5 * reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in 16 * the documentation and/or other materials provided with the 17 * distribution. 18 * 19 * 3. The end-user documentation included with the redistribution, 20 * if any, must include the following acknowledgment: 21 * "This product includes software developed by the 22 * Apache Software Foundation (http://www.apache.org/)." 23 * Alternately, this acknowledgment may appear in the software itself, 24 * if and wherever such third-party acknowledgments normally appear. 25 * 26 * 4. The names "Apache" and "Apache Software Foundation" must 27 * not be used to endorse or promote products derived from this 28 * software without prior written permission. For written 29 * permission, please contact apache@apache.org. 30 * 31 * 5. Products derived from this software may not be called "Apache", 32 * nor may "Apache" appear in their name, without prior written 33 * permission of the Apache Software Foundation. 34 * 35 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 36 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 37 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 38 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 39 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 40 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 41 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 42 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 43 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 44 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 45 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 46 * SUCH DAMAGE. 47 * ==================================================================== 48 * 49 * This software consists of voluntary contributions made by many 50 * individuals on behalf of the Apache Software Foundation. For more 51 * information on the Apache Software Foundation, please see 52 * <http://www.apache.org/>. 53 * 54 * Portions of this software are based upon public domain software 55 * originally written at the National Center for Supercomputing Applications, 56 * University of Illinois, Urbana-Champaign. 57 * 58 * Portions of this software are based upon public domain software 59 * originally written at the National Center for Supercomputing Applications, 60 * University of Illinois, Urbana-Champaign. 61 */ 62 63 package org.apache.poi.hpsf; 64 65 import java.util.*; 66 import org.apache.poi.hpsf.littleendian.*; 67 68 /** 69 * <p>A property in a {@link Section} of a {@link PropertySet}.</p> 70 * 71 * <p>The property's <strong>ID</strong> gives the property a meaning 72 * in the context of its {@link Section}. Each {@link Section} spans 73 * its own name space of property IDs.</p> 74 * 75 * <p>The property's <strong>type</strong> determines how its 76 * <strong>value</strong> is interpreted. For example, if the type is 77 * {@link Variant#VT_LPSTR} (byte string), the value consists of a 78 * {@link DWord} telling how many bytes the string contains. The bytes 79 * follow immediately, including any null bytes that terminate the 80 * string. The type {@link Variant#VT_I4} denotes a four-byte integer 81 * value, {@link Variant#VT_FILETIME} some date and time (of a 82 * file).</p> 83 * 84 * <p><strong>FIXME:</strong> Reading of other types than those 85 * mentioned above and the dictionary property is not yet 86 * implemented.</p> 87 * 88 * @see Section 89 * @see Variant 90 * 91 * @author Rainer Klute (klute@rainer-klute.de) 92 * @author Drew Varner (Drew.Varner InAndAround sc.edu) 93 * 94 * @version $Id: Property.java,v 1.5 2002/05/06 23:25:35 acoliver Exp $ 95 * @since 2002-02-09 96 */ 97 public class Property 98 { 99 100 private int id; 101 102 /** 103 * <p>Returns the property's ID.</p> 104 */ 105 public int getID() 106 { 107 return id; 108 } 109 110 111 112 private int type; 113 114 /** 115 * <p>Returns the property's type.</p> 116 */ 117 public int getType() 118 { 119 return type; 120 } 121 122 123 124 private Object value; 125 126 /** 127 * <p>Returns the property value's.</p> 128 */ 129 public Object getValue() 130 { 131 return value; 132 } 133 134 135 136 /** 137 * <p>Creates a {@link Property} instance by reading its bytes 138 * from the property set stream.</p> 139 * 140 * @param id The property's ID. 141 * 142 * @param src The bytes the property set stream consists of. 143 * 144 * @param offset The property's type/value pair's offset in the 145 * section. 146 * 147 * @param length The property's type/value pair's length in bytes. 148 * list. 149 */ 150 public Property(final int id, final byte[] src, final int offset, 151 int length) 152 { 153 this.id = id; 154 155 /* ID 0 is a special case since it specifies a dictionary of 156 * property IDs and property names. */ 157 if (id == 0) 158 { 159 value = readDictionary(src, offset, length); 160 return; 161 } 162 163 /* FIXME: Support this! */ 164 // /* ID 1 is another special case: It denotes the code page of 165 // * byte strings in this section. */ 166 // if (id == 1) 167 // { 168 // value = readCodepage(src, offset); 169 // return; 170 // } 171 172 int o = offset; 173 type = new DWord(src, o).intValue(); 174 o += DWord.LENGTH; 175 176 /* FIXME: Support reading more types! */ 177 switch (type) 178 { 179 case Variant.VT_I4: 180 { 181 /* Read a word. In Java it is represented as an 182 Integer object. */ 183 value = new Integer(new DWord(src, o).intValue()); 184 break; 185 } 186 case Variant.VT_FILETIME: 187 { 188 /* Read a FILETIME object. In Java it is represented 189 as a Date. */ 190 final int low = new DWord(src, o).intValue(); 191 o += DWord.LENGTH; 192 final int high = new DWord(src, o).intValue(); 193 value = Util.filetimeToDate(high, low); 194 break; 195 } 196 case Variant.VT_LPSTR: 197 { 198 /* Read a byte string. In Java it is represented as a 199 String. The null bytes at the end of the byte 200 strings must be stripped. */ 201 final int first = o + DWord.LENGTH; 202 int last = first + new DWord(src, o).intValue() - 1; 203 o += DWord.LENGTH; 204 while (src[last] == 0 && first <= last) 205 last--; 206 value = new String(src, first, last - first + 1); 207 break; 208 } 209 case Variant.VT_CF: 210 { 211 /* The first four bytes in src, from rc[offset] to 212 * src[offset + 3] contain the DWord for VT_CF, so 213 * skip it, we don't need it. */ 214 215 /* Truncate the length of the return array by a DWord 216 * length (4 bytes). */ 217 length = length - DWord.LENGTH; 218 219 final byte[] v = new byte[length]; 220 for (int i = 0; i < length; i++) 221 v[i] = src[o + i]; 222 value = v; 223 break; 224 } 225 case Variant.VT_BOOL: 226 { 227 /* The first four bytes in src, from src[offset] to 228 * src[offset + 3] contain the DWord for VT_BOOL, so 229 * skip it, we don't need it. */ 230 final int first = o + DWord.LENGTH; 231 DWord bool = new DWord(src,o); 232 if (bool.intValue() == -1) 233 { 234 value = new Boolean(true); 235 } 236 else if (bool.intValue() == 0) 237 { 238 value = new Boolean(false); 239 } 240 else 241 /* FIXME: Someone might invent a new 242 * HPSFRuntimeException subclass 243 * IllegalPropertySetDataException for this and 244 * similar cases. */ 245 throw new HPSFRuntimeException 246 ("Illegal property set data: A boolean must be " + 247 "either -1 (true) or 0 (false)."); 248 break; 249 } 250 default: 251 { 252 final byte[] v = new byte[length]; 253 for (int i = 0; i < length; i++) 254 v[i] = src[offset + i]; 255 value = v; 256 break; 257 } 258 } 259 } 260 261 262 263 /** 264 * <p>Reads a dictionary.</p> 265 * 266 * @param src The byte array containing the bytes making out the 267 * dictionary. 268 * 269 * @param offset At this offset within <var>src</var> the 270 * dictionary starts. 271 * 272 * @param length The dictionary contains at most this many bytes. 273 */ 274 protected Map readDictionary(final byte[] src, final int offset, 275 final int length) 276 { 277 /* FIXME: Check the length! */ 278 int o = offset; 279 280 /* Read the number of dictionary entries. */ 281 final int nrEntries = new DWord(src, o).intValue(); 282 o += DWord.LENGTH; 283 284 final Map m = new HashMap(nrEntries, (float) 1.0); 285 for (int i = 0; i < nrEntries; i++) 286 { 287 /* The key */ 288 final Integer id = new Integer(new DWord(src, o).intValue()); 289 o += DWord.LENGTH; 290 291 /* The value (a string) */ 292 final int sLength = new DWord(src, o).intValue(); 293 o += DWord.LENGTH; 294 /* Strip trailing 0x00 bytes. */ 295 int l = sLength; 296 while (src[o + l - 1] == 0x00) 297 l--; 298 final String s = new String(src, o, l); 299 o += sLength; 300 m.put(id, s); 301 } 302 return m; 303 } 304 305 306 307 /** 308 * <p>Reads a code page.</p> 309 * 310 * @param src The byte array containing the bytes making out the 311 * code page. 312 * 313 * @param offset At this offset within <var>src</var> the code 314 * page starts. 315 */ 316 protected int readCodePage(final byte[] src, final int offset) 317 { 318 throw new UnsupportedOperationException("FIXME"); 319 } 320 321 } 322