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.*;
62   
63   import org.apache.poi.poifs.common.POIFSConstants;
64   import org.apache.poi.poifs.filesystem.BATManaged;
65   import org.apache.poi.util.IntList;
66   import org.apache.poi.util.LittleEndian;
67   import org.apache.poi.util.LittleEndianConsts;
68   
69   /**
70    * This class manages and creates the Block Allocation Table, which is
71    * basically a set of linked lists of block indices.
72    * <P>
73    * Each block of the filesystem has an index. The first block, the
74    * header, is skipped; the first block after the header is index 0,
75    * the next is index 1, and so on.
76    * <P>
77    * A block's index is also its index into the Block Allocation
78    * Table. The entry that it finds in the Block Allocation Table is the
79    * index of the next block in the linked list of blocks making up a
80    * file, or it is set to -2: end of list.
81    *
82    * @author Marc Johnson (mjohnson at apache dot org)
83    */
84   
85   public class BlockAllocationTableWriter
86       implements BlockWritable, BATManaged
87   {
88       private IntList    _entries;
89       private BATBlock[] _blocks;
90       private int        _start_block;
91   
92       /**
93        * create a BlockAllocationTableWriter
94        */
95   
96       public BlockAllocationTableWriter()
97       {
98           _start_block = POIFSConstants.END_OF_CHAIN;
99           _entries     = new IntList();
100          _blocks      = new BATBlock[ 0 ];
101      }
102  
103      /**
104       * Create the BATBlocks we need
105       *
106       * @return start block index of BAT blocks
107       */
108  
109      public int createBlocks()
110      {
111          int xbat_blocks = 0;
112          int bat_blocks  = 0;
113  
114          while (true)
115          {
116              int calculated_bat_blocks  =
117                  BATBlock.calculateStorageRequirements(bat_blocks
118                                                        + xbat_blocks
119                                                        + _entries.size());
120              int calculated_xbat_blocks =
121                  HeaderBlockWriter
122                      .calculateXBATStorageRequirements(calculated_bat_blocks);
123  
124              if ((bat_blocks == calculated_bat_blocks)
125                      && (xbat_blocks == calculated_xbat_blocks))
126              {
127  
128                  // stable ... we're OK
129                  break;
130              }
131              else
132              {
133                  bat_blocks  = calculated_bat_blocks;
134                  xbat_blocks = calculated_xbat_blocks;
135              }
136          }
137          int startBlock = allocateSpace(bat_blocks);
138  
139          allocateSpace(xbat_blocks);
140          simpleCreateBlocks();
141          return startBlock;
142      }
143  
144      /**
145       * Allocate space for a block of indices
146       *
147       * @param blockCount the number of blocks to allocate space for
148       *
149       * @return the starting index of the blocks
150       */
151  
152      public int allocateSpace(final int blockCount)
153      {
154          int startBlock = _entries.size();
155  
156          if (blockCount > 0)
157          {
158              int limit = blockCount - 1;
159              int index = startBlock + 1;
160  
161              for (int k = 0; k < limit; k++)
162              {
163                  _entries.add(index++);
164              }
165              _entries.add(POIFSConstants.END_OF_CHAIN);
166          }
167          return startBlock;
168      }
169  
170      /**
171       * get the starting block
172       *
173       * @return the starting block index
174       */
175  
176      public int getStartBlock()
177      {
178          return _start_block;
179      }
180  
181      /**
182       * create the BATBlocks
183       */
184  
185      void simpleCreateBlocks()
186      {
187          _blocks = BATBlock.createBATBlocks(_entries.toArray());
188      }
189  
190      /* ********** START implementation of BlockWritable ********** */
191  
192      /**
193       * Write the storage to an OutputStream
194       *
195       * @param stream the OutputStream to which the stored data should
196       *               be written
197       *
198       * @exception IOException on problems writing to the specified
199       *            stream
200       */
201  
202      public void writeBlocks(final OutputStream stream)
203          throws IOException
204      {
205          for (int j = 0; j < _blocks.length; j++)
206          {
207              _blocks[ j ].writeBlocks(stream);
208          }
209      }
210  
211      /* **********  END  implementation of BlockWritable ********** */
212      /* ********** START implementation of BATManaged ********** */
213  
214      /**
215       * Return the number of BigBlock's this instance uses
216       *
217       * @return count of BigBlock instances
218       */
219  
220      public int countBlocks()
221      {
222          return _blocks.length;
223      }
224  
225      /**
226       * Set the start block for this instance
227       *
228       * @param index index into the array of BigBlock instances making
229       *              up the the filesystem
230       *
231       * @param start_block
232       */
233  
234      public void setStartBlock(int start_block)
235      {
236          _start_block = start_block;
237      }
238  
239      /* **********  END  implementation of BATManaged ********** */
240  }   // end class BlockAllocationTableWriter
241  
242