1 /* 2 * ==================================================================== 3 * The Apache Software License, Version 1.1 4 * 5 * Copyright (c) 2000 The Apache Software Foundation. All rights 6 * reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in 17 * the documentation and/or other materials provided with the 18 * distribution. 19 * 20 * 3. The end-user documentation included with the redistribution, 21 * if any, must include the following acknowledgment: 22 * "This product includes software developed by the 23 * Apache Software Foundation (http://www.apache.org/)." 24 * Alternately, this acknowledgment may appear in the software itself, 25 * if and wherever such third-party acknowledgments normally appear. 26 * 27 * 4. The names "Apache" and "Apache Software Foundation" must 28 * not be used to endorse or promote products derived from this 29 * software without prior written permission. For written 30 * permission, please contact apache@apache.org. 31 * 32 * 5. Products derived from this software may not be called "Apache", 33 * nor may "Apache" appear in their name, without prior written 34 * permission of the Apache Software Foundation. 35 * 36 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 37 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 38 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 39 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 40 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 41 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 42 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 43 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 44 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 45 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 46 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 47 * SUCH DAMAGE. 48 * ==================================================================== 49 * 50 * This software consists of voluntary contributions made by many 51 * individuals on behalf of the Apache Software Foundation. For more 52 * information on the Apache Software Foundation, please see 53 * <http://www.apache.org/>. 54 */ 55 package org.apache.poi.hpsf; 56 57 import java.util.*; 58 import org.apache.poi.util.LittleEndian; 59 import org.apache.poi.hpsf.wellknown.*; 60 61 /** 62 * <p>Represents a section in a {@link PropertySet}.</p> 63 * 64 * @author Rainer Klute (klute@rainer-klute.de) 65 * @author Drew Varner (Drew.Varner allUpIn sc.edu) 66 * @version $Id: Section.java,v 1.7 2002/07/17 16:23:22 klute Exp $ 67 * @since 2002-02-09 68 */ 69 public class Section 70 { 71 72 /** 73 * <p>Maps property IDs to section-private PID strings. These 74 * strings can be found in the property with ID 0.</p> 75 */ 76 protected Map dictionary; 77 78 private ClassID formatID; 79 80 81 /** 82 * <p>Returns the format ID. The format ID is the "type" of the 83 * section.</p> 84 * 85 * @return The format ID 86 */ 87 public ClassID getFormatID() 88 { 89 return formatID; 90 } 91 92 93 94 private long offset; 95 96 97 /** 98 * <p>Returns the offset of the section in the stream.</p> 99 * 100 * @return The offset of the section in the stream. 101 */ 102 public long getOffset() 103 { 104 return offset; 105 } 106 107 108 109 private int size; 110 111 112 /** 113 * <p>Returns the section's size in bytes.</p> 114 * 115 * @return The section's size in bytes. 116 */ 117 public int getSize() 118 { 119 return size; 120 } 121 122 123 124 private int propertyCount; 125 126 127 /** 128 * <p>Returns the number of properties in this section.</p> 129 * 130 * @return The number of properties in this section. 131 */ 132 public int getPropertyCount() 133 { 134 return propertyCount; 135 } 136 137 138 139 private Property[] properties; 140 141 142 /** 143 * <p>Returns this section's properties.</p> 144 * 145 * @return This section's properties. 146 */ 147 public Property[] getProperties() 148 { 149 return properties; 150 } 151 152 153 154 /** 155 * <p>Creates a {@link Section} instance from a byte array.</p> 156 * 157 * @param src Contains the complete property set stream. 158 * @param offset The position in the stream that points to the 159 * section's format ID. 160 */ 161 public Section(final byte[] src, int offset) 162 { 163 /* 164 * Read the format ID. 165 */ 166 formatID = new ClassID(src, offset); 167 offset += ClassID.LENGTH; 168 169 /* 170 * Read the offset from the stream's start and positions to 171 * the section header. 172 */ 173 this.offset = LittleEndian.getUInt(src, offset); 174 offset = (int)this.offset; 175 176 /* 177 * Read the section length. 178 */ 179 size = (int)LittleEndian.getUInt(src, offset); 180 offset += LittleEndian.INT_SIZE; 181 182 /* 183 * Read the number of properties. 184 */ 185 propertyCount = (int)LittleEndian.getUInt(src, offset); 186 offset += LittleEndian.INT_SIZE; 187 188 /* 189 * Read the properties. The offset is positioned at the first 190 * entry of the property list. 191 */ 192 properties = new Property[propertyCount]; 193 for (int i = 0; i < properties.length; i++) { 194 final int id = (int)LittleEndian.getUInt(src, offset); 195 offset += LittleEndian.INT_SIZE; 196 197 /* 198 * Offset from the section. 199 */ 200 final int sOffset = (int)LittleEndian.getUInt(src, offset); 201 offset += LittleEndian.INT_SIZE; 202 203 /* 204 * Calculate the length of the property. 205 */ 206 int length; 207 if (i == properties.length - 1) { 208 length = (int)(src.length - this.offset - sOffset); 209 } else { 210 length = (int) 211 LittleEndian.getUInt(src, offset + LittleEndian.INT_SIZE) - 212 sOffset; 213 } 214 215 /* 216 * Create it. 217 */ 218 properties[i] = 219 new Property(id, src, this.offset + sOffset, length); 220 } 221 222 /* 223 * Extract the dictionary (if available). 224 */ 225 dictionary = (Map) getProperty(0); 226 } 227 228 229 230 /** 231 * <p>Returns the value of the property with the specified ID. If 232 * the property is not available, <code>null</code> is returned 233 * and a subsequent call to {@link #wasNull} will return 234 * <code>true</code>.</p> 235 * 236 * @param id The property's ID 237 * 238 * @return The property's value 239 */ 240 protected Object getProperty(final int id) 241 { 242 wasNull = false; 243 for (int i = 0; i < properties.length; i++) 244 if (id == properties[i].getID()) 245 return properties[i].getValue(); 246 wasNull = true; 247 return null; 248 } 249 250 251 252 /** 253 * <p>Returns the value of the numeric property with the specified 254 * ID. If the property is not available, 0 is returned. A 255 * subsequent call to {@link #wasNull} will return 256 * <code>true</code> to let the caller distinguish that case from 257 * a real property value of 0.</p> 258 * 259 * @param id The property's ID 260 * 261 * @return The property's value 262 */ 263 protected int getPropertyIntValue(final int id) 264 { 265 /* FIXME: Find out why the following is a Long instead of an 266 * Integer! */ 267 final Long i = (Long) getProperty(id); 268 if (i != null) 269 return i.intValue(); 270 else 271 return 0; 272 } 273 274 275 276 /** 277 * <p>Returns the value of the boolean property with the specified 278 * ID. If the property is not available, <code>false</code> is 279 * returned. A subsequent call to {@link #wasNull} will return 280 * <code>true</code> to let the caller distinguish that case from 281 * a real property value of <code>false</code>.</p> 282 * 283 * @param id The property's ID 284 * 285 * @return The property's value 286 */ 287 protected boolean getPropertyBooleanValue(final int id) 288 { 289 final Boolean b = (Boolean) getProperty(id); 290 if (b != null) 291 return b.booleanValue(); 292 else 293 return false; 294 } 295 296 297 298 private boolean wasNull; 299 300 301 /** 302 * <p>Checks whether the property which the last call to {@link 303 * #getPropertyIntValue} or {@link #getProperty} tried to access 304 * was available or not. This information might be important for 305 * callers of {@link #getPropertyIntValue} since the latter 306 * returns 0 if the property does not exist. Using {@link 307 * #wasNull} the caller can distiguish this case from a property's 308 * real value of 0.</p> 309 * 310 * @return <code>true</code> if the last call to {@link 311 * #getPropertyIntValue} or {@link #getProperty} tried to access a 312 * property that was not available, else <code>false</code>. 313 */ 314 public boolean wasNull() 315 { 316 return wasNull; 317 } 318 319 320 321 /** 322 * <p>Returns the PID string associated with a property ID. The ID 323 * is first looked up in the {@link Section}'s private 324 * dictionary. If it is not found there, the method calls {@link 325 * SectionIDMap#getPIDString}.</p> 326 * 327 * @param pid The property ID 328 * 329 * @return The property ID's string value 330 */ 331 public String getPIDString(final int pid) 332 { 333 String s = null; 334 if (dictionary != null) 335 s = (String) dictionary.get(new Integer(pid)); 336 if (s == null) 337 s = SectionIDMap.getPIDString(getFormatID().getBytes(), pid); 338 if (s == null) 339 s = SectionIDMap.UNDEFINED; 340 return s; 341 } 342 343 } 344