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.*;
021:
022: import java.util.*;
023:
024: import org.apache.poi.poifs.common.POIFSConstants;
025: import org.apache.poi.util.IntegerField;
026: import org.apache.poi.util.LittleEndianConsts;
027: import org.apache.poi.util.LongField;
028: import org.apache.poi.util.ShortField;
029:
030: /**
031: * The block containing the archive header
032: *
033: * @author Marc Johnson (mjohnson at apache dot org)
034: */
035:
036: public class HeaderBlockWriter extends BigBlock implements
037: HeaderBlockConstants {
038: private static final byte _default_value = (byte) 0xFF;
039:
040: // number of big block allocation table blocks (int)
041: private IntegerField _bat_count;
042:
043: // start of the property set block (int index of the property set
044: // chain's first big block)
045: private IntegerField _property_start;
046:
047: // start of the small block allocation table (int index of small
048: // block allocation table's first big block)
049: private IntegerField _sbat_start;
050:
051: // number of big blocks holding the small block allocation table
052: private IntegerField _sbat_block_count;
053:
054: // big block index for extension to the big block allocation table
055: private IntegerField _xbat_start;
056: private IntegerField _xbat_count;
057: private byte[] _data;
058:
059: /**
060: * Create a single instance initialized with default values
061: */
062:
063: public HeaderBlockWriter() {
064: _data = new byte[POIFSConstants.BIG_BLOCK_SIZE];
065: Arrays.fill(_data, _default_value);
066: new LongField(_signature_offset, _signature, _data);
067: new IntegerField(0x08, 0, _data);
068: new IntegerField(0x0c, 0, _data);
069: new IntegerField(0x10, 0, _data);
070: new IntegerField(0x14, 0, _data);
071: new ShortField(0x18, (short) 0x3b, _data);
072: new ShortField(0x1a, (short) 0x3, _data);
073: new ShortField(0x1c, (short) -2, _data);
074: new ShortField(0x1e, (short) 0x9, _data);
075: new IntegerField(0x20, 0x6, _data);
076: new IntegerField(0x24, 0, _data);
077: new IntegerField(0x28, 0, _data);
078: _bat_count = new IntegerField(_bat_count_offset, 0, _data);
079: _property_start = new IntegerField(_property_start_offset,
080: POIFSConstants.END_OF_CHAIN, _data);
081: new IntegerField(0x34, 0, _data);
082: new IntegerField(0x38, 0x1000, _data);
083: _sbat_start = new IntegerField(_sbat_start_offset,
084: POIFSConstants.END_OF_CHAIN, _data);
085: _sbat_block_count = new IntegerField(_sbat_block_count_offset,
086: 0, _data);
087: _xbat_start = new IntegerField(_xbat_start_offset,
088: POIFSConstants.END_OF_CHAIN, _data);
089: _xbat_count = new IntegerField(_xbat_count_offset, 0, _data);
090: }
091:
092: /**
093: * Set BAT block parameters. Assumes that all BAT blocks are
094: * contiguous. Will construct XBAT blocks if necessary and return
095: * the array of newly constructed XBAT blocks.
096: *
097: * @param blockCount count of BAT blocks
098: * @param startBlock index of first BAT block
099: *
100: * @return array of XBAT blocks; may be zero length, will not be
101: * null
102: */
103:
104: public BATBlock[] setBATBlocks(final int blockCount,
105: final int startBlock) {
106: BATBlock[] rvalue;
107:
108: _bat_count.set(blockCount, _data);
109: int limit = Math.min(blockCount, _max_bats_in_header);
110: int offset = _bat_array_offset;
111:
112: for (int j = 0; j < limit; j++) {
113: new IntegerField(offset, startBlock + j, _data);
114: offset += LittleEndianConsts.INT_SIZE;
115: }
116: if (blockCount > _max_bats_in_header) {
117: int excess_blocks = blockCount - _max_bats_in_header;
118: int[] excess_block_array = new int[excess_blocks];
119:
120: for (int j = 0; j < excess_blocks; j++) {
121: excess_block_array[j] = startBlock + j
122: + _max_bats_in_header;
123: }
124: rvalue = BATBlock.createXBATBlocks(excess_block_array,
125: startBlock + blockCount);
126: _xbat_start.set(startBlock + blockCount, _data);
127: } else {
128: rvalue = BATBlock.createXBATBlocks(new int[0], 0);
129: _xbat_start.set(POIFSConstants.END_OF_CHAIN, _data);
130: }
131: _xbat_count.set(rvalue.length, _data);
132: return rvalue;
133: }
134:
135: /**
136: * Set start of Property Table
137: *
138: * @param startBlock the index of the first block of the Property
139: * Table
140: */
141:
142: public void setPropertyStart(final int startBlock) {
143: _property_start.set(startBlock, _data);
144: }
145:
146: /**
147: * Set start of small block allocation table
148: *
149: * @param startBlock the index of the first big block of the small
150: * block allocation table
151: */
152:
153: public void setSBATStart(final int startBlock) {
154: _sbat_start.set(startBlock, _data);
155: }
156:
157: /**
158: * Set count of SBAT blocks
159: *
160: * @param count the number of SBAT blocks
161: */
162:
163: public void setSBATBlockCount(final int count) {
164: _sbat_block_count.set(count, _data);
165: }
166:
167: /**
168: * For a given number of BAT blocks, calculate how many XBAT
169: * blocks will be needed
170: *
171: * @param blockCount number of BAT blocks
172: *
173: * @return number of XBAT blocks needed
174: */
175:
176: static int calculateXBATStorageRequirements(final int blockCount) {
177: return (blockCount > _max_bats_in_header) ? BATBlock
178: .calculateXBATStorageRequirements(blockCount
179: - _max_bats_in_header) : 0;
180: }
181:
182: /* ********** START extension of BigBlock ********** */
183:
184: /**
185: * Write the block's data to an OutputStream
186: *
187: * @param stream the OutputStream to which the stored data should
188: * be written
189: *
190: * @exception IOException on problems writing to the specified
191: * stream
192: */
193:
194: void writeData(final OutputStream stream) throws IOException {
195: doWriteData(stream, _data);
196: }
197:
198: /* ********** END extension of BigBlock ********** */
199: } // end public class HeaderBlockWriter
|