blob: e7ec13ccfaee9120652e6cbfd54a773bb7fddf27 [file] [log] [blame]
/*
* Copyright (c) 2016 Audi AG
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.mdm.mdfsorter.mdf3;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.zip.DataFormatException;
import org.eclipse.mdm.mdfsorter.MDFAbstractProcessWriter;
public class MDF3BlocksSplittMerger {
/**
* Parent Object.
*/
private MDF3ProcessWriter ps;
/**
* Pointer to block in which the data is written.
*/
private DTBLOCK curr;
/**
* Pointer to block that is currently written. If curr is an DZBlock, write
* out data is buffered here, and zipped and written out, once all data for
* this block is read.
*/
private final MDF3GenBlock parentnode;
/**
* Total length of the new Data section. Needs to be calculated in advance
* before processing blocks.
*/
private final long totdatalength;
/**
* Amount of bytes of data written behind the output block
*/
private long datawritten = 0;
/**
* An offset in the global data section, only used, if the block that is
* read from is not known (towrite == null)
*/
private long globalReadPtr = 0;
/**
* Data Provider for reading blocks. This Object manages unzipping of
* blocks.
*/
private MDF3DataProvider prov;
/**
* Create a new Datasection with the given options, to write data without
* concern about the underlying block structure. Totaldatalength and prov
* can be passed manually. Therfore oldsection is not needed.
*
* @param ps
* The parent ProcessWriter
* @param parentnode
* Node that is parent of this datasection.
* @param totdatalength
* The length of data that will be written.
* @param prov
* The DataProvider to read from.
*/
public MDF3BlocksSplittMerger(MDF3ProcessWriter ps, MDF3GenBlock parentnode,
long totdatalength, MDF3DataProvider prov) {
this.ps = ps;
this.parentnode = parentnode;
this.totdatalength = totdatalength;
this.prov = prov;
}
public DTBLOCK getStructuralRoot() {
return curr;
}
/**
* Append the datasection beginning at <code>startaddress</code> until
* length to the output.
*
* @param startaddress
* Beginning of the section.
* @param length
* Length of the section.
* @throws IOException
* If an input error occurs.
* @throws DataFormatException
* If zipped data is in an invalid format.
*/
public void splitmerge(long startaddress, long length)
throws IOException, DataFormatException {
globalReadPtr = startaddress;
appendDataFromPos(length);
}
/**
* Reads leftbytes from the current position and appends them to the output
* section.
*
* @param leftbytes
* The number of bytes to append.
* @throws IOException
* If an I/O-Error occurs.
* @throws DataFormatException
* If zipped data is in an invalid format.
*/
public void appendDataFromPos(long leftbytes)
throws IOException, DataFormatException {
// check if space in curr-Block is available, and fill with first data,
// or attach all data if it fits
if (curr == null) {
curr = abstractcreate(totdatalength);
}
if (datawritten + leftbytes <= totdatalength) { // Space available
abstractcopy(leftbytes);
datawritten += leftbytes;
} else {
throw new RuntimeException(
"MDF3Merger got more data than space was reserved.");
}
}
/**
* Read data was read from the stream or Cache.
*
* @param length
* Number of Bytes to get.
* @return A Bytebuffer where <code>length</code> Bytes can be read from.
* @throws IOException
* If an I/O-Error occurs.
* @throws DataFormatException
* If zipped data is in an invalid format.
*/
public ByteBuffer abstractread(int length)
throws IOException, DataFormatException {
return prov.cachedRead(globalReadPtr, length);
}
public void abstractput(ByteBuffer buf, int length) {
ps.performPut(buf, length, true);
}
/**
* This Method creats a new data block.
*
* @param newblocklength
* Datalength of the new block
* @return The newly created block.
* @throws IOException
* If an I/O-Error occurs.
*/
public DTBLOCK abstractcreate(long newblocklength) throws IOException {
DTBLOCK ret;
ret = ps.create(newblocklength);
return ret;
}
/**
* Reads length bytes with <code>reader</code> and writes them out. This
* happens in smaller blocks.
*
* @param length
* The number of bytes to copy.
* @throws IOException
* If an I/O-Error occurs.
* @throws DataFormatException
* If zipped data is in an invalid format.
*/
public void abstractcopy(long length)
throws IOException, DataFormatException {
long written = 0L;
do {
int bytesread = 0;
if (written
+ MDFAbstractProcessWriter.MAX_OUTPUTBLOCKSIZE > length) {
bytesread = (int) (length - written);
ByteBuffer custombuffer = abstractread(bytesread);
abstractput(custombuffer, bytesread);
} else {
ByteBuffer buffer = abstractread(
MDFAbstractProcessWriter.MAX_OUTPUTBLOCKSIZE);
bytesread = MDFAbstractProcessWriter.MAX_OUTPUTBLOCKSIZE;
abstractput(buffer, bytesread);
}
written += bytesread;
} while (written < length);
if (length != written) {
throw new IOException("written length not equal to blocklength: "
+ length + "/" + written);
}
}
public void setLinks() {
if (parentnode instanceof DGBLOCK) {
parentnode.setLink(3, curr);
} else {
System.err.println(
"Unable to set link to data block. Parent block not recognized.");
}
}
/**
* ONLY FOR TESTING! Used in MDFUnsorter, replaces this splitmerger's
* provider.
*
* @param prov
* The new data provider.
*/
public void setProv(MDF3DataProvider prov) {
this.prov = prov;
}
}