1    
2    /* ====================================================================
3     * The Apache Software License, Version 1.1
4     *
5     * Copyright (c) 2002 The Apache Software Foundation.  All rights
6     * reserved.
7     *
8     * Redistribution and use in source and binary forms, with or without
9     * modification, are permitted provided that the following conditions
10    * are met:
11    *
12    * 1. Redistributions of source code must retain the above copyright
13    *    notice, this list of conditions and the following disclaimer.
14    *
15    * 2. Redistributions in binary form must reproduce the above copyright
16    *    notice, this list of conditions and the following disclaimer in
17    *    the documentation and/or other materials provided with the
18    *    distribution.
19    *
20    * 3. The end-user documentation included with the redistribution,
21    *    if any, must include the following acknowledgment:
22    *       "This product includes software developed by the
23    *        Apache Software Foundation (http://www.apache.org/)."
24    *    Alternately, this acknowledgment may appear in the software itself,
25    *    if and wherever such third-party acknowledgments normally appear.
26    *
27    * 4. The names "Apache" and "Apache Software Foundation" and
28    *    "Apache POI" must not be used to endorse or promote products
29    *    derived from this software without prior written permission. For
30    *    written permission, please contact apache@apache.org.
31    *
32    * 5. Products derived from this software may not be called "Apache",
33    *    "Apache POI", nor may "Apache" appear in their name, without
34    *    prior written permission of the Apache Software Foundation.
35    *
36    * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37    * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38    * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39    * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
40    * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41    * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42    * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43    * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44    * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45    * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46    * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47    * SUCH DAMAGE.
48    * ====================================================================
49    *
50    * This software consists of voluntary contributions made by many
51    * individuals on behalf of the Apache Software Foundation.  For more
52    * information on the Apache Software Foundation, please see
53    * <http://www.apache.org/>.
54    */
55   
56   package org.apache.poi.poifs.storage;
57   
58   import java.io.IOException;
59   import java.io.OutputStream;
60   
61   import java.util.Arrays;
62   
63   import org.apache.poi.poifs.common.POIFSConstants;
64   import org.apache.poi.util.IntegerField;
65   import org.apache.poi.util.LittleEndian;
66   import org.apache.poi.util.LittleEndianConsts;
67   
68   /**
69    * A block of block allocation table entries. BATBlocks are created
70    * only through a static factory method: createBATBlocks.
71    *
72    * @author Marc Johnson (mjohnson at apache dot org)
73    */
74   
75   public class BATBlock
76       extends BigBlock
77   {
78       private static final int  _entries_per_block      =
79           POIFSConstants.BIG_BLOCK_SIZE / LittleEndianConsts.INT_SIZE;
80       private static final int  _entries_per_xbat_block = _entries_per_block
81                                                               - 1;
82       private static final int  _xbat_chain_offset      =
83           _entries_per_xbat_block * LittleEndianConsts.INT_SIZE;
84       private static final byte _default_value          = ( byte ) 0xFF;
85       private IntegerField[]    _fields;
86       private byte[]            _data;
87   
88       /**
89        * Create a single instance initialized with default values
90        */
91   
92       private BATBlock()
93       {
94           _data = new byte[ POIFSConstants.BIG_BLOCK_SIZE ];
95           Arrays.fill(_data, _default_value);
96           _fields = new IntegerField[ _entries_per_block ];
97           int offset = 0;
98   
99           for (int j = 0; j < _entries_per_block; j++)
100          {
101              _fields[ j ] = new IntegerField(offset);
102              offset       += LittleEndianConsts.INT_SIZE;
103          }
104      }
105  
106      /**
107       * Create an array of BATBlocks from an array of int block
108       * allocation table entries
109       *
110       * @param entries the array of int entries
111       *
112       * @return the newly created array of BATBlocks
113       */
114  
115      public static BATBlock [] createBATBlocks(final int [] entries)
116      {
117          int        block_count = calculateStorageRequirements(entries.length);
118          BATBlock[] blocks      = new BATBlock[ block_count ];
119          int        index       = 0;
120          int        remaining   = entries.length;
121  
122          for (int j = 0; j < entries.length; j += _entries_per_block)
123          {
124              blocks[ index++ ] = new BATBlock(entries, j,
125                                               (remaining > _entries_per_block)
126                                               ? j + _entries_per_block
127                                               : entries.length);
128              remaining         -= _entries_per_block;
129          }
130          return blocks;
131      }
132  
133      /**
134       * Create an array of XBATBlocks from an array of int block
135       * allocation table entries
136       *
137       * @param entries the array of int entries
138       * @param startBlock the start block of the array of XBAT blocks
139       *
140       * @return the newly created array of BATBlocks
141       */
142  
143      public static BATBlock [] createXBATBlocks(final int [] entries,
144                                                 final int startBlock)
145      {
146          int        block_count =
147              calculateXBATStorageRequirements(entries.length);
148          BATBlock[] blocks      = new BATBlock[ block_count ];
149          int        index       = 0;
150          int        remaining   = entries.length;
151  
152          if (block_count != 0)
153          {
154              for (int j = 0; j < entries.length; j += _entries_per_xbat_block)
155              {
156                  blocks[ index++ ] =
157                      new BATBlock(entries, j,
158                                   (remaining > _entries_per_xbat_block)
159                                   ? j + _entries_per_xbat_block
160                                   : entries.length);
161                  remaining         -= _entries_per_xbat_block;
162              }
163              for (index = 0; index < blocks.length - 1; index++)
164              {
165                  blocks[ index ].setXBATChain(startBlock + index + 1);
166              }
167              blocks[ index ].setXBATChain(POIFSConstants.END_OF_CHAIN);
168          }
169          return blocks;
170      }
171  
172      /**
173       * Calculate how many BATBlocks are needed to hold a specified
174       * number of BAT entries.
175       *
176       * @param entryCount the number of entries
177       *
178       * @return the number of BATBlocks needed
179       */
180  
181      public static int calculateStorageRequirements(final int entryCount)
182      {
183          return (entryCount + _entries_per_block - 1) / _entries_per_block;
184      }
185  
186      /**
187       * Calculate how many XBATBlocks are needed to hold a specified
188       * number of BAT entries.
189       *
190       * @param entryCount the number of entries
191       *
192       * @return the number of XBATBlocks needed
193       */
194  
195      public static int calculateXBATStorageRequirements(final int entryCount)
196      {
197          return (entryCount + _entries_per_xbat_block - 1)
198                 / _entries_per_xbat_block;
199      }
200  
201      /**
202       * @return number of entries per block
203       */
204  
205      public static final int entriesPerBlock()
206      {
207          return _entries_per_block;
208      }
209  
210      /**
211       * @return number of entries per XBAT block
212       */
213  
214      public static final int entriesPerXBATBlock()
215      {
216          return _entries_per_xbat_block;
217      }
218  
219      /**
220       * @return offset of chain index of XBAT block
221       */
222  
223      public static final int getXBATChainOffset()
224      {
225          return _xbat_chain_offset;
226      }
227  
228      private void setXBATChain(int chainIndex)
229      {
230          _fields[ _entries_per_xbat_block ].set(chainIndex, _data);
231      }
232  
233      /**
234       * Create a single instance initialized (perhaps partially) with entries
235       *
236       * @param entries the array of block allocation table entries
237       * @param start_index the index of the first entry to be written
238       *                    to the block
239       * @param end_index the index, plus one, of the last entry to be
240       *                  written to the block (writing is for all index
241       *                  k, start_index <= k < end_index)
242       */
243  
244      private BATBlock(final int [] entries, final int start_index,
245                       final int end_index)
246      {
247          this();
248          for (int k = start_index; k < end_index; k++)
249          {
250              _fields[ k - start_index ].set(entries[ k ], _data);
251          }
252      }
253  
254      /* ********** START extension of BigBlock ********** */
255  
256      /**
257       * Write the block's data to an OutputStream
258       *
259       * @param stream the OutputStream to which the stored data should
260       *               be written
261       *
262       * @exception IOException on problems writing to the specified
263       *            stream
264       */
265  
266      void writeData(final OutputStream stream)
267          throws IOException
268      {
269          doWriteData(stream, _data);
270      }
271  
272      /* **********  END  extension of BigBlock ********** */
273  }   // end public class BATBlock
274  
275