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> 63 * 64 * Represents a section in a {@link PropertySet}.</p> 65 * 66 *@author Rainer Klute (klute@rainer-klute.de) 67 *@author Drew Varner (Drew.Varner allUpIn sc.edu) 68 *@created May 10, 2002 69 *@version $Id: Section.java,v 1.6 2002/05/19 18:09:26 acoliver Exp $ 70 *@since 2002-02-09 71 */ 72 public class Section { 73 74 /** 75 * <p> 76 * 77 * Maps property IDs to section-private PID strings. These strings can be 78 * found in the property with ID 0.</p> 79 */ 80 protected Map dictionary; 81 82 private ClassID formatID; 83 84 85 /** 86 * <p> 87 * 88 * Returns the format ID. The format ID is the "type" of the section.</p> 89 * 90 *@return The formatID value 91 */ 92 public ClassID getFormatID() { 93 return formatID; 94 } 95 96 97 98 private long offset; 99 100 101 /** 102 * <p> 103 * 104 * Returns the offset of the section in the stream.</p> 105 * 106 *@return The offset value 107 */ 108 public long getOffset() { 109 return offset; 110 } 111 112 113 114 private int size; 115 116 117 /** 118 * <p> 119 * 120 * Returns the section's size in bytes.</p> 121 * 122 *@return The size value 123 */ 124 public int getSize() { 125 return size; 126 } 127 128 129 130 private int propertyCount; 131 132 133 /** 134 * <p> 135 * 136 * Returns the number of properties in this section.</p> 137 * 138 *@return The propertyCount value 139 */ 140 public int getPropertyCount() { 141 return propertyCount; 142 } 143 144 145 146 private Property[] properties; 147 148 149 /** 150 * <p> 151 * 152 * Returns this section's properties.</p> 153 * 154 *@return The properties value 155 */ 156 public Property[] getProperties() { 157 return properties; 158 } 159 160 161 162 /** 163 * <p> 164 * 165 * Creates a {@link Section} instance from a byte array.</p> 166 * 167 *@param src Contains the complete property set stream. 168 *@param offset The position in the stream that points to the section's 169 * format ID. 170 */ 171 public Section(final byte[] src, int offset) { 172 /* 173 * Read the format ID. 174 */ 175 formatID = new ClassID(src, offset); 176 offset += ClassID.LENGTH; 177 178 /* 179 * Read the offset from the stream's start and positions to 180 * the section header. 181 */ 182 this.offset = LittleEndian.getUInt(src, offset); 183 offset = (int)this.offset; 184 185 /* 186 * Read the section length. 187 */ 188 size = (int)LittleEndian.getUInt(src, offset); 189 offset += LittleEndian.INT_SIZE; 190 191 /* 192 * Read the number of properties. 193 */ 194 propertyCount = (int)LittleEndian.getUInt(src, offset); 195 offset += LittleEndian.INT_SIZE; 196 197 /* 198 * Read the properties. The offset is positioned at the first 199 * entry of the property list. 200 */ 201 properties = new Property[propertyCount]; 202 for (int i = 0; i < properties.length; i++) { 203 final int id = (int)LittleEndian.getUInt(src, offset); 204 offset += LittleEndian.INT_SIZE; 205 206 /* 207 * Offset from the section. 208 */ 209 final int sOffset = (int)LittleEndian.getUInt(src, offset); 210 offset += LittleEndian.INT_SIZE; 211 212 /* 213 * Calculate the length of the property. 214 */ 215 int length; 216 if (i == properties.length - 1) { 217 length = (int)(src.length - this.offset - sOffset); 218 } else { 219 length = (int) 220 LittleEndian.getUInt(src, offset + LittleEndian.INT_SIZE) - sOffset; 221 } 222 223 /* 224 * Create it. 225 */ 226 properties[i] = 227 new Property(id, src, this.offset + sOffset, length); 228 } 229 230 /* 231 * Extract the dictionary (if available). 232 */ 233 dictionary = (Map) getProperty(0); 234 } 235 236 237 238 /** 239 * <p> 240 * 241 * Returns the value of the property with the specified ID. If the property 242 * is not available, <code>null</code> is returned and a subsequent call to 243 * {@link #wasNull} will return <code>true</code>.</p> 244 * 245 *@param id Description of the Parameter 246 *@return The property value 247 */ 248 protected Object getProperty(final int id) { 249 wasNull = false; 250 for (int i = 0; i < properties.length; i++) { 251 if (id == properties[i].getID()) { 252 return properties[i].getValue(); 253 } 254 } 255 wasNull = true; 256 return null; 257 } 258 259 260 261 /** 262 * <p> 263 * 264 * Returns the value of the numeric property with the specified ID. If the 265 * property is not available, 0 is returned. A subsequent call to {@link 266 * #wasNull} will return <code>true</code> to let the caller distinguish 267 * that case from a real property value of 0.</p> 268 * 269 *@param id Description of the Parameter 270 *@return The propertyIntValue value 271 */ 272 protected int getPropertyIntValue(final int id) { 273 final Integer i = (Integer) getProperty(id); 274 if (i != null) { 275 return i.intValue(); 276 } else { 277 return 0; 278 } 279 } 280 281 282 283 /** 284 * <p> 285 * 286 * Returns the value of the boolean property with the specified ID. If the 287 * property is not available, <code>false</code> is returned. A subsequent 288 * call to {@link #wasNull} will return <code>true</code> to let the caller 289 * distinguish that case from a real property value of <code>false</code>. 290 * </p> 291 * 292 *@param id Description of the Parameter 293 *@return The propertyBooleanValue value 294 */ 295 protected boolean getPropertyBooleanValue(final int id) { 296 final Boolean b = (Boolean) getProperty(id); 297 if (b != null) { 298 return b.booleanValue(); 299 } else { 300 return false; 301 } 302 } 303 304 305 306 private boolean wasNull; 307 308 309 /** 310 * <p> 311 * 312 * Checks whether the property which the last call to {@link 313 * #getPropertyIntValue} or {@link #getProperty} tried to access was 314 * available or not. This information might be important for callers of 315 * {@link #getPropertyIntValue} since the latter returns 0 if the property 316 * does not exist. Using {@link #wasNull} the caller can distiguish this 317 * case from a property's real value of 0.</p> 318 * 319 *@return <code>true</code> if the last call to {@link 320 * #getPropertyIntValue} or {@link #getProperty} tried to access a 321 * property that was not available, else <code>false</code>. 322 */ 323 public boolean wasNull() { 324 return wasNull; 325 } 326 327 328 329 /** 330 * <p> 331 * 332 * Returns the PID string associated with a property ID. The ID is first 333 * looked up in the {@link Section}'s private dictionary. If it is not 334 * found there, the method calls {@link SectionIDMap#getPIDString}.</p> 335 * 336 *@param pid Description of the Parameter 337 *@return The pIDString value 338 */ 339 public String getPIDString(final int pid) { 340 String s = null; 341 if (dictionary != null) { 342 s = (String) dictionary.get(new Integer(pid)); 343 } 344 if (s == null) { 345 s = SectionIDMap.getPIDString(getFormatID().getBytes(), pid); 346 } 347 if (s == null) { 348 s = SectionIDMap.UNDEFINED; 349 } 350 return s; 351 } 352 353 } 354