KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > poi > poifs > storage > BlockAllocationTableReader


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.storage;
20
21 import java.io.IOException JavaDoc;
22 import java.io.OutputStream JavaDoc;
23
24 import java.util.*;
25
26 import org.apache.poi.poifs.common.POIFSConstants;
27 import org.apache.poi.util.IntList;
28 import org.apache.poi.util.LittleEndian;
29 import org.apache.poi.util.LittleEndianConsts;
30
31 /**
32  * This class manages and creates the Block Allocation Table, which is
33  * basically a set of linked lists of block indices.
34  * <P>
35  * Each block of the filesystem has an index. The first block, the
36  * header, is skipped; the first block after the header is index 0,
37  * the next is index 1, and so on.
38  * <P>
39  * A block's index is also its index into the Block Allocation
40  * Table. The entry that it finds in the Block Allocation Table is the
41  * index of the next block in the linked list of blocks making up a
42  * file, or it is set to -2: end of list.
43  *
44  * @author Marc Johnson (mjohnson at apache dot org)
45  */

46
47 public class BlockAllocationTableReader
48 {
49     private IntList _entries;
50
51     /**
52      * create a BlockAllocationTableReader for an existing filesystem. Side
53      * effect: when this method finishes, the BAT blocks will have
54      * been removed from the raw block list, and any blocks labeled as
55      * 'unused' in the block allocation table will also have been
56      * removed from the raw block list.
57      *
58      * @param block_count the number of BAT blocks making up the block
59      * allocation table
60      * @param block_array the array of BAT block indices from the
61      * filesystem's header
62      * @param xbat_count the number of XBAT blocks
63      * @param xbat_index the index of the first XBAT block
64      * @param raw_block_list the list of RawDataBlocks
65      *
66      * @exception IOException if, in trying to create the table, we
67      * encounter logic errors
68      */

69
70     public BlockAllocationTableReader(final int block_count,
71                                       final int [] block_array,
72                                       final int xbat_count,
73                                       final int xbat_index,
74                                       final BlockList raw_block_list)
75         throws IOException JavaDoc
76     {
77         this();
78         if (block_count <= 0)
79         {
80             throw new IOException JavaDoc(
81                 "Illegal block count; minimum count is 1, got " + block_count
82                 + " instead");
83         }
84
85         // acquire raw data blocks containing the BAT block data
86
RawDataBlock blocks[] = new RawDataBlock[ block_count ];
87         int limit = Math.min(block_count, block_array.length);
88         int block_index;
89
90         for (block_index = 0; block_index < limit; block_index++)
91         {
92             blocks[ block_index ] =
93                 ( RawDataBlock ) raw_block_list
94                     .remove(block_array[ block_index ]);
95         }
96         if (block_index < block_count)
97         {
98
99             // must have extended blocks
100
if (xbat_index < 0)
101             {
102                 throw new IOException JavaDoc(
103                     "BAT count exceeds limit, yet XBAT index indicates no valid entries");
104             }
105             int chain_index = xbat_index;
106             int max_entries_per_block = BATBlock.entriesPerXBATBlock();
107             int chain_index_offset = BATBlock.getXBATChainOffset();
108
109             for (int j = 0; j < xbat_count; j++)
110             {
111                 limit = Math.min(block_count - block_index,
112                                  max_entries_per_block);
113                 byte[] data = raw_block_list.remove(chain_index).getData();
114                 int offset = 0;
115
116                 for (int k = 0; k < limit; k++)
117                 {
118                     blocks[ block_index++ ] =
119                         ( RawDataBlock ) raw_block_list
120                             .remove(LittleEndian.getInt(data, offset));
121                     offset += LittleEndianConsts.INT_SIZE;
122                 }
123                 chain_index = LittleEndian.getInt(data, chain_index_offset);
124                 if (chain_index == POIFSConstants.END_OF_CHAIN)
125                 {
126                     break;
127                 }
128             }
129         }
130         if (block_index != block_count)
131         {
132             throw new IOException JavaDoc("Could not find all blocks");
133         }
134
135         // now that we have all of the raw data blocks, go through and
136
// create the indices
137
setEntries(blocks, raw_block_list);
138     }
139
140     /**
141      * create a BlockAllocationTableReader from an array of raw data blocks
142      *
143      * @param blocks the raw data
144      * @param raw_block_list the list holding the managed blocks
145      *
146      * @exception IOException
147      */

148
149     BlockAllocationTableReader(final ListManagedBlock [] blocks,
150                                final BlockList raw_block_list)
151         throws IOException JavaDoc
152     {
153         this();
154         setEntries(blocks, raw_block_list);
155     }
156
157     /**
158      * Constructor BlockAllocationTableReader
159      *
160      *
161      */

162
163     BlockAllocationTableReader()
164     {
165         _entries = new IntList();
166     }
167
168     /**
169      * walk the entries from a specified point and return the
170      * associated blocks. The associated blocks are removed from the
171      * block list
172      *
173      * @param startBlock the first block in the chain
174      * @param blockList the raw data block list
175      *
176      * @return array of ListManagedBlocks, in their correct order
177      *
178      * @exception IOException if there is a problem acquiring the blocks
179      */

180
181     ListManagedBlock [] fetchBlocks(final int startBlock,
182                                     final BlockList blockList)
183         throws IOException JavaDoc
184     {
185         List blocks = new ArrayList();
186         int currentBlock = startBlock;
187
188         while (currentBlock != POIFSConstants.END_OF_CHAIN)
189         {
190             blocks.add(blockList.remove(currentBlock));
191             currentBlock = _entries.get(currentBlock);
192         }
193         return ( ListManagedBlock [] ) blocks
194             .toArray(new ListManagedBlock[ 0 ]);
195     }
196
197     // methods for debugging reader
198

199     /**
200      * determine whether the block specified by index is used or not
201      *
202      * @param index index of block in question
203      *
204      * @return true if the specific block is used, else false
205      */

206
207     boolean isUsed(final int index)
208     {
209         boolean rval = false;
210
211         try
212         {
213             rval = _entries.get(index) != -1;
214         }
215         catch (IndexOutOfBoundsException JavaDoc ignored)
216         {
217         }
218         return rval;
219     }
220
221     /**
222      * return the next block index
223      *
224      * @param index of the current block
225      *
226      * @return index of the next block (may be
227      * POIFSConstants.END_OF_CHAIN, indicating end of chain
228      * (duh))
229      *
230      * @exception IOException if the current block is unused
231      */

232
233     int getNextBlockIndex(final int index)
234         throws IOException JavaDoc
235     {
236         if (isUsed(index))
237         {
238             return _entries.get(index);
239         }
240         else
241         {
242             throw new IOException JavaDoc("index " + index + " is unused");
243         }
244     }
245
246     /**
247      * Convert an array of blocks into a set of integer indices
248      *
249      * @param blocks the array of blocks containing the indices
250      * @param raw_blocks the list of blocks being managed. Unused
251      * blocks will be eliminated from the list
252      *
253      * @exception IOException
254      */

255
256     private void setEntries(final ListManagedBlock [] blocks,
257                             final BlockList raw_blocks)
258         throws IOException JavaDoc
259     {
260         int limit = BATBlock.entriesPerBlock();
261
262         for (int block_index = 0; block_index < blocks.length; block_index++)
263         {
264             byte[] data = blocks[ block_index ].getData();
265             int offset = 0;
266
267             for (int k = 0; k < limit; k++)
268             {
269                 int entry = LittleEndian.getInt(data, offset);
270
271                 if (entry == POIFSConstants.UNUSED_BLOCK)
272                 {
273                     raw_blocks.zap(_entries.size());
274                 }
275                 _entries.add(entry);
276                 offset += LittleEndianConsts.INT_SIZE;
277             }
278
279             // discard block
280
blocks[ block_index ] = null;
281         }
282         raw_blocks.setBAT(this);
283     }
284 } // end class BlockAllocationTableReader
285

286
Popular Tags