package org.openntf.domino.nsfdata.structs.obj;
import java.nio.ByteBuffer;
import java.util.Iterator;
import org.openntf.domino.nsfdata.structs.cd.CDFILEHEADER;
import org.openntf.domino.nsfdata.structs.cd.CDFILESEGMENT;
import org.openntf.domino.nsfdata.structs.cd.CDRecord;
import org.openntf.domino.nsfdata.structs.cd.CDSignature;
/**
* This is a convenience class that wrapped a composite data file - one CDFILEHEADER record and zero or more CDFILESEGMENT records - into a
* single entity.
*
* @author jgallagher
*
*/
public class CDResourceFile extends CDObject {
// It appears that segments cap out at 10240 bytes of data
public static final int SEGMENT_SIZE_CAP = 10240;
public CDFILEHEADER header_;
public byte[] fileData_;
private transient CDFILESEGMENT[] segments_;
private int totalSize = 0;
// /**
// * Creates a CDResourceFile wrapping the underlying byte array. Until the file is modified, it does <b>not</b> copy the bytes, so any
// * modifications to the underlying array will also modify this data.
// *
// * @param data
// * A byte array representing a valid CD file record (i.e. one CDFILEHEADER and zero or more CDFILESEGMENTs).
// */
// public CDResourceFile(final byte[] data) {
// CData cdata = new CData(ByteBuffer.wrap(data));
// Iterator<CDRecord> iter = cdata.iterator();
// header_ = (CDFILEHEADER) iter.next();
// fileData_ = new byte[(int) header_.FileDataSize.get()];
// int ofs = 0;
// for (int i = 0; i < header_.SegCount.get(); i++) {
// CDFILESEGMENT segment = (CDFILESEGMENT) iter.next();
// ofs += segment.getPayload(fileData_, ofs);
// }
// }
public CDResourceFile(final String fileExt) {
header_ = new CDFILEHEADER();
header_.init();
header_.Header.setSigIdentifier(CDSignature.FILEHEADER.getBaseValue());
header_.setFileExt(fileExt);
header_.Header.setRecordLength(header_.size() + header_.getVariableSize());
header_.FileDataSize.set(0);
header_.SegCount.set(0);
fileData_ = new byte[0];
}
public CDResourceFile(final CDFILEHEADER header, final Iterator<CDRecord> records) {
header_ = header;
fileData_ = new byte[(int) header_.FileDataSize.get()];
int ofs = 0;
for (int i = 0; i < header_.SegCount.get(); i++) {
CDFILESEGMENT segment = (CDFILESEGMENT) records.next();
ofs += segment.getPayload(fileData_, ofs);
}
}
public void setFileData(final byte[] fileData) {
header_.FileDataSize.set(fileData.length);
fileData_ = fileData;
segments_ = null;
}
public ByteBuffer getData() {
// Determine how many file segments will be needed based on the inferred size cap
if (segments_ == null) {
int chunks = fileData_.length / SEGMENT_SIZE_CAP;
if (fileData_.length % SEGMENT_SIZE_CAP > 0) {
chunks++;
}
header_.SegCount.set(chunks);
segments_ = new CDFILESEGMENT[chunks];
totalSize = (int) header_.getTotalSize();
for (int i = 0; i < chunks; i++) {
// Each chunk begins with a CDFILESEGMENT
// Figure out our data and segment sizes
int dataOffset = SEGMENT_SIZE_CAP * i;
short dataSize = (short) ((fileData_.length - dataOffset) > SEGMENT_SIZE_CAP ? SEGMENT_SIZE_CAP
: (fileData_.length - dataOffset));
short segSize = (short) (dataSize % 2 == 0 ? dataSize : dataSize + 1);
segments_[i] = new CDFILESEGMENT();
segments_[i].init();
segments_[i].Header.setSigIdentifier(CDSignature.FILESEGMENT.getBaseValue());
segments_[i].SegSize.set(segSize);
segments_[i].setFileData(fileData_);
segments_[i].Header.setRecordLength(segments_[i].size() + segments_[i].getVariableSize());
totalSize += segments_[i].getTotalSize();
}
}
ByteBuffer result = ByteBuffer.allocate(totalSize);
// ByteBuffer headerBuffer = header_.getByteBuffer();
// headerBuffer.position(0);
result.put(header_.getBytes());
for (CDFILESEGMENT seg : segments_) {
// ByteBuffer segBuffer = seg.getByteBuffer();
// segBuffer.position(0);
byte[] segBytes = seg.getBytes();
result.put(segBytes);
}
result.position(0);
return result;
}
public byte[] getFileData() {
return fileData_;
}
}