1 /
55
56 package org.apache.poi.poifs.filesystem;
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.poifs.property.DocumentProperty;
65 import org.apache.poi.poifs.property.Property;
66 import org.apache.poi.poifs.storage.BlockWritable;
67 import org.apache.poi.poifs.storage.ListManagedBlock;
68 import org.apache.poi.poifs.storage.DocumentBlock;
69 import org.apache.poi.poifs.storage.RawDataBlock;
70 import org.apache.poi.poifs.storage.SmallDocumentBlock;
71 import org.apache.poi.util.HexDump;
72
73
78
79 public class POIFSDocument
80 implements BATManaged, BlockWritable, POIFSViewable
81 {
82 private DocumentProperty _property;
83 private int _size;
84
85
86 private SmallBlockStore _small_store;
87 private BigBlockStore _big_store;
88
89
98
99 public POIFSDocument(final String name, final RawDataBlock [] blocks,
100 final int length)
101 throws IOException
102 {
103 _size = length;
104 _big_store = new BigBlockStore(blocks);
105 _property = new DocumentProperty(name, _size);
106 _small_store = new SmallBlockStore(new BlockWritable[ 0 ]);
107 _property.setDocument(this);
108 }
109
110
117
118 public POIFSDocument(final String name,
119 final SmallDocumentBlock [] blocks, final int length)
120 {
121 _size = length;
122 try
123 {
124 _big_store = new BigBlockStore(new RawDataBlock[ 0 ]);
125 }
126 catch (IOException ignored)
127 {
128
129
130 }
131 _property = new DocumentProperty(name, _size);
132 _small_store = new SmallBlockStore(blocks);
133 _property.setDocument(this);
134 }
135
136
145
146 public POIFSDocument(final String name, final ListManagedBlock [] blocks,
147 final int length)
148 throws IOException
149 {
150 _size = length;
151 _property = new DocumentProperty(name, _size);
152 _property.setDocument(this);
153 if (Property.isSmall(_size))
154 {
155 _big_store = new BigBlockStore(new RawDataBlock[ 0 ]);
156 _small_store = new SmallBlockStore(blocks);
157 }
158 else
159 {
160 _big_store = new BigBlockStore(blocks);
161 _small_store = new SmallBlockStore(new BlockWritable[ 0 ]);
162 }
163 }
164
165
173
174 public POIFSDocument(final String name, final InputStream stream)
175 throws IOException
176 {
177 List blocks = new ArrayList();
178
179 _size = 0;
180 while (true)
181 {
182 DocumentBlock block = new DocumentBlock(stream);
183 int blockSize = block.size();
184
185 if (blockSize > 0)
186 {
187 blocks.add(block);
188 _size += blockSize;
189 }
190 if (block.partiallyRead())
191 {
192 break;
193 }
194 }
195 DocumentBlock[] bigBlocks =
196 ( DocumentBlock [] ) blocks.toArray(new DocumentBlock[ 0 ]);
197
198 _big_store = new BigBlockStore(bigBlocks);
199 _property = new DocumentProperty(name, _size);
200 _property.setDocument(this);
201 if (_property.shouldUseSmallBlocks())
202 {
203 _small_store =
204 new SmallBlockStore(SmallDocumentBlock.convert(bigBlocks,
205 _size));
206 _big_store = new BigBlockStore(new DocumentBlock[ 0 ]);
207 }
208 else
209 {
210 _small_store = new SmallBlockStore(new BlockWritable[ 0 ]);
211 }
212 }
213
214
225
226 public POIFSDocument(final String name, final int size,
227 final POIFSDocumentPath path,
228 final POIFSWriterListener writer)
229 throws IOException
230 {
231 _size = size;
232 _property = new DocumentProperty(name, _size);
233 _property.setDocument(this);
234 if (_property.shouldUseSmallBlocks())
235 {
236 _small_store = new SmallBlockStore(path, name, size, writer);
237 _big_store = new BigBlockStore(new Object[ 0 ]);
238 }
239 else
240 {
241 _small_store = new SmallBlockStore(new BlockWritable[ 0 ]);
242 _big_store = new BigBlockStore(path, name, size, writer);
243 }
244 }
245
246
251
252 public BlockWritable [] getSmallBlocks()
253 {
254 return _small_store.getBlocks();
255 }
256
257
260
261 public int getSize()
262 {
263 return _size;
264 }
265
266
272
273 void read(final byte [] buffer, final int offset)
274 {
275 if (_property.shouldUseSmallBlocks())
276 {
277 SmallDocumentBlock.read(_small_store.getBlocks(), buffer, offset);
278 }
279 else
280 {
281 DocumentBlock.read(_big_store.getBlocks(), buffer, offset);
282 }
283 }
284
285
290
291 DocumentProperty getDocumentProperty()
292 {
293 return _property;
294 }
295
296
297
298
307
308 public void writeBlocks(final OutputStream stream)
309 throws IOException
310 {
311 _big_store.writeBlocks(stream);
312 }
313
314
315
316
317
322
323 public int countBlocks()
324 {
325 return _big_store.countBlocks();
326 }
327
328
334
335 public void setStartBlock(final int index)
336 {
337 _property.setStartBlock(index);
338 }
339
340
341
342
343
349
350 public Object [] getViewableArray()
351 {
352 Object[] results = new Object[ 1 ];
353 String result;
354
355 try
356 {
357 ByteArrayOutputStream output = new ByteArrayOutputStream();
358 BlockWritable[] blocks = null;
359
360 if (_big_store.isValid())
361 {
362 blocks = _big_store.getBlocks();
363 }
364 else if (_small_store.isValid())
365 {
366 blocks = _small_store.getBlocks();
367 }
368 if (blocks != null)
369 {
370 for (int k = 0; k < blocks.length; k++)
371 {
372 blocks[ k ].writeBlocks(output);
373 }
374 byte[] data = output.toByteArray();
375
376 if (data.length > _property.getSize())
377 {
378 byte[] tmp = new byte[ _property.getSize() ];
379
380 System.arraycopy(data, 0, tmp, 0, tmp.length);
381 data = tmp;
382 }
383 output = new ByteArrayOutputStream();
384 HexDump.dump(data, 0, output, 0);
385 result = output.toString();
386 }
387 else
388 {
389 result = "<NO DATA>";
390 }
391 }
392 catch (IOException e)
393 {
394 result = e.getMessage();
395 }
396 results[ 0 ] = result;
397 return results;
398 }
399
400
407
408 public Iterator getViewableIterator()
409 {
410 return Collections.EMPTY_LIST.iterator();
411 }
412
413
420
421 public boolean preferArray()
422 {
423 return true;
424 }
425
426
432
433 public String getShortDescription()
434 {
435 StringBuffer buffer = new StringBuffer();
436
437 buffer.append("Document: \"").append(_property.getName())
438 .append("\"");
439 buffer.append(" size = ").append(getSize());
440 return buffer.toString();
441 }
442
443
444 private class SmallBlockStore
445 {
446 private SmallDocumentBlock[] smallBlocks;
447 private POIFSDocumentPath path;
448 private String name;
449 private int size;
450 private POIFSWriterListener writer;
451
452
457
458 SmallBlockStore(final Object [] blocks)
459 {
460 smallBlocks = new SmallDocumentBlock[ blocks.length ];
461 for (int j = 0; j < blocks.length; j++)
462 {
463 smallBlocks[ j ] = ( SmallDocumentBlock ) blocks[ j ];
464 }
465 this.path = null;
466 this.name = null;
467 this.size = -1;
468 this.writer = null;
469 }
470
471
480
481 SmallBlockStore(final POIFSDocumentPath path, final String name,
482 final int size, final POIFSWriterListener writer)
483 {
484 smallBlocks = new SmallDocumentBlock[ 0 ];
485 this.path = path;
486 this.name = name;
487 this.size = size;
488 this.writer = writer;
489 }
490
491
494
495 boolean isValid()
496 {
497 return ((smallBlocks.length > 0) || (writer != null));
498 }
499
500
503
504 BlockWritable [] getBlocks()
505 {
506 if (isValid() && (writer != null))
507 {
508 ByteArrayOutputStream stream =
509 new ByteArrayOutputStream(size);
510 DocumentOutputStream dstream =
511 new DocumentOutputStream(stream, size);
512
513 writer.processPOIFSWriterEvent(new POIFSWriterEvent(dstream,
514 path, name, size));
515 smallBlocks = SmallDocumentBlock.convert(stream.toByteArray(),
516 size);
517 }
518 return smallBlocks;
519 }
520 }
521
522 private class BigBlockStore
523 {
524 private DocumentBlock[] bigBlocks;
525 private POIFSDocumentPath path;
526 private String name;
527 private int size;
528 private POIFSWriterListener writer;
529
530
537
538 BigBlockStore(final Object [] blocks)
539 throws IOException
540 {
541 bigBlocks = new DocumentBlock[ blocks.length ];
542 for (int j = 0; j < blocks.length; j++)
543 {
544 if (blocks[ j ] instanceof DocumentBlock)
545 {
546 bigBlocks[ j ] = ( DocumentBlock ) blocks[ j ];
547 }
548 else
549 {
550 bigBlocks[ j ] =
551 new DocumentBlock(( RawDataBlock ) blocks[ j ]);
552 }
553 }
554 this.path = null;
555 this.name = null;
556 this.size = -1;
557 this.writer = null;
558 }
559
560
570
571 BigBlockStore(final POIFSDocumentPath path, final String name,
572 final int size, final POIFSWriterListener writer)
573 {
574 bigBlocks = new DocumentBlock[ 0 ];
575 this.path = path;
576 this.name = name;
577 this.size = size;
578 this.writer = writer;
579 }
580
581
584
585 boolean isValid()
586 {
587 return ((bigBlocks.length > 0) || (writer != null));
588 }
589
590
593
594 DocumentBlock [] getBlocks()
595 {
596 if (isValid() && (writer != null))
597 {
598 ByteArrayOutputStream stream =
599 new ByteArrayOutputStream(size);
600 DocumentOutputStream dstream =
601 new DocumentOutputStream(stream, size);
602
603 writer.processPOIFSWriterEvent(new POIFSWriterEvent(dstream,
604 path, name, size));
605 bigBlocks = DocumentBlock.convert(stream.toByteArray(), size);
606 }
607 return bigBlocks;
608 }
609
610
617
618 void writeBlocks(OutputStream stream)
619 throws IOException
620 {
621 if (isValid())
622 {
623 if (writer != null)
624 {
625 DocumentOutputStream dstream =
626 new DocumentOutputStream(stream, size);
627
628 writer.processPOIFSWriterEvent(
629 new POIFSWriterEvent(dstream, path, name, size));
630 dstream.writeFiller(countBlocks()
631 * POIFSConstants
632 .BIG_BLOCK_SIZE, DocumentBlock
633 .getFillByte());
634 }
635 else
636 {
637 for (int k = 0; k < bigBlocks.length; k++)
638 {
639 bigBlocks[ k ].writeBlocks(stream);
640 }
641 }
642 }
643 }
644
645 /**
646 * @return number of big blocks making up this document
647 */
648
649 int countBlocks()
650 {
651 int rval = 0;
652
653 if (isValid())
654 {
655 if (writer != null)
656 {
657 rval = (size + POIFSConstants.BIG_BLOCK_SIZE - 1)
658 / POIFSConstants.BIG_BLOCK_SIZE;
659 }
660 else
661 {
662 rval = bigBlocks.length;
663 }
664 }
665 return rval;
666 }
667 } // end private class BigBlockStore
668 } // end class POIFSDocument
669
670 ??????????????????????????????????????????????BIG_BLOCK_SIZE??????????????????????????????????????????????getFillByte??????????????????????????????????????????????????????????????DocumentBlock?????????????????????????????????????k?????????????????????????????????????????bigBlocks???????????????????????????????????????????????????????????k?????????????????????????bigBlocks????????????????????????????????????k????????????????????????????????????????writeBlocks????????????????????????????????????????????????????stream??????????????????????countBlocks?????????????????isValid?????????????????????writer?????????????????????rval?????????????????????????????size????????????????????????????????????POIFSConstants???????????????????????????????????????????????????BIG_BLOCK_SIZE??????????????????????????????POIFSConstants?????????????????????????????????????????????BIG_BLOCK_SIZE?????????????????????rval????????????????????????????bigBlocks????????????????????rval??????????????????