KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > poi > poifs > property > Property


1
2 /* ====================================================================
3    Copyright 2002-2004 Apache Software Foundation
4
5    Licensed under the Apache License, Version 2.0 (the "License");
6    you may not use this file except in compliance with the License.
7    You may obtain a copy of the License at
8
9        http://www.apache.org/licenses/LICENSE-2.0
10
11    Unless required by applicable law or agreed to in writing, software
12    distributed under the License is distributed on an "AS IS" BASIS,
13    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14    See the License for the specific language governing permissions and
15    limitations under the License.
16 ==================================================================== */

17         
18
19 package org.apache.poi.poifs.property;
20
21 import java.io.*;
22
23 import java.util.*;
24
25 import org.apache.poi.hpsf.ClassID;
26
27 import org.apache.poi.poifs.common.POIFSConstants;
28 import org.apache.poi.poifs.dev.POIFSViewable;
29 import org.apache.poi.util.ByteField;
30 import org.apache.poi.util.IntegerField;
31 import org.apache.poi.util.LittleEndianConsts;
32 import org.apache.poi.util.ShortField;
33
34 /**
35  * This abstract base class is the ancestor of all classes
36  * implementing POIFS Property behavior.
37  *
38  * @author Marc Johnson (mjohnson at apache dot org)
39  */

40
41 public abstract class Property
42     implements Child, POIFSViewable
43 {
44     static final private byte _default_fill = ( byte ) 0x00;
45     static final private int _name_size_offset = 0x40;
46     static final private int _max_name_length =
47         (_name_size_offset / LittleEndianConsts.SHORT_SIZE) - 1;
48     static final protected int _NO_INDEX = -1;
49
50     // useful offsets
51
static final private int _node_color_offset = 0x43;
52     static final private int _previous_property_offset = 0x44;
53     static final private int _next_property_offset = 0x48;
54     static final private int _child_property_offset = 0x4C;
55     static final private int _storage_clsid_offset = 0x50;
56     static final private int _user_flags_offset = 0x60;
57     static final private int _seconds_1_offset = 0x64;
58     static final private int _days_1_offset = 0x68;
59     static final private int _seconds_2_offset = 0x6C;
60     static final private int _days_2_offset = 0x70;
61     static final private int _start_block_offset = 0x74;
62     static final private int _size_offset = 0x78;
63
64     // node colors
65
static final protected byte _NODE_BLACK = 1;
66     static final protected byte _NODE_RED = 0;
67
68     // documents must be at least this size to be stored in big blocks
69
static final private int _big_block_minimum_bytes = 4096;
70     private String JavaDoc _name;
71     private ShortField _name_size;
72     private ByteField _property_type;
73     private ByteField _node_color;
74     private IntegerField _previous_property;
75     private IntegerField _next_property;
76     private IntegerField _child_property;
77     private ClassID _storage_clsid;
78     private IntegerField _user_flags;
79     private IntegerField _seconds_1;
80     private IntegerField _days_1;
81     private IntegerField _seconds_2;
82     private IntegerField _days_2;
83     private IntegerField _start_block;
84     private IntegerField _size;
85     private byte[] _raw_data;
86     private int _index;
87     private Child _next_child;
88     private Child _previous_child;
89
90     /**
91      * Default constructor
92      */

93
94     protected Property()
95     {
96         _raw_data = new byte[ POIFSConstants.PROPERTY_SIZE ];
97         Arrays.fill(_raw_data, _default_fill);
98         _name_size = new ShortField(_name_size_offset);
99         _property_type =
100             new ByteField(PropertyConstants.PROPERTY_TYPE_OFFSET);
101         _node_color = new ByteField(_node_color_offset);
102         _previous_property = new IntegerField(_previous_property_offset,
103                                               _NO_INDEX, _raw_data);
104         _next_property = new IntegerField(_next_property_offset,
105                                               _NO_INDEX, _raw_data);
106         _child_property = new IntegerField(_child_property_offset,
107                                               _NO_INDEX, _raw_data);
108         _storage_clsid = new ClassID(_raw_data,_storage_clsid_offset);
109         _user_flags = new IntegerField(_user_flags_offset, 0, _raw_data);
110         _seconds_1 = new IntegerField(_seconds_1_offset, 0,
111                                               _raw_data);
112         _days_1 = new IntegerField(_days_1_offset, 0, _raw_data);
113         _seconds_2 = new IntegerField(_seconds_2_offset, 0,
114                                               _raw_data);
115         _days_2 = new IntegerField(_days_2_offset, 0, _raw_data);
116         _start_block = new IntegerField(_start_block_offset);
117         _size = new IntegerField(_size_offset, 0, _raw_data);
118         _index = _NO_INDEX;
119         setName("");
120         setNextChild(null);
121         setPreviousChild(null);
122     }
123
124     /**
125      * Constructor from byte data
126      *
127      * @param index index number
128      * @param array byte data
129      * @param offset offset into byte data
130      */

131
132     protected Property(final int index, final byte [] array, final int offset)
133     {
134         _raw_data = new byte[ POIFSConstants.PROPERTY_SIZE ];
135         System.arraycopy(array, offset, _raw_data, 0,
136                          POIFSConstants.PROPERTY_SIZE);
137         _name_size = new ShortField(_name_size_offset, _raw_data);
138         _property_type =
139             new ByteField(PropertyConstants.PROPERTY_TYPE_OFFSET, _raw_data);
140         _node_color = new ByteField(_node_color_offset, _raw_data);
141         _previous_property = new IntegerField(_previous_property_offset,
142                                               _raw_data);
143         _next_property = new IntegerField(_next_property_offset,
144                                               _raw_data);
145         _child_property = new IntegerField(_child_property_offset,
146                                               _raw_data);
147         _storage_clsid = new ClassID(_raw_data,_storage_clsid_offset);
148         _user_flags = new IntegerField(_user_flags_offset, 0, _raw_data);
149         _seconds_1 = new IntegerField(_seconds_1_offset, _raw_data);
150         _days_1 = new IntegerField(_days_1_offset, _raw_data);
151         _seconds_2 = new IntegerField(_seconds_2_offset, _raw_data);
152         _days_2 = new IntegerField(_days_2_offset, _raw_data);
153         _start_block = new IntegerField(_start_block_offset, _raw_data);
154         _size = new IntegerField(_size_offset, _raw_data);
155         _index = index;
156         int name_length = (_name_size.get() / LittleEndianConsts.SHORT_SIZE)
157                           - 1;
158
159         if (name_length < 1)
160         {
161             _name = "";
162         }
163         else
164         {
165             char[] char_array = new char[ name_length ];
166             int name_offset = 0;
167
168             for (int j = 0; j < name_length; j++)
169             {
170                 char_array[ j ] = ( char ) new ShortField(name_offset,
171                                                           _raw_data).get();
172                 name_offset += LittleEndianConsts.SHORT_SIZE;
173             }
174             _name = new String JavaDoc(char_array, 0, name_length);
175         }
176         _next_child = null;
177         _previous_child = null;
178     }
179
180     /**
181      * Write the raw data to an OutputStream.
182      *
183      * @param stream the OutputStream to which the data should be
184      * written.
185      *
186      * @exception IOException on problems writing to the specified
187      * stream.
188      */

189
190     public void writeData(final OutputStream stream)
191         throws IOException
192     {
193         stream.write(_raw_data);
194     }
195
196     /**
197      * Set the start block for the document referred to by this
198      * Property.
199      *
200      * @param startBlock the start block index
201      */

202
203     public void setStartBlock(final int startBlock)
204     {
205         _start_block.set(startBlock, _raw_data);
206     }
207
208     /**
209      * @return the start block
210      */

211
212     public int getStartBlock()
213     {
214         return _start_block.get();
215     }
216
217     /**
218      * find out the document size
219      *
220      * @return size in bytes
221      */

222
223     public int getSize()
224     {
225         return _size.get();
226     }
227
228     /**
229      * Based on the currently defined size, should this property use
230      * small blocks?
231      *
232      * @return true if the size is less than _big_block_minimum_bytes
233      */

234
235     public boolean shouldUseSmallBlocks()
236     {
237         return Property.isSmall(_size.get());
238     }
239
240     /**
241      * does the length indicate a small document?
242      *
243      * @param length length in bytes
244      *
245      * @return true if the length is less than
246      * _big_block_minimum_bytes
247      */

248
249     public static boolean isSmall(final int length)
250     {
251         return length < _big_block_minimum_bytes;
252     }
253
254     /**
255      * Get the name of this property
256      *
257      * @return property name as String
258      */

259
260     public String JavaDoc getName()
261     {
262         return _name;
263     }
264
265     /**
266      * @return true if a directory type Property
267      */

268
269     abstract public boolean isDirectory();
270
271     /**
272      * Sets the storage clsid, which is the Class ID of a COM object which
273      * reads and writes this stream
274      * @return storage Class ID for this property stream
275      */

276     public ClassID getStorageClsid()
277     {
278         return _storage_clsid;
279     }
280
281     /**
282      * Set the name; silently truncates the name if it's too long.
283      *
284      * @param name the new name
285      */

286     protected final void setName(final String JavaDoc name)
287     {
288         char[] char_array = name.toCharArray();
289         int limit = Math.min(char_array.length, _max_name_length);
290
291         _name = new String JavaDoc(char_array, 0, limit);
292         short offset = 0;
293         int j = 0;
294
295         for (; j < limit; j++)
296         {
297             new ShortField(offset, ( short ) char_array[ j ], _raw_data);
298             offset += LittleEndianConsts.SHORT_SIZE;
299         }
300         for (; j < _max_name_length + 1; j++)
301         {
302             new ShortField(offset, ( short ) 0, _raw_data);
303             offset += LittleEndianConsts.SHORT_SIZE;
304         }
305
306         // double the count, and include the null at the end
307
_name_size
308             .set(( short ) ((limit + 1)
309                             * LittleEndianConsts.SHORT_SIZE), _raw_data);
310     }
311
312     /**
313      * Sets the storage class ID for this property stream. This is the Class ID
314      * of the COM object which can read and write this property stream
315      * @param clsidStorage Storage Class ID
316      */

317     public void setStorageClsid( ClassID clsidStorage)
318     {
319         _storage_clsid = clsidStorage;
320         if( clsidStorage == null) {
321             Arrays.fill( _raw_data, _storage_clsid_offset, _storage_clsid_offset + ClassID.LENGTH, (byte) 0);
322         } else {
323             clsidStorage.write( _raw_data, _storage_clsid_offset);
324         }
325     }
326     /**
327      * Set the property type. Makes no attempt to validate the value.
328      *
329      * @param propertyType the property type (root, file, directory)
330      */

331
332     protected void setPropertyType(final byte propertyType)
333     {
334         _property_type.set(propertyType, _raw_data);
335     }
336
337     /**
338      * Set the node color.
339      *
340      * @param nodeColor the node color (red or black)
341      */

342
343     protected void setNodeColor(final byte nodeColor)
344     {
345         _node_color.set(nodeColor, _raw_data);
346     }
347
348     /**
349      * Set the child property.
350      *
351      * @param child the child property's index in the Property Table
352      */

353
354     protected void setChildProperty(final int child)
355     {
356         _child_property.set(child, _raw_data);
357     }
358
359     /**
360      * Get the child property (its index in the Property Table)
361      *
362      * @return child property index
363      */

364
365     protected int getChildIndex()
366     {
367         return _child_property.get();
368     }
369
370     /**
371      * Set the size of the document associated with this Property
372      *
373      * @param size the size of the document, in bytes
374      */

375
376     protected void setSize(final int size)
377     {
378         _size.set(size, _raw_data);
379     }
380
381     /**
382      * Set the index for this Property
383      *
384      * @param index this Property's index within its containing
385      * Property Table
386      */

387
388     protected void setIndex(final int index)
389     {
390         _index = index;
391     }
392
393     /**
394      * get the index for this Property
395      *
396      * @return the index of this Property within its Property Table
397      */

398
399     protected int getIndex()
400     {
401         return _index;
402     }
403
404     /**
405      * Perform whatever activities need to be performed prior to
406      * writing
407      */

408
409     abstract protected void preWrite();
410
411     /**
412      * get the next sibling
413      *
414      * @return index of next sibling
415      */

416
417     int getNextChildIndex()
418     {
419         return _next_property.get();
420     }
421
422     /**
423      * get the previous sibling
424      *
425      * @return index of previous sibling
426      */

427
428     int getPreviousChildIndex()
429     {
430         return _previous_property.get();
431     }
432
433     /**
434      * determine whether the specified index is valid
435      *
436      * @param index value to be checked
437      *
438      * @return true if the index is valid
439      */

440
441     static boolean isValidIndex(int index)
442     {
443         return index != _NO_INDEX;
444     }
445
446     /* ********** START implementation of Child ********** */
447
448     /**
449      * Get the next Child, if any
450      *
451      * @return the next Child; may return null
452      */

453
454     public Child getNextChild()
455     {
456         return _next_child;
457     }
458
459     /**
460      * Get the previous Child, if any
461      *
462      * @return the previous Child; may return null
463      */

464
465     public Child getPreviousChild()
466     {
467         return _previous_child;
468     }
469
470     /**
471      * Set the next Child
472      *
473      * @param child the new 'next' child; may be null, which has the
474      * effect of saying there is no 'next' child
475      */

476
477     public void setNextChild(final Child child)
478     {
479         _next_child = child;
480         _next_property.set((child == null) ? _NO_INDEX
481                                            : (( Property ) child)
482                                                .getIndex(), _raw_data);
483     }
484
485     /**
486      * Set the previous Child
487      *
488      * @param child the new 'previous' child; may be null, which has
489      * the effect of saying there is no 'previous' child
490      */

491
492     public void setPreviousChild(final Child child)
493     {
494         _previous_child = child;
495         _previous_property.set((child == null) ? _NO_INDEX
496                                                : (( Property ) child)
497                                                    .getIndex(), _raw_data);
498     }
499
500     /* ********** END implementation of Child ********** */
501     /* ********** START begin implementation of POIFSViewable ********** */
502
503     /**
504      * Get an array of objects, some of which may implement
505      * POIFSViewable
506      *
507      * @return an array of Object; may not be null, but may be empty
508      */

509
510     public Object JavaDoc [] getViewableArray()
511     {
512         Object JavaDoc[] results = new Object JavaDoc[ 5 ];
513
514         results[ 0 ] = "Name = \"" + getName() + "\"";
515         results[ 1 ] = "Property Type = " + _property_type.get();
516         results[ 2 ] = "Node Color = " + _node_color.get();
517         long time = _days_1.get();
518
519         time <<= 32;
520         time += (( long ) _seconds_1.get()) & 0x0000FFFFL;
521         results[ 3 ] = "Time 1 = " + time;
522         time = _days_2.get();
523         time <<= 32;
524         time += (( long ) _seconds_2.get()) & 0x0000FFFFL;
525         results[ 4 ] = "Time 2 = " + time;
526         return results;
527     }
528
529     /**
530      * Get an Iterator of objects, some of which may implement
531      * POIFSViewable
532      *
533      * @return an Iterator; may not be null, but may have an empty
534      * back end store
535      */

536
537     public Iterator getViewableIterator()
538     {
539         return Collections.EMPTY_LIST.iterator();
540     }
541
542     /**
543      * Give viewers a hint as to whether to call getViewableArray or
544      * getViewableIterator
545      *
546      * @return true if a viewer should call getViewableArray, false if
547      * a viewer should call getViewableIterator
548      */

549
550     public boolean preferArray()
551     {
552         return true;
553     }
554
555     /**
556      * Provides a short description of the object, to be used when a
557      * POIFSViewable object has not provided its contents.
558      *
559      * @return short description
560      */

561
562     public String JavaDoc getShortDescription()
563     {
564         StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
565
566         buffer.append("Property: \"").append(getName()).append("\"");
567         return buffer.toString();
568     }
569
570     /* ********** END begin implementation of POIFSViewable ********** */
571 } // end public abstract class Property
572

573
Popular Tags