KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > jxl > write > biff > CompoundFile


1 /*********************************************************************
2 *
3 * Copyright (C) 2002 Andrew Khan
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 ***************************************************************************/

19
20 package jxl.write.biff;
21
22 import java.io.OutputStream JavaDoc;
23 import java.io.IOException JavaDoc;
24 import java.util.ArrayList JavaDoc;
25 import java.util.Iterator JavaDoc;
26 import java.util.HashMap JavaDoc;
27
28 import common.Assert;
29 import common.Logger;
30 import jxl.biff.BaseCompoundFile;
31 import jxl.biff.IntegerHelper;
32 import jxl.read.biff.BiffException;
33
34 /**
35  * Writes out a compound file
36  *
37  * Header block is -1
38  * Excel data is e..n (where is the head extension blocks, normally 0 and
39  * n is at least 8)
40  * Summary information (8 blocks)
41  * Document summary (8 blocks)
42  * BBD is block p..q (where p=e+n+16 and q-p+1 is the number of BBD blocks)
43  * Property storage block is q+b...r (normally 1 block) (where b is the number
44  * of BBD blocks)
45  */

46 final class CompoundFile extends BaseCompoundFile
47 {
48   /**
49    * The logger
50    */

51   private static Logger logger = Logger.getLogger(CompoundFile.class);
52
53   /**
54    * The stream to which the jumbled up data is written to
55    */

56   private OutputStream JavaDoc out;
57   /**
58    * The organized biff records which form the actual excel data
59    */

60   private byte[] excelData;
61
62   /**
63    * The size of the array
64    */

65   private int size;
66
67   /**
68    * The size the excel data should be in order to comply with the
69    * general compound file format
70    */

71   private int requiredSize;
72
73   /**
74    * The number of blocks it takes to store the big block depot
75    */

76   private int numBigBlockDepotBlocks;
77
78   /**
79    * The number of blocks it takes to store the small block depot chain
80    */

81   private int numSmallBlockDepotChainBlocks;
82
83   /**
84    * The number of blocks it takes to store the small block depot
85    */

86   private int numSmallBlockDepotBlocks;
87
88   /**
89    * The number of extension blocks required for the header to describe
90    * the BBD
91    */

92   private int numExtensionBlocks;
93
94   /**
95    * The extension block for the header
96    */

97   private int extensionBlock;
98
99   /**
100    * The number of blocks it takes to store the excel data
101    */

102   private int excelDataBlocks;
103
104   /**
105    * The start block of the root entry
106    */

107   private int rootStartBlock;
108
109   /**
110    * The start block of the excel data
111    */

112   private int excelDataStartBlock;
113
114   /**
115    * The start block of the big block depot
116    */

117   private int bbdStartBlock;
118
119   /**
120    * The start block of the small block depot
121    */

122   private int sbdStartBlockChain;
123
124   /**
125    * The start block of the small block depot
126    */

127   private int sbdStartBlock;
128
129   /**
130    * The number of big blocks required for additional property sets
131    */

132   private int additionalPropertyBlocks;
133
134   /**
135    * The number of small blocks
136    */

137   private int numSmallBlocks;
138
139   /**
140    * The total number of property sets in this compound file
141    */

142   private int numPropertySets;
143
144   /**
145    * The number of blocks required to store the root entry property sets
146    * and small block depot
147    */

148   private int numRootEntryBlocks;
149
150   /**
151    * The list of additional, non standard property sets names
152    */

153   private ArrayList JavaDoc additionalPropertySets;
154
155   /**
156    * A hash map of the original property sets keyed on name
157    */

158   private HashMap JavaDoc readPropertySets;
159
160   /**
161    * The array of standard property set mappings
162    */

163   private int[] standardPropertySetMappings;
164
165   private ReadPropertyStorage rootEntryPropertySet;
166
167   /**
168    * Structure used to store the property set and the data
169    */

170   private static final class ReadPropertyStorage
171   {
172     PropertyStorage propertyStorage;
173     byte[] data;
174     int number;
175
176     ReadPropertyStorage(PropertyStorage ps, byte[] d, int n)
177     {
178       propertyStorage = ps;
179       data = d;
180       number = n;
181     }
182   }
183
184
185   // The following member variables are used across methods when
186
// writing out the big block depot
187
/**
188    * The current position within the bbd. Used when writing out the
189    * BBD
190    */

191   private int bbdPos;
192
193   /**
194    * The current bbd block
195    */

196   private byte[] bigBlockDepot;
197
198
199   /**
200    * Constructor
201    *
202    * @param l the length of the data
203    * @param os the output stream to write to
204    * @param data the excel data
205    * @param rcf the read compound
206    */

207   public CompoundFile(byte[] data, int l, OutputStream JavaDoc os,
208                       jxl.read.biff.CompoundFile rcf)
209     throws CopyAdditionalPropertySetsException, IOException JavaDoc
210   {
211     super();
212     size = l;
213     excelData = data;
214
215     readAdditionalPropertySets(rcf);
216
217     numRootEntryBlocks = 1;
218     numPropertySets = 4 +
219       (additionalPropertySets != null ? additionalPropertySets.size() : 0);
220
221
222     if (additionalPropertySets != null)
223     {
224       numSmallBlockDepotChainBlocks = getBigBlocksRequired(numSmallBlocks * 4);
225       numSmallBlockDepotBlocks = getBigBlocksRequired
226         (numSmallBlocks * SMALL_BLOCK_SIZE);
227
228       numRootEntryBlocks += getBigBlocksRequired
229         (additionalPropertySets.size() * PROPERTY_STORAGE_BLOCK_SIZE);
230     }
231
232
233     int blocks = getBigBlocksRequired(l);
234
235     // First pad the data out so that it fits nicely into a whole number
236
// of blocks
237
if (l < SMALL_BLOCK_THRESHOLD)
238     {
239       requiredSize = SMALL_BLOCK_THRESHOLD;
240     }
241     else
242     {
243       requiredSize = blocks * BIG_BLOCK_SIZE;
244     }
245     
246     out = os;
247
248
249     // Do the calculations
250
excelDataBlocks = requiredSize/BIG_BLOCK_SIZE;
251     numBigBlockDepotBlocks = 1;
252
253     int blockChainLength = (BIG_BLOCK_SIZE - BIG_BLOCK_DEPOT_BLOCKS_POS)/4;
254
255     int startTotalBlocks = excelDataBlocks +
256       8 + // summary block
257
8 + // document information
258
additionalPropertyBlocks +
259       numSmallBlockDepotBlocks +
260       numSmallBlockDepotChainBlocks +
261       numRootEntryBlocks;
262
263     int totalBlocks = startTotalBlocks + numBigBlockDepotBlocks;
264
265     // Calculate the number of BBD blocks needed to hold this info
266
numBigBlockDepotBlocks = (int) Math.ceil( (double) totalBlocks /
267                                               (double) (BIG_BLOCK_SIZE/4));
268
269     // Does this affect the total?
270
totalBlocks = startTotalBlocks + numBigBlockDepotBlocks;
271
272     // And recalculate
273
numBigBlockDepotBlocks = (int) Math.ceil( (double) totalBlocks /
274                                               (double) (BIG_BLOCK_SIZE/4));
275
276     // Does this affect the total?
277
totalBlocks = startTotalBlocks + numBigBlockDepotBlocks;
278
279     // See if the excel bbd chain can fit into the header block.
280
// Remember to allow for the end of chain indicator
281
if (numBigBlockDepotBlocks > blockChainLength - 1 )
282     {
283       // Sod it - we need an extension block. We have to go through
284
// the whole tiresome calculation again
285
extensionBlock = 0;
286
287       // Compute the number of extension blocks
288
int bbdBlocksLeft = numBigBlockDepotBlocks - blockChainLength + 1;
289
290       numExtensionBlocks = (int) Math.ceil((double) bbdBlocksLeft /
291                                            (double) (BIG_BLOCK_SIZE/4 - 1));
292
293       // Modify the total number of blocks required and recalculate the
294
// the number of bbd blocks
295
totalBlocks = startTotalBlocks +
296                     numExtensionBlocks +
297                     numBigBlockDepotBlocks;
298       numBigBlockDepotBlocks = (int) Math.ceil( (double) totalBlocks /
299                                                 (double) (BIG_BLOCK_SIZE/4));
300
301       // The final total
302
totalBlocks = startTotalBlocks +
303                     numExtensionBlocks +
304                     numBigBlockDepotBlocks;
305     }
306     else
307     {
308       extensionBlock = -2;
309       numExtensionBlocks = 0;
310     }
311
312     // Set the excel data start block to be after the header (and
313
// its extensions)
314
excelDataStartBlock = numExtensionBlocks;
315
316     // Set the start block of the small block depot
317
sbdStartBlock = -2;
318     if (additionalPropertySets != null)
319     {
320       sbdStartBlock = excelDataStartBlock +
321                       excelDataBlocks +
322                       additionalPropertyBlocks +
323                       16;
324     }
325
326     // Set the sbd chain start block to be after the excel data and the
327
// small block depot
328
sbdStartBlockChain = -2;
329     
330     if (sbdStartBlock != -2)
331     {
332       sbdStartBlockChain = sbdStartBlock + numSmallBlockDepotBlocks;
333     }
334     
335     // Set the bbd start block to be after all the excel data
336
if (sbdStartBlockChain != -2)
337     {
338       bbdStartBlock = sbdStartBlockChain +
339                       numSmallBlockDepotChainBlocks;
340     }
341     else
342     {
343       bbdStartBlock = excelDataStartBlock +
344                       excelDataBlocks +
345                       additionalPropertyBlocks +
346                       16;
347     }
348
349     // Set the root start block to be after all the big block depot blocks
350
rootStartBlock = bbdStartBlock +
351                      numBigBlockDepotBlocks;
352
353
354     if (totalBlocks != rootStartBlock + numRootEntryBlocks)
355     {
356       logger.warn("Root start block and total blocks are inconsistent " +
357                   " generated file may be corrupt");
358       logger.warn("RootStartBlock " + rootStartBlock + " totalBlocks " + totalBlocks);
359     }
360   }
361
362   /**
363    * Reads the additional property sets from the read in compound file
364    *
365    * @return the number of blocks needed to store these property sets
366    */

367   private void readAdditionalPropertySets
368     (jxl.read.biff.CompoundFile readCompoundFile)
369     throws CopyAdditionalPropertySetsException, IOException JavaDoc
370   {
371     if (readCompoundFile == null)
372     {
373       return;
374     }
375
376     additionalPropertySets = new ArrayList JavaDoc();
377     readPropertySets = new HashMap JavaDoc();
378
379     String JavaDoc[] psnames = readCompoundFile.getPropertySetNames();
380     int blocksRequired = 0;
381     standardPropertySetMappings = new int[STANDARD_PROPERTY_SETS.length];
382
383     for (int i = 0 ; i < psnames.length ; i++)
384     {
385       // Add it to the hash map for later
386
PropertyStorage ps = readCompoundFile.getPropertySet(psnames[i]);
387
388       // If the name is non standard, then retrieve the property set
389
// information
390
boolean standard = false;
391       for (int j = 0 ; j < STANDARD_PROPERTY_SETS.length && !standard ; j++)
392       {
393         if (psnames[i].equalsIgnoreCase(STANDARD_PROPERTY_SETS[j]))
394         {
395           standard = true;
396           ReadPropertyStorage rps = new ReadPropertyStorage(ps, null, i);
397           readPropertySets.put(psnames[i], rps);
398         }
399       }
400
401       if (!standard)
402       {
403         try
404         {
405           byte[] data = null;
406           if (ps.size > 0 )
407           {
408             data = readCompoundFile.getStream(ps.name);
409           }
410           else
411           {
412             data = new byte[0];
413           }
414           ReadPropertyStorage rps = new ReadPropertyStorage(ps, data, i);
415           readPropertySets.put(psnames[i], rps);
416           additionalPropertySets.add(rps);
417
418           if (data.length > SMALL_BLOCK_THRESHOLD)
419           {
420             int blocks = getBigBlocksRequired(data.length);
421             blocksRequired += blocks;
422           }
423           else
424           {
425             int blocks = getSmallBlocksRequired(data.length);
426             numSmallBlocks += blocks;
427           }
428         }
429         catch (BiffException e)
430         {
431           logger.error(e);
432           throw new CopyAdditionalPropertySetsException();
433         }
434       }
435     }
436
437     additionalPropertyBlocks = blocksRequired;
438   }
439
440
441   /**
442    * Writes out the excel file in OLE compound file format
443    *
444    * @exception IOException
445    */

446   public void write() throws IOException JavaDoc
447   {
448     writeHeader();
449     writeExcelData();
450     writeDocumentSummaryData();
451     writeSummaryData();
452     writeAdditionalPropertySets();
453     writeSmallBlockDepot();
454     writeSmallBlockDepotChain();
455     writeBigBlockDepot();
456     writePropertySets();
457     
458     // Don't flush or close the stream - this is handled by the enclosing File
459
// object
460
}
461
462   /**
463    * Writes out any additional property sets
464    */

465   private void writeAdditionalPropertySets() throws IOException JavaDoc
466   {
467     if (additionalPropertySets == null)
468     {
469       return;
470     }
471
472     for (Iterator JavaDoc i = additionalPropertySets.iterator(); i.hasNext() ;)
473     {
474       ReadPropertyStorage rps = (ReadPropertyStorage) i.next();
475       byte[] data = rps.data;
476
477       if (data.length > SMALL_BLOCK_THRESHOLD)
478       {
479         int numBlocks = getBigBlocksRequired(data.length);
480         int requiredSize = numBlocks * BIG_BLOCK_SIZE;
481
482         out.write(data, 0, data.length);
483       
484         byte[] padding = new byte[requiredSize - data.length];
485         out.write(padding, 0, padding.length);
486       }
487     }
488
489     // if (rps.propertyStorage.name.equals("Module1"))
490
/*
491       {
492         System.out.println("terminating");
493         out.flush();
494         out.close();
495         System.exit(1);
496       }
497     */

498   }
499
500   /**
501    * Writes out the excel data, padding it out with empty bytes as
502    * necessary
503    * Also write out empty
504    *
505    * @exception IOException
506    */

507   private void writeExcelData() throws IOException JavaDoc
508   {
509     out.write(excelData, 0, size);
510
511     byte[] padding = new byte[requiredSize - size];
512     out.write(padding);
513   }
514
515   /**
516    * Write out the document summary data. This is just blank
517    *
518    * @exception IOException
519    */

520   private void writeDocumentSummaryData() throws IOException JavaDoc
521   {
522     byte[] padding = new byte[SMALL_BLOCK_THRESHOLD];
523
524     // Write out the summary information
525
out.write(padding);
526   }
527
528   /**
529    * Write out the summary data. This is just blank
530    *
531    * @exception IOException
532    */

533   private void writeSummaryData() throws IOException JavaDoc
534   {
535     byte[] padding = new byte[SMALL_BLOCK_THRESHOLD];
536
537     // Write out the summary information
538
out.write(padding);
539   }
540
541   /**
542    * Writes the compound file header
543    *
544    * @exception IOException
545    */

546   private void writeHeader() throws IOException JavaDoc
547   {
548     // Build up the header array
549
byte[] headerBlock = new byte[BIG_BLOCK_SIZE];
550     byte[] extensionBlockData = new byte[BIG_BLOCK_SIZE * numExtensionBlocks];
551
552     // Copy in the identifier
553
System.arraycopy(IDENTIFIER, 0, headerBlock, 0, IDENTIFIER.length);
554
555     // Copy in some magic values - no idea what they mean
556
headerBlock[0x18] = 0x3e;
557     headerBlock[0x1a] = 0x3;
558     headerBlock[0x1c] = (byte) 0xfe;
559     headerBlock[0x1d] = (byte) 0xff;
560     headerBlock[0x1e] = 0x9;
561     headerBlock[0x20] = 0x6;
562     headerBlock[0x39] = 0x10;
563
564     // Set the number of BBD blocks
565
IntegerHelper.getFourBytes(numBigBlockDepotBlocks,
566                                headerBlock,
567                                NUM_BIG_BLOCK_DEPOT_BLOCKS_POS);
568
569     // Set the small block depot chain
570
IntegerHelper.getFourBytes(sbdStartBlockChain,
571                                headerBlock,
572                                SMALL_BLOCK_DEPOT_BLOCK_POS);
573
574     // Set the number of blocks in the small block depot chain
575
IntegerHelper.getFourBytes(numSmallBlockDepotChainBlocks,
576                                headerBlock,
577                                NUM_SMALL_BLOCK_DEPOT_BLOCKS_POS);
578
579     // Set the extension block
580
IntegerHelper.getFourBytes(extensionBlock,
581                                headerBlock,
582                                EXTENSION_BLOCK_POS);
583
584     // Set the number of extension blocks to be the number of BBD blocks - 1
585
IntegerHelper.getFourBytes(numExtensionBlocks,
586                                headerBlock,
587                                NUM_EXTENSION_BLOCK_POS);
588     
589     // Set the root start block
590
IntegerHelper.getFourBytes(rootStartBlock,
591                                headerBlock,
592                                ROOT_START_BLOCK_POS);
593
594     // Set the block numbers for the BBD. Set the BBD running
595
// after the excel data and summary information
596
int pos = BIG_BLOCK_DEPOT_BLOCKS_POS;
597
598     // See how many blocks fit into the header
599
int blocksToWrite = Math.min(numBigBlockDepotBlocks,
600                                  (BIG_BLOCK_SIZE -
601                                   BIG_BLOCK_DEPOT_BLOCKS_POS)/4);
602     int extensionBlock = 0;
603     int blocksWritten = 0;
604
605     for (int i = 0 ; i < blocksToWrite; i++)
606     {
607       IntegerHelper.getFourBytes(bbdStartBlock + i,
608                                  headerBlock,
609                                  pos);
610       pos += 4;
611       blocksWritten++;
612     }
613     
614     // Pad out the rest of the header with blanks
615
for (int i = pos; i < BIG_BLOCK_SIZE; i++)
616     {
617       headerBlock[i] = (byte) 0xff;
618     }
619
620     out.write(headerBlock);
621
622     // Write out the extension blocks
623
pos = 0;
624
625     for (int extBlock = 0; extBlock < numExtensionBlocks; extBlock++)
626     {
627       blocksToWrite = Math.min(numBigBlockDepotBlocks - blocksWritten,
628                                BIG_BLOCK_SIZE/4 -1);
629
630       for(int j = 0 ; j < blocksToWrite; j++)
631       {
632         IntegerHelper.getFourBytes(bbdStartBlock + blocksWritten + j,
633                                    extensionBlockData,
634                                    pos);
635         pos += 4;
636       }
637
638       blocksWritten += blocksToWrite;
639
640       // Indicate the next block, or the termination of the chain
641
int nextBlock = (blocksWritten == numBigBlockDepotBlocks) ?
642                               -2 : extBlock+1 ;
643       IntegerHelper.getFourBytes(nextBlock, extensionBlockData, pos);
644       pos +=4;
645     }
646
647     if (numExtensionBlocks > 0)
648     {
649       // Pad out the rest of the extension block with blanks
650
for (int i = pos; i < extensionBlockData.length; i++)
651       {
652         extensionBlockData[i] = (byte) 0xff;
653       }
654
655       out.write(extensionBlockData);
656     }
657   }
658
659   /**
660    * Checks that the data can fit into the current BBD block. If not,
661    * then it moves on to the next block
662    *
663    * @exception IOException
664    */

665   private void checkBbdPos() throws IOException JavaDoc
666   {
667     if (bbdPos >= BIG_BLOCK_SIZE)
668     {
669       // Write out the extension block. This will simply be the next block
670
out.write(bigBlockDepot);
671       
672       // Create a new block
673
bigBlockDepot = new byte[BIG_BLOCK_SIZE];
674       bbdPos = 0;
675     }
676   }
677
678   /**
679    * Writes out the big block chain
680    *
681    * @param startBlock the starting block of the big block chain
682    * @param numBlocks the number of blocks in the chain
683    * @exception IOException
684    */

685   private void writeBlockChain(int startBlock, int numBlocks)
686     throws IOException JavaDoc
687   {
688     int blocksToWrite = numBlocks - 1;
689     int blockNumber = startBlock + 1;
690     
691     while (blocksToWrite > 0)
692     {
693       int bbdBlocks = Math.min(blocksToWrite, (BIG_BLOCK_SIZE - bbdPos)/4);
694
695       for (int i = 0 ; i < bbdBlocks; i++)
696       {
697         IntegerHelper.getFourBytes(blockNumber, bigBlockDepot, bbdPos);
698         bbdPos +=4 ;
699         blockNumber++;
700       }
701       
702       blocksToWrite -= bbdBlocks;
703       checkBbdPos();
704     }
705
706     // Write the end of the block chain
707
IntegerHelper.getFourBytes(-2, bigBlockDepot, bbdPos);
708     bbdPos += 4;
709     checkBbdPos();
710   }
711
712   /**
713    * Writes the block chains for the additional property sets
714    *
715    * @exception IOException
716    */

717   private void writeAdditionalPropertySetBlockChains() throws IOException JavaDoc
718   {
719     if (additionalPropertySets == null)
720     {
721       return;
722     }
723
724     int blockNumber = excelDataStartBlock + excelDataBlocks + 16;
725     for (Iterator JavaDoc i = additionalPropertySets.iterator(); i.hasNext() ; )
726     {
727       ReadPropertyStorage rps = (ReadPropertyStorage) i.next();
728       if (rps.data.length > SMALL_BLOCK_THRESHOLD)
729       {
730         String JavaDoc psname = rps.propertyStorage.name;
731         int numBlocks = getBigBlocksRequired(rps.data.length);
732
733         writeBlockChain(blockNumber, numBlocks);
734         blockNumber += numBlocks;
735       }
736     }
737   }
738   
739   /**
740    * Writes out the chains for the small block depot
741    */

742   private void writeSmallBlockDepotChain() throws IOException JavaDoc
743   {
744     if (sbdStartBlockChain == -2)
745     {
746       return;
747     }
748
749     byte[] smallBlockDepotChain =
750       new byte[numSmallBlockDepotChainBlocks * BIG_BLOCK_SIZE];
751
752     int pos = 0;
753     int sbdBlockNumber = 1;
754
755     for (Iterator JavaDoc i = additionalPropertySets.iterator(); i.hasNext() ; )
756     {
757       ReadPropertyStorage rps = (ReadPropertyStorage) i.next();
758
759       if (rps.data.length <= SMALL_BLOCK_THRESHOLD &&
760           rps.data.length != 0)
761       {
762         int numSmallBlocks = getSmallBlocksRequired(rps.data.length);
763         for (int j = 0 ; j < numSmallBlocks - 1 ; j++)
764         {
765           IntegerHelper.getFourBytes(sbdBlockNumber,
766                                      smallBlockDepotChain,
767                                      pos);
768           pos += 4;
769           sbdBlockNumber++;
770         }
771
772         // Write out the end of chain
773
IntegerHelper.getFourBytes(-2, smallBlockDepotChain, pos);
774         pos += 4;
775         sbdBlockNumber++;
776       }
777     }
778
779     out.write(smallBlockDepotChain);
780   }
781
782   /**
783    * Writes out all the data in the small block depot
784    *
785    * @exception
786    */

787   private void writeSmallBlockDepot() throws IOException JavaDoc
788   {
789     if (additionalPropertySets == null)
790     {
791       return;
792     }
793
794     byte[] smallBlockDepot =
795       new byte[numSmallBlockDepotBlocks * BIG_BLOCK_SIZE];
796
797     int pos = 0;
798
799     /*
800     int smallBlocks2 = getSmallBlocksRequired(rootEntryPropertySet.data.length);
801     int length2 = smallBlocks2 * SMALL_BLOCK_SIZE;
802     System.arraycopy(rootEntryPropertySet.data, 0, smallBlockDepot, pos, rootEntryPropertySet.data.length);
803     pos += length2;
804     */

805
806     for (Iterator JavaDoc i = additionalPropertySets.iterator() ; i.hasNext() ; )
807     {
808       ReadPropertyStorage rps = (ReadPropertyStorage) i.next();
809
810       if (rps.data.length <= SMALL_BLOCK_THRESHOLD)
811       {
812         int smallBlocks = getSmallBlocksRequired(rps.data.length);
813         int length = smallBlocks * SMALL_BLOCK_SIZE;
814         System.arraycopy(rps.data, 0, smallBlockDepot, pos, rps.data.length);
815         pos += length;
816       }
817     }
818
819     out.write(smallBlockDepot);
820   }
821
822   /**
823    * Writes out the Big Block Depot
824    *
825    * @exception IOException
826    */

827   private void writeBigBlockDepot() throws IOException JavaDoc
828   {
829     // This is after the excel data, the summary information, the
830
// big block property sets and the small block depot
831
bigBlockDepot = new byte[BIG_BLOCK_SIZE];
832     bbdPos = 0;
833
834     // Write out the extension blocks, indicating them as special blocks
835
for (int i = 0 ; i < numExtensionBlocks; i++)
836     {
837       IntegerHelper.getFourBytes(-3, bigBlockDepot, bbdPos);
838       bbdPos += 4;
839       checkBbdPos();
840     }
841
842     writeBlockChain(excelDataStartBlock, excelDataBlocks);
843     
844     // The excel data has been written. Now write out the rest of it
845

846     // Write the block chain for the summary information
847
int summaryInfoBlock = excelDataStartBlock +
848       excelDataBlocks +
849       additionalPropertyBlocks;
850
851     for (int i = summaryInfoBlock; i < summaryInfoBlock + 7; i++)
852     {
853       IntegerHelper.getFourBytes(i + 1, bigBlockDepot, bbdPos);
854       bbdPos +=4 ;
855       checkBbdPos();
856     }
857
858     // Write the end of the block chain for the summary info block
859
IntegerHelper.getFourBytes(-2, bigBlockDepot, bbdPos);
860     bbdPos += 4;
861     checkBbdPos();
862
863     // Write the block chain for the document summary information
864
for (int i = summaryInfoBlock + 8; i < summaryInfoBlock + 15; i++)
865     {
866       IntegerHelper.getFourBytes(i + 1, bigBlockDepot, bbdPos);
867       bbdPos +=4 ;
868       checkBbdPos();
869     }
870
871     // Write the end of the block chain for the document summary
872
IntegerHelper.getFourBytes(-2, bigBlockDepot, bbdPos);
873     bbdPos += 4;
874     checkBbdPos();
875
876     // Write out the block chain for the copied property sets, if present
877
writeAdditionalPropertySetBlockChains();
878
879     if (sbdStartBlock != -2)
880     {
881       // Write out the block chain for the small block depot
882
writeBlockChain(sbdStartBlock, numSmallBlockDepotBlocks);
883
884       // Write out the block chain for the small block depot chain
885
writeBlockChain(sbdStartBlockChain, numSmallBlockDepotChainBlocks);
886     }
887
888     // The Big Block Depot immediately follows the document summary. Denote
889
// these as a special block
890
for (int i = 0; i < numBigBlockDepotBlocks; i++)
891     {
892       IntegerHelper.getFourBytes(-3, bigBlockDepot, bbdPos);
893       bbdPos += 4;
894       checkBbdPos();
895     }
896
897     // Write the root entry
898
writeBlockChain(rootStartBlock, numRootEntryBlocks);
899
900     // Pad out the remainder of the block
901
if (bbdPos != 0)
902     {
903       for (int i = bbdPos; i < BIG_BLOCK_SIZE; i++)
904       {
905         bigBlockDepot[i] = (byte) 0xff;
906       }
907       out.write(bigBlockDepot);
908     }
909   }
910
911   /**
912    * Calculates the number of big blocks required to store data of the
913    * specified length
914    *
915    * @param length the length of the data
916    * @return the number of big blocks required to store the data
917    */

918   private int getBigBlocksRequired(int length)
919   {
920     int blocks = length / BIG_BLOCK_SIZE;
921     
922     return (length % BIG_BLOCK_SIZE > 0 )? blocks + 1 : blocks;
923   }
924
925   /**
926    * Calculates the number of small blocks required to store data of the
927    * specified length
928    *
929    * @param length the length of the data
930    * @return the number of small blocks required to store the data
931    */

932   private int getSmallBlocksRequired(int length)
933   {
934     int blocks = length / SMALL_BLOCK_SIZE;
935     
936     return (length % SMALL_BLOCK_SIZE > 0 )? blocks + 1 : blocks;
937   }
938
939   /**
940    * Writes out the property sets
941    *
942    * @exception IOException
943    */

944   private void writePropertySets() throws IOException JavaDoc
945   {
946     byte[] propertySetStorage = new byte[BIG_BLOCK_SIZE * numRootEntryBlocks];
947
948     int pos = 0;
949     int[] mappings = null;
950
951     // Build up the mappings array
952
if (additionalPropertySets != null)
953     {
954       mappings = new int[numPropertySets];
955       
956       // Map the standard ones to the first four
957
for (int i = 0 ; i < STANDARD_PROPERTY_SETS.length ; i++)
958       {
959         ReadPropertyStorage rps = (ReadPropertyStorage)
960           readPropertySets.get(STANDARD_PROPERTY_SETS[i]);
961         mappings[rps.number] = i;
962       }
963
964       // Now go through the original ones
965
int newMapping = STANDARD_PROPERTY_SETS.length;
966       for (Iterator JavaDoc i = additionalPropertySets.iterator(); i.hasNext(); )
967       {
968         ReadPropertyStorage rps = (ReadPropertyStorage) i.next();
969         mappings[rps.number] = newMapping;
970         newMapping++;
971       }
972     }
973
974     int child = 0;
975     int previous = 0;
976     int next = 0;
977
978     // Compute the size of the root property set
979
int size = 0;
980     
981     if (additionalPropertySets != null)
982     {
983       // Workbook
984
size += getBigBlocksRequired(requiredSize) * BIG_BLOCK_SIZE;
985
986       // The two information blocks
987
size += getBigBlocksRequired(SMALL_BLOCK_THRESHOLD) * BIG_BLOCK_SIZE;
988       size += getBigBlocksRequired(SMALL_BLOCK_THRESHOLD) * BIG_BLOCK_SIZE;
989
990       // Additional property sets
991
for (Iterator JavaDoc i = additionalPropertySets.iterator(); i.hasNext(); )
992       {
993         ReadPropertyStorage rps = (ReadPropertyStorage) i.next();
994         if (rps.propertyStorage.type != 1)
995         {
996         if (rps.propertyStorage.size >= SMALL_BLOCK_THRESHOLD)
997         {
998           size += getBigBlocksRequired(rps.propertyStorage.size) *
999             BIG_BLOCK_SIZE;
1000        }
1001        else
1002        {
1003          size += getSmallBlocksRequired(rps.propertyStorage.size) *
1004            SMALL_BLOCK_SIZE;
1005        }
1006        }
1007      }
1008    }
1009
1010    // Set the root entry property set
1011
PropertyStorage ps = new PropertyStorage(ROOT_ENTRY_NAME);
1012    ps.setType(5);
1013    ps.setStartBlock(sbdStartBlock);
1014    ps.setSize(size);
1015    ps.setPrevious(-1);
1016    ps.setNext(-1);
1017    ps.setColour(0);
1018
1019    child = 1;
1020    if (additionalPropertySets != null)
1021    {
1022      ReadPropertyStorage rps = (ReadPropertyStorage)
1023                            readPropertySets.get(ROOT_ENTRY_NAME);
1024      child = mappings[rps.propertyStorage.child];
1025    }
1026    ps.setChild(child);
1027
1028    System.arraycopy(ps.data, 0,
1029                     propertySetStorage, pos,
1030                     PROPERTY_STORAGE_BLOCK_SIZE);
1031    pos += PROPERTY_STORAGE_BLOCK_SIZE;
1032
1033
1034    // Set the workbook property set
1035
ps = new PropertyStorage(WORKBOOK_NAME);
1036    ps.setType(2);
1037    ps.setStartBlock(excelDataStartBlock);
1038      // start the excel data after immediately after this block
1039
ps.setSize(requiredSize);
1040      // alway use a big block stream - none of that messing around
1041
// with small blocks
1042

1043    previous = 3;
1044    next = -1;
1045
1046    if (additionalPropertySets != null)
1047    {
1048      ReadPropertyStorage rps = (ReadPropertyStorage)
1049        readPropertySets.get(WORKBOOK_NAME);
1050      previous = rps.propertyStorage.previous != -1 ?
1051        mappings[rps.propertyStorage.previous] : -1;
1052      next = rps.propertyStorage.next != -1 ?
1053        mappings[rps.propertyStorage.next] : -1 ;
1054    }
1055
1056    ps.setPrevious(previous);
1057    ps.setNext(next);
1058    ps.setChild(-1);
1059
1060    System.arraycopy(ps.data, 0,
1061                     propertySetStorage, pos,
1062                     PROPERTY_STORAGE_BLOCK_SIZE);
1063    pos += PROPERTY_STORAGE_BLOCK_SIZE;
1064
1065    // Set the summary information
1066
ps = new PropertyStorage(SUMMARY_INFORMATION_NAME);
1067    ps.setType(2);
1068    ps.setStartBlock(excelDataStartBlock + excelDataBlocks);
1069    ps.setSize(SMALL_BLOCK_THRESHOLD);
1070
1071    previous = 1;
1072    next = 3;
1073
1074    if (additionalPropertySets != null)
1075    {
1076      ReadPropertyStorage rps = (ReadPropertyStorage)
1077                            readPropertySets.get(SUMMARY_INFORMATION_NAME);
1078
1079      previous = rps.propertyStorage.previous != - 1 ?
1080        mappings[rps.propertyStorage.previous] : -1 ;
1081      next = rps.propertyStorage.next != - 1 ?
1082        mappings[rps.propertyStorage.next] : -1 ;
1083    }
1084
1085    ps.setPrevious(previous);
1086    ps.setNext(next);
1087    ps.setChild(-1);
1088
1089    System.arraycopy(ps.data, 0,
1090                     propertySetStorage, pos,
1091                     PROPERTY_STORAGE_BLOCK_SIZE);
1092    pos += PROPERTY_STORAGE_BLOCK_SIZE;
1093
1094    // Set the document summary information
1095
ps = new PropertyStorage(DOCUMENT_SUMMARY_INFORMATION_NAME);
1096    ps.setType(2);
1097    ps.setStartBlock(excelDataStartBlock + excelDataBlocks + 8);
1098    ps.setSize(SMALL_BLOCK_THRESHOLD);
1099    ps.setPrevious(-1);
1100    ps.setNext(-1);
1101    ps.setChild(-1);
1102
1103    System.arraycopy(ps.data, 0,
1104                     propertySetStorage, pos,
1105                     PROPERTY_STORAGE_BLOCK_SIZE);
1106    pos += PROPERTY_STORAGE_BLOCK_SIZE;
1107
1108
1109
1110    // Write out the additional property sets
1111
if (additionalPropertySets == null)
1112    {
1113      out.write(propertySetStorage);
1114      return;
1115    }
1116    
1117    int bigBlock = excelDataStartBlock + excelDataBlocks + 16;
1118    int smallBlock = 0;
1119    int sz = 0;
1120
1121    for (Iterator JavaDoc i = additionalPropertySets.iterator() ; i.hasNext(); )
1122    {
1123      ReadPropertyStorage rps = (ReadPropertyStorage) i.next();
1124 
1125      int block = rps.data.length > SMALL_BLOCK_THRESHOLD ?
1126        bigBlock : smallBlock;
1127
1128      ps = new PropertyStorage(rps.propertyStorage.name);
1129      ps.setType(rps.propertyStorage.type);
1130      ps.setStartBlock(block);
1131      ps.setSize(rps.propertyStorage.size);
1132      // ps.setColour(rps.propertyStorage.colour);
1133

1134      previous = rps.propertyStorage.previous != -1 ?
1135        mappings[rps.propertyStorage.previous] : -1;
1136      next = rps.propertyStorage.next != -1 ?
1137        mappings[rps.propertyStorage.next] : -1;
1138      child = rps.propertyStorage.child != -1 ?
1139        mappings[rps.propertyStorage.child] : -1;
1140
1141      ps.setPrevious(previous);
1142      ps.setNext(next);
1143      ps.setChild(child);
1144
1145      System.arraycopy(ps.data, 0,
1146                       propertySetStorage, pos,
1147                       PROPERTY_STORAGE_BLOCK_SIZE);
1148      pos += PROPERTY_STORAGE_BLOCK_SIZE;
1149
1150      if (rps.data.length > SMALL_BLOCK_THRESHOLD)
1151      {
1152        bigBlock += getBigBlocksRequired(rps.data.length);
1153      }
1154      else
1155      {
1156        smallBlock += getSmallBlocksRequired(rps.data.length);
1157      }
1158    }
1159
1160    out.write(propertySetStorage);
1161  }
1162}
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
Popular Tags