001: /* ====================================================================
002: Licensed to the Apache Software Foundation (ASF) under one or more
003: contributor license agreements. See the NOTICE file distributed with
004: this work for additional information regarding copyright ownership.
005: The ASF licenses this file to You under the Apache License, Version 2.0
006: (the "License"); you may not use this file except in compliance with
007: the License. You may obtain a copy of the License at
008:
009: http://www.apache.org/licenses/LICENSE-2.0
010:
011: Unless required by applicable law or agreed to in writing, software
012: distributed under the License is distributed on an "AS IS" BASIS,
013: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: See the License for the specific language governing permissions and
015: limitations under the License.
016: ==================================================================== */
017:
018: package org.apache.poi.poifs.storage;
019:
020: import java.io.IOException;
021: import java.io.OutputStream;
022:
023: import java.util.Arrays;
024:
025: import org.apache.poi.poifs.common.POIFSConstants;
026: import org.apache.poi.util.IntegerField;
027: import org.apache.poi.util.LittleEndian;
028: import org.apache.poi.util.LittleEndianConsts;
029:
030: /**
031: * A block of block allocation table entries. BATBlocks are created
032: * only through a static factory method: createBATBlocks.
033: *
034: * @author Marc Johnson (mjohnson at apache dot org)
035: */
036:
037: public class BATBlock extends BigBlock {
038: private static final int _entries_per_block = POIFSConstants.BIG_BLOCK_SIZE
039: / LittleEndianConsts.INT_SIZE;
040: private static final int _entries_per_xbat_block = _entries_per_block - 1;
041: private static final int _xbat_chain_offset = _entries_per_xbat_block
042: * LittleEndianConsts.INT_SIZE;
043: private static final byte _default_value = (byte) 0xFF;
044: private IntegerField[] _fields;
045: private byte[] _data;
046:
047: /**
048: * Create a single instance initialized with default values
049: */
050:
051: private BATBlock() {
052: _data = new byte[POIFSConstants.BIG_BLOCK_SIZE];
053: Arrays.fill(_data, _default_value);
054: _fields = new IntegerField[_entries_per_block];
055: int offset = 0;
056:
057: for (int j = 0; j < _entries_per_block; j++) {
058: _fields[j] = new IntegerField(offset);
059: offset += LittleEndianConsts.INT_SIZE;
060: }
061: }
062:
063: /**
064: * Create an array of BATBlocks from an array of int block
065: * allocation table entries
066: *
067: * @param entries the array of int entries
068: *
069: * @return the newly created array of BATBlocks
070: */
071:
072: public static BATBlock[] createBATBlocks(final int[] entries) {
073: int block_count = calculateStorageRequirements(entries.length);
074: BATBlock[] blocks = new BATBlock[block_count];
075: int index = 0;
076: int remaining = entries.length;
077:
078: for (int j = 0; j < entries.length; j += _entries_per_block) {
079: blocks[index++] = new BATBlock(entries, j,
080: (remaining > _entries_per_block) ? j
081: + _entries_per_block : entries.length);
082: remaining -= _entries_per_block;
083: }
084: return blocks;
085: }
086:
087: /**
088: * Create an array of XBATBlocks from an array of int block
089: * allocation table entries
090: *
091: * @param entries the array of int entries
092: * @param startBlock the start block of the array of XBAT blocks
093: *
094: * @return the newly created array of BATBlocks
095: */
096:
097: public static BATBlock[] createXBATBlocks(final int[] entries,
098: final int startBlock) {
099: int block_count = calculateXBATStorageRequirements(entries.length);
100: BATBlock[] blocks = new BATBlock[block_count];
101: int index = 0;
102: int remaining = entries.length;
103:
104: if (block_count != 0) {
105: for (int j = 0; j < entries.length; j += _entries_per_xbat_block) {
106: blocks[index++] = new BATBlock(entries, j,
107: (remaining > _entries_per_xbat_block) ? j
108: + _entries_per_xbat_block
109: : entries.length);
110: remaining -= _entries_per_xbat_block;
111: }
112: for (index = 0; index < blocks.length - 1; index++) {
113: blocks[index].setXBATChain(startBlock + index + 1);
114: }
115: blocks[index].setXBATChain(POIFSConstants.END_OF_CHAIN);
116: }
117: return blocks;
118: }
119:
120: /**
121: * Calculate how many BATBlocks are needed to hold a specified
122: * number of BAT entries.
123: *
124: * @param entryCount the number of entries
125: *
126: * @return the number of BATBlocks needed
127: */
128:
129: public static int calculateStorageRequirements(final int entryCount) {
130: return (entryCount + _entries_per_block - 1)
131: / _entries_per_block;
132: }
133:
134: /**
135: * Calculate how many XBATBlocks are needed to hold a specified
136: * number of BAT entries.
137: *
138: * @param entryCount the number of entries
139: *
140: * @return the number of XBATBlocks needed
141: */
142:
143: public static int calculateXBATStorageRequirements(
144: final int entryCount) {
145: return (entryCount + _entries_per_xbat_block - 1)
146: / _entries_per_xbat_block;
147: }
148:
149: /**
150: * @return number of entries per block
151: */
152:
153: public static final int entriesPerBlock() {
154: return _entries_per_block;
155: }
156:
157: /**
158: * @return number of entries per XBAT block
159: */
160:
161: public static final int entriesPerXBATBlock() {
162: return _entries_per_xbat_block;
163: }
164:
165: /**
166: * @return offset of chain index of XBAT block
167: */
168:
169: public static final int getXBATChainOffset() {
170: return _xbat_chain_offset;
171: }
172:
173: private void setXBATChain(int chainIndex) {
174: _fields[_entries_per_xbat_block].set(chainIndex, _data);
175: }
176:
177: /**
178: * Create a single instance initialized (perhaps partially) with entries
179: *
180: * @param entries the array of block allocation table entries
181: * @param start_index the index of the first entry to be written
182: * to the block
183: * @param end_index the index, plus one, of the last entry to be
184: * written to the block (writing is for all index
185: * k, start_index <= k < end_index)
186: */
187:
188: private BATBlock(final int[] entries, final int start_index,
189: final int end_index) {
190: this ();
191: for (int k = start_index; k < end_index; k++) {
192: _fields[k - start_index].set(entries[k], _data);
193: }
194: }
195:
196: /* ********** START extension of BigBlock ********** */
197:
198: /**
199: * Write the block's data to an OutputStream
200: *
201: * @param stream the OutputStream to which the stored data should
202: * be written
203: *
204: * @exception IOException on problems writing to the specified
205: * stream
206: */
207:
208: void writeData(final OutputStream stream) throws IOException {
209: doWriteData(stream, _data);
210: }
211:
212: /* ********** END extension of BigBlock ********** */
213: } // end public class BATBlock
|