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