blob: dc6d0f3babb46b47f3a7a60b0fb5de7f0e244bdf [file] [log] [blame]
/********************************************************************************
* Copyright (c) 2015-2018 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
********************************************************************************/
package org.eclipse.mdm.mdfsorter.mdf4;
import java.io.IOException;
import java.math.BigInteger;
import java.util.Arrays;
import org.eclipse.mdm.mdfsorter.ArgumentStruct;
import org.eclipse.mdm.mdfsorter.MDFParser;
/**
* The Data List Block The DLBLOCK references a list of data blocks (DTBLOCK) or
* a list of signal data blocks (SDBLOCK) or a list of reduction data blocks
* (RDBLOCK). This list of blocks is equivalent to using a single
* (signal/reduction) data block and can be used to avoid a huge data block by
* splitting it into smaller parts.
*
* @author Christian Rechner, Tobias Leemann
*/
public class DLBLOCK extends MDF4GenBlock {
// public static String BLOCK_ID = "##DL";
/** Data section */
// Flags
// Bit 0: Equal length flag
// UINT8
private byte flags;
// Number of referenced blocks N
// UINT32
private long count;
// Only present if "equal length" flag (bit 0 in dl_flags) is set.
// Equal data section length.
// UINT64
private long equalLength;
// Only present if "equal length" flag (bit 0 in dl_flags) is not set.
// Start offset (in Bytes) for the data section of each referenced block.
// UINT64
private long[] offset;
public DLBLOCK() {
super(0);
setId("##DL");
}
/**
* Parse a HLBLOCK from an existing MDFGenBlock
*
* @param parent
* The already existing MDF Generic Block.
*/
public DLBLOCK(MDF4GenBlock parent) {
super(parent.getPos());
setLength(parent.getLength());
setLinkCount(parent.getLinkCount());
setId(parent.getId());
setLinks(parent.getLinks());
parent.setPrec(this);
}
public MDF4GenBlock getLnkDlNext() {
return links[0];
}
public MDF4GenBlock[] getLnkDlData() {
return Arrays.copyOfRange(links, 1, links.length);
}
public byte getFlags() {
return flags;
}
public long getCount() {
return count;
}
public long getEqualLength() {
return equalLength;
}
public long[] getOffset() {
return offset;
}
public void setFlags(byte flags) {
this.flags = flags;
}
public void setCount(long count) {
this.count = count;
}
public void setEqualLength(long equalLength) {
this.equalLength = equalLength;
}
public void setOffset(long[] offset) {
this.offset = offset;
}
public boolean isEqualLengthFlag() {
return BigInteger.valueOf(flags).testBit(0);
}
@Override
public void setLinkCount(long linkCount) {
offset = new long[(int) linkCount - 1];
super.setLinkCount(linkCount);
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
return "DLBLOCK [lnkDlNext=" + getLnkDlNext() + ", lnkDlData=" + Arrays.toString(getLnkDlData()) + ", flags="
+ flags + ", count=" + count + ", equalLength=" + equalLength + ", offset=" + Arrays.toString(offset)
+ "]";
}
@Override
public void parse(byte[] content) throws IOException {
setFlags(MDF4Util.readUInt8(MDFParser.getDataBuffer(content, 0, 1)));
setCount(MDF4Util.readUInt32(MDFParser.getDataBuffer(content, 4, 8)));
if (isEqualLengthFlag()) {
setEqualLength(MDF4Util.readUInt64(MDFParser.getDataBuffer(content, 8, 16)));
} else {
long[] offset = new long[(int) getCount()];
for (int i = 0; i < offset.length; i++) {
offset[i] = MDF4Util.readUInt64(MDFParser.getDataBuffer(content, 8 + 8 * i, 16 + 8 * i));
}
setOffset(offset);
}
}
@Override
public byte[] getBodyBytes() {
int arraylen = 0;
if (isEqualLengthFlag()) {
arraylen = 4 + 4 + 8;
} else {
arraylen = (int) (4 + 4 + 8 * getCount());
}
byte[] ret = new byte[arraylen];
// flags UINT8
ret[0] = flags;
byte[] count = MDF4Util.getBytesUInt32(this.count);
System.arraycopy(count, 0, ret, 4, 4);
if (isEqualLengthFlag()) {
byte[] eqlen = MDF4Util.getBytesUInt64(equalLength);
System.arraycopy(eqlen, 0, ret, 8, 8);
} else {
int offset = 8;
for (int i = 0; i < this.count; i++) {
byte[] dtoffset = MDF4Util.getBytesUInt64(this.offset[i]);
System.arraycopy(dtoffset, 0, ret, offset, 8);
offset += 8;
}
}
return ret;
}
/**
* Checks if this list can be improved by merging blocks.
*
* @param args
* The programm arguments for this call
* @return True, if fewer blocks or an improvement is possible. False if
* not.
*/
public boolean isImproveable(ArgumentStruct args) {
if (getCount() == 0) {
return true;
}
// A data list that only contains one block is useless.
if (getCount() == 1 && getLink(1).getLength() < args.maxblocksize) {
return true;
}
// Split blocks if necessary
if (args.overrideOldSize) {
return true;
}
// check if list contains unzipped data but zipping is needed.
if (!args.unzip) {
DLBLOCK curr = this;
do {
for (int i = 0; i < curr.count; i++) {
String chldid = curr.getLink(i + 1).getId();
if (chldid.equals("##DT") || chldid.equals("##RD") || chldid.equals("##SD")) {
return true;
}
}
} while ((curr = (DLBLOCK) curr.getLink(0)) != null);
}
// check if fewer block are possible
if (isEqualLengthFlag()) {
if (getEqualLength() >= args.maxblocksize) {
return false;
} else {
// list consists of smaller blocks than possible
return true;
}
} else {
if (getLnkDlNext() != null) {
// list consists of another list (bad!)
return true;
} else {
long datasectionlength = getOffset()[(int) (getCount() - 1)]; // Calculate
// last
// offset
datasectionlength += getLink((int) getCount()).getLength() - 24L; // ...
// and
// add
// length
// of
// last
// block
if (datasectionlength / args.maxblocksize + 1 < getCount()) {
// fewer blocks are possible
return true;
} else {
return false;
}
}
}
}
}