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   
55   package org.apache.poi.hpsf;
56   
57   import java.util.*;
58   import org.apache.poi.hpsf.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    *
67    * @version $Id: Section.java,v 1.4 2002/05/03 07:29:09 klute Exp $
68    * @since 2002-02-09
69    */
70   public class Section
71   {
72   
73       /**
74        * <p>Maps property IDs to section-private PID strings. These
75        * strings can be found in the property with ID 0.</p>
76        */
77       protected Map dictionary;
78   
79   
80   
81       private ClassID formatID;
82   
83       /**
84        * <p>Returns the format ID. The format ID is the "type" of the
85        * section.</p>
86        */
87       public ClassID getFormatID()
88       {
89           return formatID;
90       }
91   
92   
93   
94       private int offset;
95   
96       /**
97        * <p>Returns the offset of the section in the stream.</p>
98        */
99       public int getOffset()
100      {
101          return offset;
102      }
103  
104  
105  
106      private int size;
107  
108      /**
109       * <p>Returns the section's size in bytes.</p>
110       */
111      public int getSize()
112      {
113          return size;
114      }
115  
116  
117  
118      private int propertyCount;
119  
120      /**
121       * <p>Returns the number of properties in this section.</p>
122       */
123      public int getPropertyCount()
124      {
125          return propertyCount;
126      }
127  
128  
129  
130      private Property[] properties;
131  
132      /**
133       * <p>Returns this section's properties.</p>
134       */
135      public Property[] getProperties()
136      {
137          return properties;
138      }
139  
140  
141  
142      /**
143       * <p>Creates a {@link Section} instance from a byte array.</p>
144       *
145       * @param src Contains the complete property set stream.
146       *
147       * @param offset The position in the stream that points to the
148       * section's format ID.
149       */
150      public Section(final byte[] src, int offset)
151      {
152          /* Read the format ID. */
153          formatID = new ClassID(src, offset);
154          offset += ClassID.LENGTH;
155  
156          /* Read the offset from the stream's start and positions to
157           * the section header. */
158          this.offset = new DWord(src, offset).intValue();
159          offset = this.offset;
160  
161          /* Read the section length. */
162          size = new DWord(src, offset).intValue();
163          offset += DWord.LENGTH;
164  
165          /* Read the number of properties. */
166          propertyCount = new DWord(src, offset).intValue();
167          offset += DWord.LENGTH;
168  
169          /* Read the properties. The offset is positioned at the first
170           * entry of the property list. */
171          properties = new Property[propertyCount];
172          for (int i = 0; i < properties.length; i++)
173          {
174              final int id = new DWord(src, offset).intValue();
175              offset += DWord.LENGTH;
176  
177              /* Offset from the section. */
178              final int sOffset = new DWord(src, offset).intValue();
179              offset += DWord.LENGTH;
180  
181              /* Calculate the length of the property. */
182              int length;
183              if (i == properties.length - 1)
184                  length = src.length - this.offset - sOffset;
185              else
186                  length =
187                      new DWord(src, offset + DWord.LENGTH).intValue() - sOffset;
188  
189              /* Create it. */
190              properties[i] =
191                  new Property(id, src, this.offset + sOffset, length);
192          }
193  
194          /* Extract the dictionary (if available). */
195          dictionary = (Map) getProperty(0);
196      }
197  
198  
199  
200      /**
201       * <p>Returns the value of the property with the specified ID. If
202       * the property is not available, <code>null</code> is returned
203       * and a subsequent call to {@link #wasNull} will return
204       * <code>true</code>.</p>
205       */
206      protected Object getProperty(final int id)
207      {
208          wasNull = false;
209          for (int i = 0; i < properties.length; i++)
210              if (id == properties[i].getID())
211                  return properties[i].getValue();
212          wasNull = true;
213          return null;
214      }
215  
216  
217  
218      /**
219       * <p>Returns the value of the numeric property with the specified
220       * ID. If the property is not available, 0 is returned. A
221       * subsequent call to {@link #wasNull} will return
222       * <code>true</code> to let the caller distinguish that case from
223       * a real property value of 0.</p>
224       */
225      protected int getPropertyIntValue(final int id)
226      {
227          final Integer i = (Integer) getProperty(id);
228          if (i != null)
229              return i.intValue();
230          else
231              return 0;
232      }
233  
234  
235  
236      /**
237       * <p>Returns the value of the boolean property with the specified
238       * ID. If the property is not available, <code>false</code> is
239       * returned. A subsequent call to {@link #wasNull} will return
240       * <code>true</code> to let the caller distinguish that case from
241       * a real property value of <code>false</code>.</p>
242       */
243      protected boolean getPropertyBooleanValue(final int id)
244      {
245          final Boolean b = (Boolean) getProperty(id);
246          if (b != null)
247              return b.booleanValue();
248          else
249              return false;
250      }
251  
252  
253  
254      private boolean wasNull;
255  
256      /**
257       * <p>Checks whether the property which the last call to {@link
258       * #getPropertyIntValue} or {@link #getProperty} tried to access
259       * was available or not. This information might be important for
260       * callers of {@link #getPropertyIntValue} since the latter
261       * returns 0 if the property does not exist. Using {@link
262       * #wasNull} the caller can distiguish this case from a property's
263       * real value of 0.</p>
264       *
265       * @return <code>true</code> if the last call to {@link
266       * #getPropertyIntValue} or {@link #getProperty} tried to access a
267       * property that was not available, else <code>false</code>.
268       */
269      public boolean wasNull()
270      {
271          return wasNull;
272      }
273  
274  
275  
276      /**
277       * <p>Returns the PID string associated with a property ID. The ID
278       * is first looked up in the {@link Section}'s private
279       * dictionary. If it is not found there, the method calls {@link
280       * SectionIDMap#getPIDString}.</p>
281       */
282      public String getPIDString(final int pid)
283      {
284          String s = null;
285          if (dictionary != null)
286              s = (String) dictionary.get(new Integer(pid));
287          if (s == null)
288              s =  SectionIDMap.getPIDString(getFormatID().getBytes(), pid);
289          if (s == null)
290              s = SectionIDMap.UNDEFINED;
291          return s;
292      }
293  
294  }
295