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.*;
024:
025: import org.apache.poi.poifs.common.POIFSConstants;
026: import org.apache.poi.poifs.filesystem.BATManaged;
027: import org.apache.poi.util.IntList;
028: import org.apache.poi.util.LittleEndian;
029: import org.apache.poi.util.LittleEndianConsts;
030:
031: /**
032: * This class manages and creates the Block Allocation Table, which is
033: * basically a set of linked lists of block indices.
034: * <P>
035: * Each block of the filesystem has an index. The first block, the
036: * header, is skipped; the first block after the header is index 0,
037: * the next is index 1, and so on.
038: * <P>
039: * A block's index is also its index into the Block Allocation
040: * Table. The entry that it finds in the Block Allocation Table is the
041: * index of the next block in the linked list of blocks making up a
042: * file, or it is set to -2: end of list.
043: *
044: * @author Marc Johnson (mjohnson at apache dot org)
045: */
046:
047: public class BlockAllocationTableWriter implements BlockWritable,
048: BATManaged {
049: private IntList _entries;
050: private BATBlock[] _blocks;
051: private int _start_block;
052:
053: /**
054: * create a BlockAllocationTableWriter
055: */
056:
057: public BlockAllocationTableWriter() {
058: _start_block = POIFSConstants.END_OF_CHAIN;
059: _entries = new IntList();
060: _blocks = new BATBlock[0];
061: }
062:
063: /**
064: * Create the BATBlocks we need
065: *
066: * @return start block index of BAT blocks
067: */
068:
069: public int createBlocks() {
070: int xbat_blocks = 0;
071: int bat_blocks = 0;
072:
073: while (true) {
074: int calculated_bat_blocks = BATBlock
075: .calculateStorageRequirements(bat_blocks
076: + xbat_blocks + _entries.size());
077: int calculated_xbat_blocks = HeaderBlockWriter
078: .calculateXBATStorageRequirements(calculated_bat_blocks);
079:
080: if ((bat_blocks == calculated_bat_blocks)
081: && (xbat_blocks == calculated_xbat_blocks)) {
082:
083: // stable ... we're OK
084: break;
085: } else {
086: bat_blocks = calculated_bat_blocks;
087: xbat_blocks = calculated_xbat_blocks;
088: }
089: }
090: int startBlock = allocateSpace(bat_blocks);
091:
092: allocateSpace(xbat_blocks);
093: simpleCreateBlocks();
094: return startBlock;
095: }
096:
097: /**
098: * Allocate space for a block of indices
099: *
100: * @param blockCount the number of blocks to allocate space for
101: *
102: * @return the starting index of the blocks
103: */
104:
105: public int allocateSpace(final int blockCount) {
106: int startBlock = _entries.size();
107:
108: if (blockCount > 0) {
109: int limit = blockCount - 1;
110: int index = startBlock + 1;
111:
112: for (int k = 0; k < limit; k++) {
113: _entries.add(index++);
114: }
115: _entries.add(POIFSConstants.END_OF_CHAIN);
116: }
117: return startBlock;
118: }
119:
120: /**
121: * get the starting block
122: *
123: * @return the starting block index
124: */
125:
126: public int getStartBlock() {
127: return _start_block;
128: }
129:
130: /**
131: * create the BATBlocks
132: */
133:
134: void simpleCreateBlocks() {
135: _blocks = BATBlock.createBATBlocks(_entries.toArray());
136: }
137:
138: /* ********** START implementation of BlockWritable ********** */
139:
140: /**
141: * Write the storage to an OutputStream
142: *
143: * @param stream the OutputStream to which the stored data should
144: * be written
145: *
146: * @exception IOException on problems writing to the specified
147: * stream
148: */
149:
150: public void writeBlocks(final OutputStream stream)
151: throws IOException {
152: for (int j = 0; j < _blocks.length; j++) {
153: _blocks[j].writeBlocks(stream);
154: }
155: }
156:
157: /* ********** END implementation of BlockWritable ********** */
158: /* ********** START implementation of BATManaged ********** */
159:
160: /**
161: * Return the number of BigBlock's this instance uses
162: *
163: * @return count of BigBlock instances
164: */
165:
166: public int countBlocks() {
167: return _blocks.length;
168: }
169:
170: /**
171: * Set the start block for this instance
172: *
173: * @param start_block
174: */
175:
176: public void setStartBlock(int start_block) {
177: _start_block = start_block;
178: }
179:
180: /* ********** END implementation of BATManaged ********** */
181: } // end class BlockAllocationTableWriter
|