Files
HRMS/hrmsEjb/jxl/write/biff/CompoundFile.java
2025-07-28 13:56:49 +05:30

540 lines
20 KiB
Java

package jxl.write.biff;
import common.Assert;
import common.Logger;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import jxl.biff.BaseCompoundFile;
import jxl.biff.IntegerHelper;
import jxl.read.biff.BiffException;
final class CompoundFile extends BaseCompoundFile {
private static Logger logger = Logger.getLogger(CompoundFile.class);
private OutputStream out;
private byte[] excelData;
private int size;
private int requiredSize;
private int numBigBlockDepotBlocks;
private int numSmallBlockDepotChainBlocks;
private int numSmallBlockDepotBlocks;
private int numExtensionBlocks;
private int extensionBlock;
private int excelDataBlocks;
private int rootStartBlock;
private int excelDataStartBlock;
private int bbdStartBlock;
private int sbdStartBlockChain;
private int sbdStartBlock;
private int additionalPropertyBlocks;
private int numSmallBlocks;
private int numPropertySets;
private int numRootEntryBlocks;
private ArrayList additionalPropertySets;
private HashMap standardPropertySets;
private int bbdPos;
private byte[] bigBlockDepot;
private static final class ReadPropertyStorage {
BaseCompoundFile.PropertyStorage propertyStorage;
byte[] data;
int number;
ReadPropertyStorage(BaseCompoundFile.PropertyStorage ps, byte[] d, int n) {
this.propertyStorage = ps;
this.data = d;
this.number = n;
}
}
public CompoundFile(byte[] data, int l, OutputStream os, jxl.read.biff.CompoundFile rcf) throws CopyAdditionalPropertySetsException, IOException {
this.size = l;
this.excelData = data;
readAdditionalPropertySets(rcf);
this.numRootEntryBlocks = 1;
this.numPropertySets = 4 + ((this.additionalPropertySets != null) ? this.additionalPropertySets.size() : 0);
if (this.additionalPropertySets != null) {
this.numSmallBlockDepotChainBlocks = getBigBlocksRequired(this.numSmallBlocks * 4);
this.numSmallBlockDepotBlocks = getBigBlocksRequired(this.numSmallBlocks * 64);
this.numRootEntryBlocks += getBigBlocksRequired(this.additionalPropertySets.size() * 128);
}
int blocks = getBigBlocksRequired(l);
if (l < 4096) {
this.requiredSize = 4096;
} else {
this.requiredSize = blocks * 512;
}
this.out = os;
this.excelDataBlocks = this.requiredSize / 512;
this.numBigBlockDepotBlocks = 1;
int blockChainLength = 109;
int startTotalBlocks = this.excelDataBlocks + 8 + 8 + this.additionalPropertyBlocks + this.numSmallBlockDepotBlocks + this.numSmallBlockDepotChainBlocks + this.numRootEntryBlocks;
int totalBlocks = startTotalBlocks + this.numBigBlockDepotBlocks;
this.numBigBlockDepotBlocks = (int)Math.ceil(totalBlocks / 128.0D);
totalBlocks = startTotalBlocks + this.numBigBlockDepotBlocks;
this.numBigBlockDepotBlocks = (int)Math.ceil(totalBlocks / 128.0D);
totalBlocks = startTotalBlocks + this.numBigBlockDepotBlocks;
if (this.numBigBlockDepotBlocks > blockChainLength - 1) {
this.extensionBlock = 0;
int bbdBlocksLeft = this.numBigBlockDepotBlocks - blockChainLength + 1;
this.numExtensionBlocks = (int)Math.ceil(bbdBlocksLeft / 127.0D);
totalBlocks = startTotalBlocks + this.numExtensionBlocks + this.numBigBlockDepotBlocks;
this.numBigBlockDepotBlocks = (int)Math.ceil(totalBlocks / 128.0D);
totalBlocks = startTotalBlocks + this.numExtensionBlocks + this.numBigBlockDepotBlocks;
} else {
this.extensionBlock = -2;
this.numExtensionBlocks = 0;
}
this.excelDataStartBlock = this.numExtensionBlocks;
this.sbdStartBlock = -2;
if (this.additionalPropertySets != null && this.numSmallBlockDepotBlocks != 0)
this.sbdStartBlock = this.excelDataStartBlock + this.excelDataBlocks + this.additionalPropertyBlocks + 16;
this.sbdStartBlockChain = -2;
if (this.sbdStartBlock != -2)
this.sbdStartBlockChain = this.sbdStartBlock + this.numSmallBlockDepotBlocks;
if (this.sbdStartBlockChain != -2) {
this.bbdStartBlock = this.sbdStartBlockChain + this.numSmallBlockDepotChainBlocks;
} else {
this.bbdStartBlock = this.excelDataStartBlock + this.excelDataBlocks + this.additionalPropertyBlocks + 16;
}
this.rootStartBlock = this.bbdStartBlock + this.numBigBlockDepotBlocks;
if (totalBlocks != this.rootStartBlock + this.numRootEntryBlocks) {
logger.warn("Root start block and total blocks are inconsistent generated file may be corrupt");
logger.warn("RootStartBlock " + this.rootStartBlock + " totalBlocks " + totalBlocks);
}
}
private void readAdditionalPropertySets(jxl.read.biff.CompoundFile readCompoundFile) throws CopyAdditionalPropertySetsException, IOException {
if (readCompoundFile == null)
return;
this.additionalPropertySets = new ArrayList();
this.standardPropertySets = new HashMap();
int blocksRequired = 0;
int numPropertySets = readCompoundFile.getNumberOfPropertySets();
for (int i = 0; i < numPropertySets; i++) {
BaseCompoundFile.PropertyStorage ps = readCompoundFile.getPropertySet(i);
boolean standard = false;
if (ps.name.equalsIgnoreCase("Root Entry")) {
standard = true;
ReadPropertyStorage rps = new ReadPropertyStorage(ps, null, i);
this.standardPropertySets.put("Root Entry", rps);
}
for (int j = 0; j < STANDARD_PROPERTY_SETS.length && !standard; j++) {
if (ps.name.equalsIgnoreCase(STANDARD_PROPERTY_SETS[j])) {
BaseCompoundFile.PropertyStorage ps2 = readCompoundFile.findPropertyStorage(ps.name);
Assert.verify((ps2 != null));
if (ps2 == ps) {
standard = true;
ReadPropertyStorage rps = new ReadPropertyStorage(ps, null, i);
this.standardPropertySets.put(STANDARD_PROPERTY_SETS[j], rps);
}
}
}
if (!standard)
try {
byte[] data = null;
if (ps.size > 0) {
data = readCompoundFile.getStream(i);
} else {
data = new byte[0];
}
ReadPropertyStorage rps = new ReadPropertyStorage(ps, data, i);
this.additionalPropertySets.add(rps);
if (data.length > 4096) {
int blocks = getBigBlocksRequired(data.length);
blocksRequired += blocks;
} else {
int blocks = getSmallBlocksRequired(data.length);
this.numSmallBlocks += blocks;
}
} catch (BiffException e) {
logger.error(e);
throw new CopyAdditionalPropertySetsException();
}
}
this.additionalPropertyBlocks = blocksRequired;
}
public void write() throws IOException {
writeHeader();
writeExcelData();
writeDocumentSummaryData();
writeSummaryData();
writeAdditionalPropertySets();
writeSmallBlockDepot();
writeSmallBlockDepotChain();
writeBigBlockDepot();
writePropertySets();
}
private void writeAdditionalPropertySets() throws IOException {
if (this.additionalPropertySets == null)
return;
for (Iterator i = this.additionalPropertySets.iterator(); i.hasNext(); ) {
ReadPropertyStorage rps = i.next();
byte[] data = rps.data;
if (data.length > 4096) {
int numBlocks = getBigBlocksRequired(data.length);
int requiredSize = numBlocks * 512;
this.out.write(data, 0, data.length);
byte[] padding = new byte[requiredSize - data.length];
this.out.write(padding, 0, padding.length);
}
}
}
private void writeExcelData() throws IOException {
this.out.write(this.excelData, 0, this.size);
byte[] padding = new byte[this.requiredSize - this.size];
this.out.write(padding);
}
private void writeDocumentSummaryData() throws IOException {
byte[] padding = new byte[4096];
this.out.write(padding);
}
private void writeSummaryData() throws IOException {
byte[] padding = new byte[4096];
this.out.write(padding);
}
private void writeHeader() throws IOException {
byte[] headerBlock = new byte[512];
byte[] extensionBlockData = new byte[512 * this.numExtensionBlocks];
System.arraycopy(IDENTIFIER, 0, headerBlock, 0, IDENTIFIER.length);
headerBlock[24] = 62;
headerBlock[26] = 3;
headerBlock[28] = -2;
headerBlock[29] = -1;
headerBlock[30] = 9;
headerBlock[32] = 6;
headerBlock[57] = 16;
IntegerHelper.getFourBytes(this.numBigBlockDepotBlocks, headerBlock, 44);
IntegerHelper.getFourBytes(this.sbdStartBlockChain, headerBlock, 60);
IntegerHelper.getFourBytes(this.numSmallBlockDepotChainBlocks, headerBlock, 64);
IntegerHelper.getFourBytes(this.extensionBlock, headerBlock, 68);
IntegerHelper.getFourBytes(this.numExtensionBlocks, headerBlock, 72);
IntegerHelper.getFourBytes(this.rootStartBlock, headerBlock, 48);
int pos = 76;
int blocksToWrite = Math.min(this.numBigBlockDepotBlocks, 109);
int blocksWritten = 0;
int i;
for (i = 0; i < blocksToWrite; i++) {
IntegerHelper.getFourBytes(this.bbdStartBlock + i, headerBlock, pos);
pos += 4;
blocksWritten++;
}
for (i = pos; i < 512; i++)
headerBlock[i] = -1;
this.out.write(headerBlock);
pos = 0;
for (int extBlock = 0; extBlock < this.numExtensionBlocks; extBlock++) {
blocksToWrite = Math.min(this.numBigBlockDepotBlocks - blocksWritten, 127);
for (int j = 0; j < blocksToWrite; j++) {
IntegerHelper.getFourBytes(this.bbdStartBlock + blocksWritten + j, extensionBlockData, pos);
pos += 4;
}
blocksWritten += blocksToWrite;
int nextBlock = (blocksWritten == this.numBigBlockDepotBlocks) ? -2 : (extBlock + 1);
IntegerHelper.getFourBytes(nextBlock, extensionBlockData, pos);
pos += 4;
}
if (this.numExtensionBlocks > 0) {
for (int j = pos; j < extensionBlockData.length; j++)
extensionBlockData[j] = -1;
this.out.write(extensionBlockData);
}
}
private void checkBbdPos() throws IOException {
if (this.bbdPos >= 512) {
this.out.write(this.bigBlockDepot);
this.bigBlockDepot = new byte[512];
this.bbdPos = 0;
}
}
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, (512 - this.bbdPos) / 4);
for (int i = 0; i < bbdBlocks; i++) {
IntegerHelper.getFourBytes(blockNumber, this.bigBlockDepot, this.bbdPos);
this.bbdPos += 4;
blockNumber++;
}
blocksToWrite -= bbdBlocks;
checkBbdPos();
}
IntegerHelper.getFourBytes(-2, this.bigBlockDepot, this.bbdPos);
this.bbdPos += 4;
checkBbdPos();
}
private void writeAdditionalPropertySetBlockChains() throws IOException {
if (this.additionalPropertySets == null)
return;
int blockNumber = this.excelDataStartBlock + this.excelDataBlocks + 16;
for (Iterator i = this.additionalPropertySets.iterator(); i.hasNext(); ) {
ReadPropertyStorage rps = i.next();
if (rps.data.length > 4096) {
int numBlocks = getBigBlocksRequired(rps.data.length);
writeBlockChain(blockNumber, numBlocks);
blockNumber += numBlocks;
}
}
}
private void writeSmallBlockDepotChain() throws IOException {
if (this.sbdStartBlockChain == -2)
return;
byte[] smallBlockDepotChain = new byte[this.numSmallBlockDepotChainBlocks * 512];
int pos = 0;
int sbdBlockNumber = 1;
for (Iterator i = this.additionalPropertySets.iterator(); i.hasNext(); ) {
ReadPropertyStorage rps = i.next();
if (rps.data.length <= 4096 && rps.data.length != 0) {
int numSmallBlocks = getSmallBlocksRequired(rps.data.length);
for (int j = 0; j < numSmallBlocks - 1; j++) {
IntegerHelper.getFourBytes(sbdBlockNumber, smallBlockDepotChain, pos);
pos += 4;
sbdBlockNumber++;
}
IntegerHelper.getFourBytes(-2, smallBlockDepotChain, pos);
pos += 4;
sbdBlockNumber++;
}
}
this.out.write(smallBlockDepotChain);
}
private void writeSmallBlockDepot() throws IOException {
if (this.additionalPropertySets == null)
return;
byte[] smallBlockDepot = new byte[this.numSmallBlockDepotBlocks * 512];
int pos = 0;
for (Iterator i = this.additionalPropertySets.iterator(); i.hasNext(); ) {
ReadPropertyStorage rps = i.next();
if (rps.data.length <= 4096) {
int smallBlocks = getSmallBlocksRequired(rps.data.length);
int length = smallBlocks * 64;
System.arraycopy(rps.data, 0, smallBlockDepot, pos, rps.data.length);
pos += length;
}
}
this.out.write(smallBlockDepot);
}
private void writeBigBlockDepot() throws IOException {
this.bigBlockDepot = new byte[512];
this.bbdPos = 0;
for (int i = 0; i < this.numExtensionBlocks; i++) {
IntegerHelper.getFourBytes(-3, this.bigBlockDepot, this.bbdPos);
this.bbdPos += 4;
checkBbdPos();
}
writeBlockChain(this.excelDataStartBlock, this.excelDataBlocks);
int summaryInfoBlock = this.excelDataStartBlock + this.excelDataBlocks + this.additionalPropertyBlocks;
int j;
for (j = summaryInfoBlock; j < summaryInfoBlock + 7; j++) {
IntegerHelper.getFourBytes(j + 1, this.bigBlockDepot, this.bbdPos);
this.bbdPos += 4;
checkBbdPos();
}
IntegerHelper.getFourBytes(-2, this.bigBlockDepot, this.bbdPos);
this.bbdPos += 4;
checkBbdPos();
for (j = summaryInfoBlock + 8; j < summaryInfoBlock + 15; j++) {
IntegerHelper.getFourBytes(j + 1, this.bigBlockDepot, this.bbdPos);
this.bbdPos += 4;
checkBbdPos();
}
IntegerHelper.getFourBytes(-2, this.bigBlockDepot, this.bbdPos);
this.bbdPos += 4;
checkBbdPos();
writeAdditionalPropertySetBlockChains();
if (this.sbdStartBlock != -2) {
writeBlockChain(this.sbdStartBlock, this.numSmallBlockDepotBlocks);
writeBlockChain(this.sbdStartBlockChain, this.numSmallBlockDepotChainBlocks);
}
for (j = 0; j < this.numBigBlockDepotBlocks; j++) {
IntegerHelper.getFourBytes(-3, this.bigBlockDepot, this.bbdPos);
this.bbdPos += 4;
checkBbdPos();
}
writeBlockChain(this.rootStartBlock, this.numRootEntryBlocks);
if (this.bbdPos != 0) {
for (j = this.bbdPos; j < 512; j++)
this.bigBlockDepot[j] = -1;
this.out.write(this.bigBlockDepot);
}
}
private int getBigBlocksRequired(int length) {
int blocks = length / 512;
return (length % 512 > 0) ? (blocks + 1) : blocks;
}
private int getSmallBlocksRequired(int length) {
int blocks = length / 64;
return (length % 64 > 0) ? (blocks + 1) : blocks;
}
private void writePropertySets() throws IOException {
byte[] propertySetStorage = new byte[512 * this.numRootEntryBlocks];
int pos = 0;
int[] mappings = null;
if (this.additionalPropertySets != null) {
mappings = new int[this.numPropertySets];
for (int j = 0; j < STANDARD_PROPERTY_SETS.length; j++) {
ReadPropertyStorage rps = (ReadPropertyStorage)this.standardPropertySets.get(STANDARD_PROPERTY_SETS[j]);
if (rps != null) {
mappings[rps.number] = j;
} else {
logger.warn("Standard property set " + STANDARD_PROPERTY_SETS[j] + " not present in source file");
}
}
int newMapping = STANDARD_PROPERTY_SETS.length;
for (Iterator iterator = this.additionalPropertySets.iterator(); iterator.hasNext(); ) {
ReadPropertyStorage rps = iterator.next();
mappings[rps.number] = newMapping;
newMapping++;
}
}
int child = 0;
int previous = 0;
int next = 0;
int size = 0;
if (this.additionalPropertySets != null) {
size += getBigBlocksRequired(this.requiredSize) * 512;
size += getBigBlocksRequired(4096) * 512;
size += getBigBlocksRequired(4096) * 512;
for (Iterator iterator = this.additionalPropertySets.iterator(); iterator.hasNext(); ) {
ReadPropertyStorage rps = iterator.next();
if (rps.propertyStorage.type != 1) {
if (rps.propertyStorage.size >= 4096) {
size += getBigBlocksRequired(rps.propertyStorage.size) * 512;
continue;
}
size += getSmallBlocksRequired(rps.propertyStorage.size) * 64;
}
}
}
BaseCompoundFile.PropertyStorage ps = new BaseCompoundFile.PropertyStorage(this, "Root Entry");
ps.setType(5);
ps.setStartBlock(this.sbdStartBlock);
ps.setSize(size);
ps.setPrevious(-1);
ps.setNext(-1);
ps.setColour(0);
child = 1;
if (this.additionalPropertySets != null) {
ReadPropertyStorage rps = (ReadPropertyStorage)this.standardPropertySets.get("Root Entry");
child = mappings[rps.propertyStorage.child];
}
ps.setChild(child);
System.arraycopy(ps.data, 0, propertySetStorage, pos, 128);
pos += 128;
ps = new BaseCompoundFile.PropertyStorage(this, "Workbook");
ps.setType(2);
ps.setStartBlock(this.excelDataStartBlock);
ps.setSize(this.requiredSize);
previous = 3;
next = -1;
if (this.additionalPropertySets != null) {
ReadPropertyStorage rps = (ReadPropertyStorage)this.standardPropertySets.get("Workbook");
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.setChild(-1);
System.arraycopy(ps.data, 0, propertySetStorage, pos, 128);
pos += 128;
ps = new BaseCompoundFile.PropertyStorage(this, "\005SummaryInformation");
ps.setType(2);
ps.setStartBlock(this.excelDataStartBlock + this.excelDataBlocks);
ps.setSize(4096);
previous = 1;
next = 3;
if (this.additionalPropertySets != null) {
ReadPropertyStorage rps = (ReadPropertyStorage)this.standardPropertySets.get("\005SummaryInformation");
if (rps != null) {
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.setChild(-1);
System.arraycopy(ps.data, 0, propertySetStorage, pos, 128);
pos += 128;
ps = new BaseCompoundFile.PropertyStorage(this, "\005DocumentSummaryInformation");
ps.setType(2);
ps.setStartBlock(this.excelDataStartBlock + this.excelDataBlocks + 8);
ps.setSize(4096);
ps.setPrevious(-1);
ps.setNext(-1);
ps.setChild(-1);
System.arraycopy(ps.data, 0, propertySetStorage, pos, 128);
pos += 128;
if (this.additionalPropertySets == null) {
this.out.write(propertySetStorage);
return;
}
int bigBlock = this.excelDataStartBlock + this.excelDataBlocks + 16;
int smallBlock = 0;
for (Iterator i = this.additionalPropertySets.iterator(); i.hasNext(); ) {
ReadPropertyStorage rps = i.next();
int block = (rps.data.length > 4096) ? bigBlock : smallBlock;
ps = new BaseCompoundFile.PropertyStorage(this, rps.propertyStorage.name);
ps.setType(rps.propertyStorage.type);
ps.setStartBlock(block);
ps.setSize(rps.propertyStorage.size);
previous = (rps.propertyStorage.previous != -1) ? mappings[rps.propertyStorage.previous] : -1;
next = (rps.propertyStorage.next != -1) ? mappings[rps.propertyStorage.next] : -1;
child = (rps.propertyStorage.child != -1) ? mappings[rps.propertyStorage.child] : -1;
ps.setPrevious(previous);
ps.setNext(next);
ps.setChild(child);
System.arraycopy(ps.data, 0, propertySetStorage, pos, 128);
pos += 128;
if (rps.data.length > 4096) {
bigBlock += getBigBlocksRequired(rps.data.length);
continue;
}
smallBlock += getSmallBlocksRequired(rps.data.length);
}
this.out.write(propertySetStorage);
}
}