1 /
55
56 package org.apache.poi.poifs.property;
57
58 import java.io.*;
59
60 import java.util.*;
61
62 import org.apache.poi.poifs.common.POIFSConstants;
63 import org.apache.poi.poifs.dev.POIFSViewable;
64 import org.apache.poi.util.ByteField;
65 import org.apache.poi.util.IntegerField;
66 import org.apache.poi.util.LittleEndianConsts;
67 import org.apache.poi.util.ShortField;
68
69
75
76 public abstract class Property
77 implements Child, POIFSViewable
78 {
79 static final private byte _default_fill = ( byte ) 0x00;
80 static final private int _name_size_offset = 0x40;
81 static final private int _max_name_length =
82 (_name_size_offset / LittleEndianConsts.SHORT_SIZE) - 1;
83 static final protected int _NO_INDEX = -1;
84
85
86 static final private int _node_color_offset = 0x43;
87 static final private int _previous_property_offset = 0x44;
88 static final private int _next_property_offset = 0x48;
89 static final private int _child_property_offset = 0x4C;
90 static final private int _seconds_1_offset = 0x64;
91 static final private int _days_1_offset = 0x68;
92 static final private int _seconds_2_offset = 0x6C;
93 static final private int _days_2_offset = 0x70;
94 static final private int _start_block_offset = 0x74;
95 static final private int _size_offset = 0x78;
96
97
98 static final protected byte _NODE_BLACK = 1;
99 static final protected byte _NODE_RED = 0;
100
101
102 static final private int _big_block_minimum_bytes = 4096;
103 private String _name;
104 private ShortField _name_size;
105 private ByteField _property_type;
106 private ByteField _node_color;
107 private IntegerField _previous_property;
108 private IntegerField _next_property;
109 private IntegerField _child_property;
110 private IntegerField _seconds_1;
111 private IntegerField _days_1;
112 private IntegerField _seconds_2;
113 private IntegerField _days_2;
114 private IntegerField _start_block;
115 private IntegerField _size;
116 private byte[] _raw_data;
117 private int _index;
118 private Child _next_child;
119 private Child _previous_child;
120
121
124
125 protected Property()
126 {
127 _raw_data = new byte[ POIFSConstants.PROPERTY_SIZE ];
128 Arrays.fill(_raw_data, _default_fill);
129 _name_size = new ShortField(_name_size_offset);
130 _property_type =
131 new ByteField(PropertyConstants.PROPERTY_TYPE_OFFSET);
132 _node_color = new ByteField(_node_color_offset);
133 _previous_property = new IntegerField(_previous_property_offset,
134 _NO_INDEX, _raw_data);
135 _next_property = new IntegerField(_next_property_offset,
136 _NO_INDEX, _raw_data);
137 _child_property = new IntegerField(_child_property_offset,
138 _NO_INDEX, _raw_data);
139 _seconds_1 = new IntegerField(_seconds_1_offset, 0,
140 _raw_data);
141 _days_1 = new IntegerField(_days_1_offset, 0, _raw_data);
142 _seconds_2 = new IntegerField(_seconds_2_offset, 0,
143 _raw_data);
144 _days_2 = new IntegerField(_days_2_offset, 0, _raw_data);
145 _start_block = new IntegerField(_start_block_offset);
146 _size = new IntegerField(_size_offset, 0, _raw_data);
147 _index = _NO_INDEX;
148 setName("");
149 setNextChild(null);
150 setPreviousChild(null);
151 }
152
153
160
161 protected Property(final int index, final byte [] array, final int offset)
162 {
163 _raw_data = new byte[ POIFSConstants.PROPERTY_SIZE ];
164 System.arraycopy(array, offset, _raw_data, 0,
165 POIFSConstants.PROPERTY_SIZE);
166 _name_size = new ShortField(_name_size_offset, _raw_data);
167 _property_type =
168 new ByteField(PropertyConstants.PROPERTY_TYPE_OFFSET, _raw_data);
169 _node_color = new ByteField(_node_color_offset, _raw_data);
170 _previous_property = new IntegerField(_previous_property_offset,
171 _raw_data);
172 _next_property = new IntegerField(_next_property_offset,
173 _raw_data);
174 _child_property = new IntegerField(_child_property_offset,
175 _raw_data);
176 _seconds_1 = new IntegerField(_seconds_1_offset, _raw_data);
177 _days_1 = new IntegerField(_days_1_offset, _raw_data);
178 _seconds_2 = new IntegerField(_seconds_2_offset, _raw_data);
179 _days_2 = new IntegerField(_days_2_offset, _raw_data);
180 _start_block = new IntegerField(_start_block_offset, _raw_data);
181 _size = new IntegerField(_size_offset, _raw_data);
182 _index = index;
183 int name_length = (_name_size.get() / LittleEndianConsts.SHORT_SIZE)
184 - 1;
185
186 if (name_length < 1)
187 {
188 _name = "";
189 }
190 else
191 {
192 char[] char_array = new char[ name_length ];
193 int name_offset = 0;
194
195 for (int j = 0; j < name_length; j++)
196 {
197 char_array[ j ] = ( char ) new ShortField(name_offset,
198 _raw_data).get();
199 name_offset += LittleEndianConsts.SHORT_SIZE;
200 }
201 _name = new String(char_array, 0, name_length);
202 }
203 _next_child = null;
204 _previous_child = null;
205 }
206
207
216
217 public void writeData(final OutputStream stream)
218 throws IOException
219 {
220 stream.write(_raw_data);
221 }
222
223
229
230 public void setStartBlock(final int startBlock)
231 {
232 _start_block.set(startBlock, _raw_data);
233 }
234
235
238
239 public int getStartBlock()
240 {
241 return _start_block.get();
242 }
243
244
249
250 public int getSize()
251 {
252 return _size.get();
253 }
254
255
261
262 public boolean shouldUseSmallBlocks()
263 {
264 return Property.isSmall(_size.get());
265 }
266
267
275
276 public static boolean isSmall(final int length)
277 {
278 return length < _big_block_minimum_bytes;
279 }
280
281
286
287 public String getName()
288 {
289 return _name;
290 }
291
292
295
296 abstract public boolean isDirectory();
297
298
303
304 protected final void setName(final String name)
305 {
306 char[] char_array = name.toCharArray();
307 int limit = Math.min(char_array.length, _max_name_length);
308
309 _name = new String(char_array, 0, limit);
310 short offset = 0;
311 int j = 0;
312
313 for (; j < limit; j++)
314 {
315 new ShortField(offset, ( short ) char_array[ j ], _raw_data);
316 offset += LittleEndianConsts.SHORT_SIZE;
317 }
318 for (; j < _max_name_length + 1; j++)
319 {
320 new ShortField(offset, ( short ) 0, _raw_data);
321 offset += LittleEndianConsts.SHORT_SIZE;
322 }
323
324
325 _name_size
326 .set(( short ) ((limit + 1)
327 * LittleEndianConsts.SHORT_SIZE), _raw_data);
328 }
329
330 /**
331 * Set the property type. Makes no attempt to validate the value.
332 *
333 * @param propertyType the property type (root, file, directory)
334 */
335
336 protected void setPropertyType(final byte propertyType)
337 {
338 _property_type.set(propertyType, _raw_data);
339 }
340
341 /**
342 * Set the node color.
343 *
344 * @param nodeColor the node color (red or black)
345 */
346
347 protected void setNodeColor(final byte nodeColor)
348 {
349 _node_color.set(nodeColor, _raw_data);
350 }
351
352 /**
353 * Set the child property.
354 *
355 * @param child the child property's index in the Property Table
356 */
357
358 protected void setChildProperty(final int child)
359 {
360 _child_property.set(child, _raw_data);
361 }
362
363 /**
364 * Get the child property (its index in the Property Table)
365 *
366 * @return child property index
367 */
368
369 protected int getChildIndex()
370 {
371 return _child_property.get();
372 }
373
374 /**
375 * Set the size of the document associated with this Property
376 *
377 * @param size the size of the document, in bytes
378 */
379
380 protected void setSize(final int size)
381 {
382 _size.set(size, _raw_data);
383 }
384
385 /**
386 * Set the index for this Property
387 *
388 * @param index this Property's index within its containing
389 * Property Table
390 */
391
392 protected void setIndex(final int index)
393 {
394 _index = index;
395 }
396
397 /**
398 * get the index for this Property
399 *
400 * @return the index of this Property within its Property Table
401 */
402
403 protected int getIndex()
404 {
405 return _index;
406 }
407
408 /**
409 * Perform whatever activities need to be performed prior to
410 * writing
411 */
412
413 abstract protected void preWrite();
414
415 /**
416 * get the next sibling
417 *
418 * @return index of next sibling
419 */
420
421 int getNextChildIndex()
422 {
423 return _next_property.get();
424 }
425
426 /**
427 * get the previous sibling
428 *
429 * @return index of previous sibling
430 */
431
432 int getPreviousChildIndex()
433 {
434 return _previous_property.get();
435 }
436
437 /**
438 * determine whether the specified index is valid
439 *
440 * @param index value to be checked
441 *
442 * @return true if the index is valid
443 */
444
445 static boolean isValidIndex(int index)
446 {
447 return index != _NO_INDEX;
448 }
449
450 /* ********** START implementation of Child ********** */
451
452 /**
453 * Get the next Child, if any
454 *
455 * @return the next Child; may return null
456 */
457
458 public Child getNextChild()
459 {
460 return _next_child;
461 }
462
463 /**
464 * Get the previous Child, if any
465 *
466 * @return the previous Child; may return null
467 */
468
469 public Child getPreviousChild()
470 {
471 return _previous_child;
472 }
473
474 /**
475 * Set the next Child
476 *
477 * @param child the new 'next' child; may be null, which has the
478 * effect of saying there is no 'next' child
479 */
480
481 public void setNextChild(final Child child)
482 {
483 _next_child = child;
484 _next_property.set((child == null) ? _NO_INDEX
485 : (( Property ) child)
486 .getIndex(), _raw_data);
487 }
488
489 /**
490 * Set the previous Child
491 *
492 * @param child the new 'previous' child; may be null, which has
493 * the effect of saying there is no 'previous' child
494 */
495
496 public void setPreviousChild(final Child child)
497 {
498 _previous_child = child;
499 _previous_property.set((child == null) ? _NO_INDEX
500 : (( Property ) child)
501 .getIndex(), _raw_data);
502 }
503
504 /* ********** END implementation of Child ********** */
505 /* ********** START begin implementation of POIFSViewable ********** */
506
507 /**
508 * Get an array of objects, some of which may implement
509 * POIFSViewable
510 *
511 * @return an array of Object; may not be null, but may be empty
512 */
513
514 public Object [] getViewableArray()
515 {
516 Object[] results = new Object[ 5 ];
517
518 results[ 0 ] = "Name = \"" + getName() + "\"";
519 results[ 1 ] = "Property Type = " + _property_type.get();
520 results[ 2 ] = "Node Color = " + _node_color.get();
521 long time = _days_1.get();
522
523 time <<= 32;
524 time += (( long ) _seconds_1.get()) & 0x0000FFFFL;
525 results[ 3 ] = "Time 1 = " + time;
526 time = _days_2.get();
527 time <<= 32;
528 time += (( long ) _seconds_2.get()) & 0x0000FFFFL;
529 results[ 4 ] = "Time 2 = " + time;
530 return results;
531 }
532
533 /**
534 * Get an Iterator of objects, some of which may implement
535 * POIFSViewable
536 *
537 * @return an Iterator; may not be null, but may have an empty
538 * back end store
539 */
540
541 public Iterator getViewableIterator()
542 {
543 return Collections.EMPTY_LIST.iterator();
544 }
545
546 /**
547 * Give viewers a hint as to whether to call getViewableArray or
548 * getViewableIterator
549 *
550 * @return true if a viewer should call getViewableArray, false if
551 * a viewer should call getViewableIterator
552 */
553
554 public boolean preferArray()
555 {
556 return true;
557 }
558
559 /**
560 * Provides a short description of the object, to be used when a
561 * POIFSViewable object has not provided its contents.
562 *
563 * @return short description
564 */
565
566 public String getShortDescription()
567 {
568 StringBuffer buffer = new StringBuffer();
569
570 buffer.append("Property: \"").append(getName()).append("\"");
571 return buffer.toString();
572 }
573
574 /* ********** END begin implementation of POIFSViewable ********** */
575 } // end public abstract class Property
576
577 ??????????????set??????????????????????????????limit???????????????????????????????????????????????????????????????_raw_data?????????????????????????setPropertyType?????????_property_type????????????????????????set????????????????????????????propertyType??????????????????????????????????????????_raw_data?????????????????????????setNodeColor?????????_node_color?????????????????????set?????????????????????????nodeColor????????????????????????????????????_raw_data?????????????????????????setChildProperty?????????_child_property?????????????????????????set?????????????????????????????child????????????????????????????????????_raw_data????????????????????????getChildIndex????????????????_child_property????????????????????????????????get?????????????????????????setSize?????????_size???????????????set???????????????????size?????????????????????????_raw_data?????????????????????????setIndex?????????_index??????????????????index????????????????????????getIndex????????????????_index??????????????????????????????????preWrite??????????????getNextChildIndex????????????????_next_property???????????????????????????????get??????????????getPreviousChildIndex????????????????_previous_property???????????????????????????????????get?????????????????????????isValidIndex????????????????index?????????????????????????_NO_INDEX??????????????????????Child??????????????????getNextChild????????????????_next_child?????????????????Child??????????????????getPreviousChild????????????????_previous_child??????????????????????setNextChild????????????????????????????????????Child?????????_next_child???????????????????????child?????????_next_property????????????????????????set?????????????????????????????child??????????????????????????????????????????????_NO_INDEX?????????????????????????????????????????????????Property????????????????????????????????????????????????????????????child?????????????????????????????????????????????????????????????_raw_data??????????????????????setPreviousChild????????????????????????????????????????Child?????????_previous_child???????????????????????????child?????????_previous_property????????????????????????????set?????????????????????????????????child??????????????????????????????????????????????????_NO_INDEX?????????????????????????????????????????????????????Property????????????????????????????????????????????????????????????????child?????????????????????????????????????????????????????????????????_raw_data?????????????????????????????????????getViewableArray?????????results???????????????????????????????????????????????getName?????????results?????????????????????????????????????????????_property_type????????????????????????????????????????????????????????????get?????????results?????????????????????????????????????????????_node_color?????????????????????????????????????????????????????????get?????????????????????_days_1?????????????????????????????get?????????time?????????time???????????????????????????????????_seconds_1??????????????????????????????????????????????get?????????results?????????????????????????????????????????????time?????????time????????????????????????_days_2????????????????????????????????get?????????time?????????time???????????????????????????????????_seconds_2??????????????????????????????????????????????get?????????results?????????????????????????????????????????????time????????????????results??????????????????????????getViewableIterator?????????????????????????preferArray????????????????????????getShortDescription?????????buffer??????????????????????????????????????????????getName????????????????buffer??????????