📄 compoundfile.java3
字号:
*/
private void writeHeader() throws IOException
{
logger.debug("num extensions blocks for header: " + numExtensionBlocks);
// Build up the header array
byte[] headerBlock = new byte[BIG_BLOCK_SIZE];
byte[] extensionBlockData = new byte[BIG_BLOCK_SIZE * numExtensionBlocks];
// Copy in the identifier
System.arraycopy(IDENTIFIER, 0, headerBlock, 0, IDENTIFIER.length);
// Copy in some magic values - no idea what they mean
headerBlock[0x18] = 0x3e;
headerBlock[0x1a] = 0x3;
headerBlock[0x1c] = (byte) 0xfe;
headerBlock[0x1d] = (byte) 0xff;
headerBlock[0x1e] = 0x9;
headerBlock[0x20] = 0x6;
headerBlock[0x39] = 0x10;
// Set the number of BBD blocks
IntegerHelper.getFourBytes(numBigBlockDepotBlocks,
headerBlock,
NUM_BIG_BLOCK_DEPOT_BLOCKS_POS);
// Set the small block depot chain to -2 ie. no small block chain
IntegerHelper.getFourBytes(-2,
headerBlock,
SMALL_BLOCK_DEPOT_BLOCK_POS);
// Set the extension block
IntegerHelper.getFourBytes(extensionBlock,
headerBlock,
EXTENSION_BLOCK_POS);
// Set the number of extension blocks to be the number of BBD blocks - 1
IntegerHelper.getFourBytes(numExtensionBlocks,
headerBlock,
NUM_EXTENSION_BLOCK_POS);
// Set the root start block
IntegerHelper.getFourBytes(rootStartBlock,
headerBlock,
ROOT_START_BLOCK_POS);
// Set the block numbers for the BBD. Set the BBD running
// after the excel data and summary information
int pos = BIG_BLOCK_DEPOT_BLOCKS_POS;
// See how many blocks fit into the header
int blocksToWrite = Math.min(numBigBlockDepotBlocks,
(BIG_BLOCK_SIZE -
BIG_BLOCK_DEPOT_BLOCKS_POS)/4);
int extensionBlock = 0;
int blocksWritten = 0;
for (int i = 0 ; i < blocksToWrite; i++)
{
IntegerHelper.getFourBytes(bbdStartBlock + i,
headerBlock,
pos);
pos += 4;
blocksWritten++;
}
// Pad out the rest of the header with blanks
for (int i = pos; i < BIG_BLOCK_SIZE; i++)
{
headerBlock[i] = (byte) 0xff;
}
out.write(headerBlock);
// Write out the extension blocks
pos = 0;
for (int extBlock = 0; extBlock < numExtensionBlocks; extBlock++)
{
blocksToWrite = Math.min(numBigBlockDepotBlocks - blocksWritten,
BIG_BLOCK_SIZE/4 -1);
for(int j = 0 ; j < blocksToWrite; j++)
{
IntegerHelper.getFourBytes(bbdStartBlock + blocksWritten + j,
extensionBlockData,
pos);
pos += 4;
}
blocksWritten += blocksToWrite;
// Indicate the next block, or the termination of the chain
int nextBlock = (blocksWritten == numBigBlockDepotBlocks) ?
-2 : extBlock+1 ;
IntegerHelper.getFourBytes(nextBlock, extensionBlockData, pos);
pos +=4;
}
if (numExtensionBlocks > 0)
{
// Pad out the rest of the extension block with blanks
for (int i = pos; i < extensionBlockData.length; i++)
{
extensionBlockData[i] = (byte) 0xff;
}
out.write(extensionBlockData);
}
}
/**
* Checks that the data can fit into the current BBD block. If not,
* then it moves on to the next block
*
* @exception IOException
*/
private void checkBbdPos() throws IOException
{
if (bbdPos >= BIG_BLOCK_SIZE)
{
// Write out the extension block. This will simply be the next block
out.write(bigBlockDepot);
// Create a new block
bigBlockDepot = new byte[BIG_BLOCK_SIZE];
bbdPos = 0;
}
}
/**
* Writes out the big block chain
*
* @param startBlock the starting block of the big block chain
* @param numBlocks the number of blocks in the chain
* @exception IOException
*/
private void writeBlockChain(int startBlock, int numBlocks)
throws IOException
{
int blocksToWrite = numBlocks - 1;
int blockNumber = startBlock + 1;
while (blocksToWrite > 0)
{
int bbdBlocks = Math.min(blocksToWrite, (BIG_BLOCK_SIZE - bbdPos)/4);
for (int i = 0 ; i < bbdBlocks; i++)
{
IntegerHelper.getFourBytes(blockNumber, bigBlockDepot, bbdPos);
bbdPos +=4 ;
blockNumber++;
}
blocksToWrite -= bbdBlocks;
checkBbdPos();
}
// Write the end of the block chain
IntegerHelper.getFourBytes(-2, bigBlockDepot, bbdPos);
bbdPos += 4;
checkBbdPos();
}
/**
* Writes the block chains for the additional property sets
*
* @exception IOException
*/
private void writeAdditionalPropertySetBlockChains() throws IOException
{
if (additionalPropertySets == null)
{
return;
}
int blockNumber = excelDataStartBlock + excelDataBlocks + 16;
int numBlocks2 = rootEntryPropertySet.data.length >= SMALL_BLOCK_THRESHOLD ?
getBigBlocksRequired(rootEntryPropertySet.data.length) :
SMALL_BLOCK_THRESHOLD / BIG_BLOCK_SIZE;
String psname2 = rootEntryPropertySet.propertyStorage.name;
logger.debug("writing big block chain for " + psname2 + " block " + blockNumber + " numBlocks " + numBlocks2);
writeBlockChain(blockNumber, numBlocks2);
blockNumber += numBlocks2;
for (Iterator i = additionalPropertySets.iterator(); i.hasNext() ; )
{
ReadPropertyStorage rps = (ReadPropertyStorage) i.next();
int numBlocks = rps.data.length >= SMALL_BLOCK_THRESHOLD ?
getBigBlocksRequired(rps.data.length) :
SMALL_BLOCK_THRESHOLD / BIG_BLOCK_SIZE;
String psname = rps.propertyStorage.name;
logger.debug("writing big block chain for " + psname + " block " + blockNumber + " numBlocks " + numBlocks);
writeBlockChain(blockNumber, numBlocks);
blockNumber += numBlocks;
}
}
/**
* Writes out the Big Block Depot
*
* @exception IOException
*/
private void writeBigBlockDepot() throws IOException
{
// This is after the excel data, the summary information, the
// big block property sets and the small block depot
bigBlockDepot = new byte[BIG_BLOCK_SIZE];
bbdPos = 0;
// Write out the extension blocks, indicating them as special blocks
for (int i = 0 ; i < numExtensionBlocks; i++)
{
IntegerHelper.getFourBytes(-3, bigBlockDepot, bbdPos);
bbdPos += 4;
checkBbdPos();
}
writeBlockChain(excelDataStartBlock, excelDataBlocks);
// The excel data has been written. Now write out the rest of it
// Write the block chain for the summary information
int summaryInfoBlock = excelDataStartBlock +
excelDataBlocks +
additionalPropertyBlocks;
for (int i = summaryInfoBlock; i < summaryInfoBlock + 7; i++)
{
IntegerHelper.getFourBytes(i + 1, bigBlockDepot, bbdPos);
bbdPos +=4 ;
checkBbdPos();
}
// Write the end of the block chain for the summary info block
IntegerHelper.getFourBytes(-2, bigBlockDepot, bbdPos);
bbdPos += 4;
checkBbdPos();
// Write the block chain for the document summary information
for (int i = summaryInfoBlock + 8; i < summaryInfoBlock + 15; i++)
{
IntegerHelper.getFourBytes(i + 1, bigBlockDepot, bbdPos);
bbdPos +=4 ;
checkBbdPos();
}
// Write the end of the block chain for the document summary
IntegerHelper.getFourBytes(-2, bigBlockDepot, bbdPos);
bbdPos += 4;
checkBbdPos();
// Write out the block chain for the copied property sets, if present
writeAdditionalPropertySetBlockChains();
// The Big Block Depot immediately follows the document summary. Denote
// these as a special block
for (int i = 0; i < numBigBlockDepotBlocks; i++)
{
IntegerHelper.getFourBytes(-3, bigBlockDepot, bbdPos);
bbdPos += 4;
checkBbdPos();
}
// Write the root entry
writeBlockChain(rootStartBlock, numRootEntryBlocks);
// Pad out the remainder of the block
if (bbdPos != 0)
{
for (int i = bbdPos; i < BIG_BLOCK_SIZE; i++)
{
bigBlockDepot[i] = (byte) 0xff;
}
out.write(bigBlockDepot);
}
}
/**
* Calculates the number of big blocks required to store data of the
* specified length
*
* @param length the length of the data
* @return the number of big blocks required to store the data
*/
private int getBigBlocksRequired(int length)
{
int blocks = length / BIG_BLOCK_SIZE;
return (length % BIG_BLOCK_SIZE > 0 )? blocks + 1 : blocks;
}
/**
* Calculates the number of small blocks required to store data of the
* specified length
*
* @param length the length of the data
* @return the number of small blocks required to store the data
*/
private int getSmallBlocksRequired(int length)
{
int blocks = length / SMALL_BLOCK_SIZE;
return (length % SMALL_BLOCK_SIZE > 0 )? blocks + 1 : blocks;
}
/**
* Writes out the property sets
*
* @exception IOException
*/
private void writePropertySets() throws IOException
{
byte[] propertySetStorage = new byte[BIG_BLOCK_SIZE * numRootEntryBlocks];
int pos = 0;
int[] mappings = null;
// Build up the mappings array
if (additionalPropertySets != null)
{
mappings = new int[numPropertySets];
// Map the standard ones to the first four
for (int i = 0 ; i < STANDARD_PROPERTY_SETS.length ; i++)
{
ReadPropertyStorage rps = (ReadPropertyStorage)
readPropertySets.get(STANDARD_PROPERTY_SETS[i]);
mappings[rps.number] = i;
}
// Now go through the original ones
int newMapping = STANDARD_PROPERTY_SETS.length;
for (Iterator i = additionalPropertySets.iterator(); i.hasNext(); )
{
ReadPropertyStorage rps = (ReadPropertyStorage) i.next();
mappings[rps.number] = newMapping;
newMapping++;
}
}
int dir = 0;
int previous = 0;
int next = 0;
// Set the root entry property set
PropertyStorage ps = new PropertyStorage(ROOT_ENTRY_NAME);
ps.setType(5);
ps.setStartBlock(-2);
ps.setSize(0);
ps.setPrevious(-1);
ps.setNext(-1);
ps.setColour(0);
dir = 2;
if (additionalPropertySets != null)
{
ReadPropertyStorage rps = (ReadPropertyStorage)
readPropertySets.get(ROOT_ENTRY_NAME);
dir = mappings[rps.propertyStorage.directory];
}
ps.setDirectory(dir);
System.arraycopy(ps.data, 0,
propertySetStorage, pos,
PROPERTY_STORAGE_BLOCK_SIZE);
pos += PROPERTY_STORAGE_BLOCK_SIZE;
// Set the workbook property set
ps = new PropertyStorage(WORKBOOK_NAME);
ps.setType(2);
ps.setStartBlock(excelDataStartBlock);
// start the excel data after immediately after this block
ps.setSize(requiredSize);
// alway use a big block stream - none of that messing around
// with small blocks
ps.setColour(1);
previous = 3;
if (additionalPropertySets != null)
{
ReadPropertyStorage rps = (ReadPropertyStorage)
readPropertySets.get(WORKBOOK_NAME);
previous = mappings[rps.propertyStorage.previous];
}
ps.setPrevious(previous);
ps.setNext(-1);
ps.setDirectory(-1);
ps.setColour(1);
System.arraycopy(ps.data, 0,
propertySetStorage, pos,
PROPERTY_STORAGE_BLOCK_SIZE);
pos += PROPERTY_STORAGE_BLOCK_SIZE;
// Set the summary information
ps = new PropertyStorage(SUMMARY_INFORMATION_NAME);
ps.setType(2);
ps.setStartBlock(excelDataStartBlock + excelDataBlocks);
ps.setSize(SMALL_BLOCK_THRESHOLD);
ps.setColour(1);
previous = 1;
next = 3;
if (additionalPropertySets != null)
{
ReadPropertyStorage rps = (ReadPropertyStorage)
readPropertySets.get(SUMMARY_INFORMATION_NAME);
previous = rps.propertyStorage.previous != - 1 ?
mappings[rps.propertyStorage.previous] : -1 ;
next = rps.propertyStorage.next != - 1 ?
mappings[rps.propertyStorage.next] : -1 ;
}
ps.setPrevious(previous);
ps.setNext(next);
ps.setDirectory(-1);
ps.setColour(1);
System.arraycopy(ps.data, 0,
propertySetStorage, pos,
PROPERTY_STORAGE_BLOCK_SIZE);
pos += PROPERTY_STORAGE_BLOCK_SIZE;
// Set the document summary information
ps = new PropertyStorage(DOCUMENT_SUMMARY_INFORMATION_NAME);
ps.setType(2);
ps.setStartBlock(excelDataStartBlock + excelDataBlocks + 8);
ps.setSize(SMALL_BLOCK_THRESHOLD);
ps.setPrevious(-1);
ps.setNext(-1);
ps.setDirectory(-1);
ps.setColour(1);
System.arraycopy(ps.data, 0,
propertySetStorage, pos,
PROPERTY_STORAGE_BLOCK_SIZE);
pos += PROPERTY_STORAGE_BLOCK_SIZE;
// Write out the additional property sets
if (additionalPropertySets == null)
{
out.write(propertySetStorage);
return;
}
int bigBlock = excelDataStartBlock + excelDataBlocks + 16 +
18;
for (Iterator i = additionalPropertySets.iterator() ; i.hasNext(); )
{
ReadPropertyStorage rps = (ReadPropertyStorage) i.next();
ps = new PropertyStorage(rps.propertyStorage.name);
ps.setType(rps.propertyStorage.type);
ps.setStartBlock(bigBlock);
ps.setSize(Math.max(rps.propertyStorage.size, SMALL_BLOCK_THRESHOLD));
previous = rps.propertyStorage.previous != -1 ?
mappings[rps.propertyStorage.previous] : -1;
next = rps.propertyStorage.next != -1 ?
mappings[rps.propertyStorage.next] : -1;
dir = rps.propertyStorage.directory != -1 ?
mappings[rps.propertyStorage.directory] : -1;
ps.setPrevious(previous);
ps.setNext(next);
ps.setDirectory(dir);
ps.setColour(1);
System.arraycopy(ps.data, 0,
propertySetStorage, pos,
PROPERTY_STORAGE_BLOCK_SIZE);
pos += PROPERTY_STORAGE_BLOCK_SIZE;
if (rps.data.length >= SMALL_BLOCK_THRESHOLD)
{
bigBlock += getBigBlocksRequired(rps.data.length);
}
else
{
bigBlock += SMALL_BLOCK_THRESHOLD / BIG_BLOCK_SIZE;
}
}
out.write(propertySetStorage);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -