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   
59   package org.apache.poi.hpsf;
60   
61   import java.util.*;
62   import org.apache.poi.hpsf.littleendian.*;
63   
64   /**
65    * <p>A property in a {@link Section} of a {@link PropertySet}.</p>
66    *
67    * <p>The property's <strong>ID</strong> gives the property a meaning
68    * in the context of its {@link Section}. Each {@link Section} spans
69    * its own name space of property IDs.</p>
70    *
71    * <p>The property's <strong>type</strong> determines how its
72    * <strong>value</strong> is interpreted. For example, if the type is
73    * {@link Variant#VT_LPSTR} (byte string), the value consists of a
74    * {@link DWord} telling how many bytes the string contains. The bytes
75    * follow immediately, including any null bytes that terminate the
76    * string. The type {@link Variant#VT_I4} denotes a four-byte integer
77    * value, {@link Variant#VT_FILETIME} some date and time (of a
78    * file).</p>
79    *
80    * <p><strong>FIXME:</strong> Reading of other types than those
81    * mentioned above and the dictionary property is not yet
82    * implemented.</p>
83    *
84    * @see Section
85    * @see Variant
86    *
87    * @author Rainer Klute (klute@rainer-klute.de)
88    * @version $Id: Property.java,v 1.1 2002/02/14 04:00:59 mjohnson Exp $
89    * @since 2002-02-09
90    */
91   public class Property
92   {
93   
94       private int id;
95   
96       /**
97        * <p>Returns the property's ID.</p>
98        */
99       public int getID()
100      {
101          return id;
102      }
103  
104  
105  
106      private int type;
107  
108      /**
109       * <p>Returns the property's type.</p>
110       */
111      public int getType()
112      {
113          return type;
114      }
115  
116  
117  
118      private Object value;
119  
120      /**
121       * <p>Returns the property value's.</p>
122       */
123      public Object getValue()
124      {
125          return value;
126      }
127  
128  
129  
130      /**
131       * <p>Creates a {@link Property} instance by reading its bytes
132       * from the property set stream.</p>
133       *
134       * @param id The property's ID.
135       *
136       * @param src The bytes the property set stream consists of.
137       *
138       * @param offset The property's type/value pair's offset in the
139       * section.
140       *
141       * @param length The property's type/value pair's length in bytes.
142       * list.
143       */
144      public Property(final int id, final byte[] src, final int offset,
145                      final int length)
146      {
147          this.id = id;
148  
149          /* ID 0 is a special case since it specifies a dictionary of
150           * property IDs and property names. */
151          if (id == 0)
152          {
153              value = readDictionary(src, offset, length);
154              return;
155          }
156  
157          /* FIXME: Support this! */
158  //        /* ID 1 is another special case: It denotes the code page of
159  //         * byte strings in this section. */
160  //        if (id == 1)
161  //        {
162  //            value = readCodepage(src, offset);
163  //            return;
164  //        }
165  
166          int o = offset;
167          type = new DWord(src, o).intValue();
168          o += DWord.LENGTH;
169  
170          /* FIXME: Support reading more types! */
171          switch (type)
172          {
173              case Variant.VT_I4:
174              {
175                  /* Read a word. In Java it is represented as an
176                     Integer object. */
177                  value = new Integer(new DWord(src, o).intValue());
178                  break;
179              }
180              case Variant.VT_FILETIME:
181              {
182                  /* Read a FILETIME object. In Java it is represented
183                     as a Date. */
184                  final int low = new DWord(src, o).intValue();
185                  o += DWord.LENGTH;
186                  final int high = new DWord(src, o).intValue();
187                  value = Util.filetimeToDate(high, low);
188                  break;
189              }
190              case Variant.VT_LPSTR:
191              {
192                  /* Read a byte string. In Java it is represented as a
193                     String. The null bytes at the end of the byte
194                     strings must be stripped. */
195                  final int first = o + DWord.LENGTH;
196                  int last = first + new DWord(src, o).intValue() - 1;
197                  o += DWord.LENGTH;
198                  while (src[last] == 0 && first <= last)
199                      last--;
200                  value = new String(src, first, last - first + 1);
201                  break;
202              }
203              default:
204              {
205                  final byte[] v = new byte[length];
206                  for (int i = 0; i < length; i++)
207                      v[i] = src[offset + i];
208                  value = v;
209                  break;
210              }
211          }
212      }
213  
214  
215  
216      /**
217       * <p>Reads a dictionary.</p>
218       *
219       * @param src The byte array containing the bytes making out the
220       * dictionary.
221       *
222       * @param offset At this offset within <var>src</var> the
223       * dictionary starts.
224       *
225       * @param length The dictionary contains at most this many bytes.
226       */
227      protected Map readDictionary(final byte[] src, final int offset,
228                                   final int length)
229      {
230          /* FIXME: Check the length! */
231          int o = offset;
232  
233          /* Read the number of dictionary entries. */
234          final int nrEntries = new DWord(src, o).intValue();
235          o += DWord.LENGTH;
236  
237          final Map m = new HashMap(nrEntries, (float) 1.0);
238          for (int i = 0; i < nrEntries; i++)
239          {
240              /* The key */
241              final Integer id = new Integer(new DWord(src, o).intValue());
242              o += DWord.LENGTH;
243  
244              /* The value (a string) */
245              final int sLength = new DWord(src, o).intValue();
246              o += DWord.LENGTH;
247              /* Strip trailing 0x00 bytes. */
248              int l = sLength;
249              while (src[o + l - 1] == 0x00)
250                  l--;
251              final String s = new String(src, o, l);
252              o += sLength;
253              m.put(id, s);
254          }
255          return m;
256      }
257  
258  
259  
260      /**
261       * <p>Reads a code page.</p>
262       *
263       * @param src The byte array containing the bytes making out the
264       * code page.
265       *
266       * @param offset At this offset within <var>src</var> the code
267       * page starts.
268       */
269      protected int readCodePage(final byte[] src, final int offset)
270      {
271          throw new UnsupportedOperationException("FIXME");
272      }
273  
274  }
275