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