| /* |
| * 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; |
| } |
| |
| } |