KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > jxl > read > 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.read.biff;
21
22 import java.util.ArrayList JavaDoc;
23 import java.util.Iterator JavaDoc;
24
25 import common.Logger;
26
27 import jxl.WorkbookSettings;
28 import jxl.biff.BaseCompoundFile;
29 import jxl.biff.IntegerHelper;
30
31 /**
32  * Reads in and defrags an OLE compound compound file
33  * (Made public only for the PropertySets demo)
34  */

35 public final class CompoundFile extends BaseCompoundFile
36 {
37   /**
38    * The logger
39    */

40   private static Logger logger = Logger.getLogger(CompoundFile.class);
41
42   /**
43    * The original OLE stream, organized into blocks, which can
44    * appear at any physical location in the file
45    */

46   private byte[] data;
47   /**
48    * The number of blocks it takes to store the big block depot
49    */

50   private int numBigBlockDepotBlocks;
51   /**
52    * The start block of the small block depot
53    */

54   private int sbdStartBlock;
55   /**
56    * The start block of the root entry
57    */

58   private int rootStartBlock;
59   /**
60    * The header extension block
61    */

62   private int extensionBlock;
63   /**
64    * The number of header extension blocks
65    */

66   private int numExtensionBlocks;
67   /**
68    * The root entry
69    */

70   private byte[] rootEntry;
71   /**
72    * The sequence of blocks which comprise the big block chain
73    */

74   private int[] bigBlockChain;
75   /**
76    * The sequence of blocks which comprise the small block chain
77    */

78   private int[] smallBlockChain;
79   /**
80    * The chain of blocks which comprise the big block depot
81    */

82   private int[] bigBlockDepotBlocks;
83   /**
84    * The list of property sets
85    */

86   private ArrayList JavaDoc propertySets;
87
88   /**
89    * The workbook settings
90    */

91   private WorkbookSettings settings;
92
93   /**
94    * Initializes the compound file
95    *
96    * @param d the raw data of the ole stream
97    * @param ws the workbook settings
98    * @exception BiffException
99    */

100   public CompoundFile(byte[] d, WorkbookSettings ws) throws BiffException
101   {
102     super();
103     data = d;
104     settings = ws;
105
106     // First verify the OLE identifier
107
for (int i = 0; i < IDENTIFIER.length; i++)
108     {
109       if (data[i] != IDENTIFIER[i])
110       {
111         throw new BiffException(BiffException.unrecognizedOLEFile);
112       }
113     }
114
115     propertySets = new ArrayList JavaDoc();
116     numBigBlockDepotBlocks = IntegerHelper.getInt
117       (data[NUM_BIG_BLOCK_DEPOT_BLOCKS_POS],
118        data[NUM_BIG_BLOCK_DEPOT_BLOCKS_POS + 1],
119        data[NUM_BIG_BLOCK_DEPOT_BLOCKS_POS + 2],
120        data[NUM_BIG_BLOCK_DEPOT_BLOCKS_POS + 3]);
121     sbdStartBlock = IntegerHelper.getInt
122       (data[SMALL_BLOCK_DEPOT_BLOCK_POS],
123        data[SMALL_BLOCK_DEPOT_BLOCK_POS + 1],
124        data[SMALL_BLOCK_DEPOT_BLOCK_POS + 2],
125        data[SMALL_BLOCK_DEPOT_BLOCK_POS + 3]);
126     rootStartBlock = IntegerHelper.getInt
127       (data[ROOT_START_BLOCK_POS],
128        data[ROOT_START_BLOCK_POS + 1],
129        data[ROOT_START_BLOCK_POS + 2],
130        data[ROOT_START_BLOCK_POS + 3]);
131     extensionBlock = IntegerHelper.getInt
132       (data[EXTENSION_BLOCK_POS],
133        data[EXTENSION_BLOCK_POS + 1],
134        data[EXTENSION_BLOCK_POS + 2],
135        data[EXTENSION_BLOCK_POS + 3]);
136     numExtensionBlocks = IntegerHelper.getInt
137       (data[NUM_EXTENSION_BLOCK_POS],
138        data[NUM_EXTENSION_BLOCK_POS + 1],
139        data[NUM_EXTENSION_BLOCK_POS + 2],
140        data[NUM_EXTENSION_BLOCK_POS + 3]);
141
142     bigBlockDepotBlocks = new int[numBigBlockDepotBlocks];
143
144     int pos = BIG_BLOCK_DEPOT_BLOCKS_POS;
145
146     int bbdBlocks = numBigBlockDepotBlocks;
147
148     if (numExtensionBlocks != 0)
149     {
150       bbdBlocks = (BIG_BLOCK_SIZE - BIG_BLOCK_DEPOT_BLOCKS_POS) / 4;
151     }
152
153     for (int i = 0; i < bbdBlocks; i++)
154     {
155       bigBlockDepotBlocks[i] = IntegerHelper.getInt
156         (d[pos], d[pos + 1], d[pos + 2], d[pos + 3]);
157       pos += 4;
158     }
159
160     for (int j = 0; j < numExtensionBlocks; j++)
161     {
162       pos = (extensionBlock + 1) * BIG_BLOCK_SIZE;
163       int blocksToRead = Math.min(numBigBlockDepotBlocks - bbdBlocks,
164                                   BIG_BLOCK_SIZE / 4 - 1);
165
166       for (int i = bbdBlocks; i < bbdBlocks + blocksToRead; i++)
167       {
168         bigBlockDepotBlocks[i] = IntegerHelper.getInt
169           (d[pos], d[pos + 1], d[pos + 2], d[pos + 3]);
170         pos += 4;
171       }
172
173       bbdBlocks += blocksToRead;
174       if (bbdBlocks < numBigBlockDepotBlocks)
175       {
176         extensionBlock = IntegerHelper.getInt
177           (d[pos], d[pos + 1], d[pos + 2], d[pos + 3]);
178       }
179     }
180
181     readBigBlockDepot();
182     readSmallBlockDepot();
183
184     rootEntry = readData(rootStartBlock);
185     readPropertySets();
186   }
187
188   /**
189    * Reads the big block depot entries
190    */

191   private void readBigBlockDepot()
192   {
193     int pos = 0;
194     int index = 0;
195     bigBlockChain = new int[numBigBlockDepotBlocks * BIG_BLOCK_SIZE / 4];
196
197     for (int i = 0; i < numBigBlockDepotBlocks; i++)
198     {
199       pos = (bigBlockDepotBlocks[i] + 1) * BIG_BLOCK_SIZE;
200
201       for (int j = 0; j < BIG_BLOCK_SIZE / 4; j++)
202       {
203         bigBlockChain[index] = IntegerHelper.getInt
204           (data[pos], data[pos + 1], data[pos + 2], data[pos + 3]);
205         pos += 4;
206         index++;
207       }
208     }
209   }
210
211   /**
212    * Reads the small block chain's depot entries
213    */

214   private void readSmallBlockDepot()
215   {
216     int pos = 0;
217     int index = 0;
218     int sbdBlock = sbdStartBlock;
219     smallBlockChain = new int[0];
220
221     while (sbdBlock != -2)
222     {
223       // Allocate some more space to the small block chain
224
int[] oldChain = smallBlockChain;
225       smallBlockChain = new int[smallBlockChain.length + BIG_BLOCK_SIZE / 4];
226       System.arraycopy(oldChain, 0, smallBlockChain, 0, oldChain.length);
227
228       pos = (sbdBlock + 1) * BIG_BLOCK_SIZE;
229
230       for (int j = 0; j < BIG_BLOCK_SIZE / 4; j++)
231       {
232         smallBlockChain[index] = IntegerHelper.getInt
233           (data[pos], data[pos + 1], data[pos + 2], data[pos + 3]);
234         pos += 4;
235         index++;
236       }
237
238       sbdBlock = bigBlockChain[sbdBlock];
239     }
240   }
241
242   /**
243    * Reads all the property sets
244    */

245   private void readPropertySets()
246   {
247     int offset = 0;
248     byte[] d = null;
249
250     while (offset < rootEntry.length)
251     {
252       d = new byte[PROPERTY_STORAGE_BLOCK_SIZE];
253       System.arraycopy(rootEntry, offset, d, 0, d.length);
254       PropertyStorage ps = new PropertyStorage(d);
255
256       // sometimes the MAC Operating system leaves some property storage
257
// names blank. Contributed by Jacky
258
if (ps.name == null || ps.name.length() == 0)
259       {
260         if (ps.type == ROOT_ENTRY_PS_TYPE)
261         {
262           ps.name = ROOT_ENTRY_NAME;
263           logger.warn("Property storage name for " + ps.type +
264                       " is empty - setting to " + ROOT_ENTRY_NAME);
265         }
266         else
267         {
268           logger.warn("Property storage type " + ps.type +
269                       " has no associated name");
270         }
271
272       }
273       propertySets.add(ps);
274       offset += PROPERTY_STORAGE_BLOCK_SIZE;
275     }
276   }
277
278   /**
279    * Gets the defragmented stream from this ole compound file
280    *
281    * @param streamName the stream name to get
282    * @return the defragmented ole stream
283    * @exception BiffException
284    */

285   public byte[] getStream(String JavaDoc streamName) throws BiffException
286   {
287     PropertyStorage ps = getPropertyStorage(streamName);
288
289     if (ps.size >= SMALL_BLOCK_THRESHOLD ||
290         streamName.equalsIgnoreCase(ROOT_ENTRY_NAME))
291     {
292       return getBigBlockStream(ps);
293     }
294     else
295     {
296       return getSmallBlockStream(ps);
297     }
298   }
299
300   /**
301    * Gets the property set with the specified name
302    * @param name the property storage name
303    * @return the property storage record
304    * @exception BiffException
305    */

306   private PropertyStorage getPropertyStorage(String JavaDoc name)
307     throws BiffException
308   {
309     // Find the workbook property
310
Iterator JavaDoc i = propertySets.iterator();
311     boolean found = false;
312     PropertyStorage ps = null;
313     while (!found && i.hasNext())
314     {
315       ps = (PropertyStorage) i.next();
316       if (ps.name.equalsIgnoreCase(name))
317       {
318         found = true;
319       }
320     }
321
322     if (!found)
323     {
324       throw new BiffException(BiffException.streamNotFound);
325     }
326
327     return ps;
328   }
329
330   /**
331    * Build up the resultant stream using the big blocks
332    *
333    * @param ps the property storage
334    * @return the big block stream
335    */

336   private byte[] getBigBlockStream(PropertyStorage ps)
337   {
338     int numBlocks = ps.size / BIG_BLOCK_SIZE;
339     if (ps.size % BIG_BLOCK_SIZE != 0)
340     {
341       numBlocks++;
342     }
343
344     byte[] streamData = new byte[numBlocks * BIG_BLOCK_SIZE];
345
346     int block = ps.startBlock;
347
348     int count = 0;
349     int pos = 0;
350     while (block != -2 && count < numBlocks)
351     {
352       pos = (block + 1) * BIG_BLOCK_SIZE;
353       System.arraycopy(data, pos, streamData,
354                        count * BIG_BLOCK_SIZE, BIG_BLOCK_SIZE);
355       count++;
356       block = bigBlockChain[block];
357     }
358
359     if (block != -2 && count == numBlocks)
360     {
361       logger.warn("Property storage size inconsistent with block chain.");
362     }
363
364     return streamData;
365   }
366
367   /**
368    * Build up the resultant stream using the small blocks
369    * @param ps the property storage
370    * @return the data
371    * @exception BiffException
372    */

373   private byte[] getSmallBlockStream(PropertyStorage ps)
374     throws BiffException
375   {
376     PropertyStorage rootps = null;
377     try
378     {
379       rootps = getPropertyStorage(ROOT_ENTRY_NAME);
380     }
381     catch (BiffException e)
382     {
383       rootps = (PropertyStorage) propertySets.get(0);
384     }
385
386     byte[] rootdata = readData(rootps.startBlock);
387     byte[] sbdata = new byte[0];
388
389     int block = ps.startBlock;
390     int pos = 0;
391     while (block != -2)
392     {
393       // grow the array
394
byte[] olddata = sbdata;
395       sbdata = new byte[olddata.length + SMALL_BLOCK_SIZE];
396       System.arraycopy(olddata, 0, sbdata, 0, olddata.length);
397
398       // Copy in the new data
399
pos = block * SMALL_BLOCK_SIZE;
400       System.arraycopy(rootdata, pos, sbdata,
401                        olddata.length, SMALL_BLOCK_SIZE);
402       block = smallBlockChain[block];
403     }
404
405     return sbdata;
406   }
407
408   /**
409    * Reads the block chain from the specified block and returns the
410    * data as a continuous stream of bytes
411    *
412    * @param bl the block number
413    * @return the data
414    */

415   private byte[] readData(int bl)
416   {
417     int block = bl;
418     int pos = 0;
419     byte[] entry = new byte[0];
420
421     while (block != -2)
422     {
423       // Grow the array
424
byte[] oldEntry = entry;
425       entry = new byte[oldEntry.length + BIG_BLOCK_SIZE];
426       System.arraycopy(oldEntry, 0, entry, 0, oldEntry.length);
427       pos = (block + 1) * BIG_BLOCK_SIZE;
428       System.arraycopy(data, pos, entry,
429                        oldEntry.length, BIG_BLOCK_SIZE);
430       block = bigBlockChain[block];
431     }
432     return entry;
433   }
434
435   /**
436    * Gets the property sets
437    * @return the list of property sets
438    */

439   public String JavaDoc[] getPropertySetNames()
440   {
441     String JavaDoc[] sets = new String JavaDoc[propertySets.size()];
442     for (int i = 0; i < sets.length; i++)
443     {
444       PropertyStorage ps = (PropertyStorage) propertySets.get(i);
445       sets[i] = ps.name;
446     }
447
448     return sets;
449   }
450
451   /**
452    * Gets the property set. Invoked when copying worksheets with macros
453    *
454    * @param ps the property set name
455    * @return the property set with the given name
456    */

457   public PropertyStorage getPropertySet(String JavaDoc ps)
458   {
459     boolean found = false;
460     PropertyStorage propertySet = null;
461     for (Iterator JavaDoc i = propertySets.iterator() ; i.hasNext() && !found ; )
462     {
463       propertySet = (PropertyStorage) i.next();
464       if (propertySet.name.equalsIgnoreCase(ps))
465       {
466         found = true;
467       }
468     }
469
470     return found ? propertySet : null;
471   }
472 }
473
474
475
476
477
478
479
480
481
482
483
484
485
Popular Tags