package org.reasm.m68k.assembly.internal;
import java.io.FileNotFoundException;
import java.io.IOException;
import javax.annotation.Nonnull;
import javax.annotation.concurrent.Immutable;
import org.reasm.AssemblyMessage;
import org.reasm.Value;
import org.reasm.commons.messages.ValueOutOfRangeErrorMessage;
import org.reasm.m68k.messages.IncbinLengthMustNotBeNegativeErrorMessage;
import org.reasm.m68k.messages.IncbinStartMustNotBeNegativeErrorMessage;
/**
* The <code>INCBIN</code> and <code>BINCLUDE</code> directives.
*
* @author Francis Gagné
*/
@Immutable
class IncbinDirective extends Mnemonic {
@Nonnull
static final IncbinDirective INCBIN = new IncbinDirective();
@Nonnull
private static final CardinalValueVisitor.ErrorFactory START_NEGATIVE_VALUE_ERROR_FACTORY = new CardinalValueVisitor.ErrorFactory() {
@Override
public AssemblyMessage createMessage() {
return new IncbinStartMustNotBeNegativeErrorMessage();
}
};
@Nonnull
private static final CardinalValueVisitor.ErrorFactory LENGTH_NEGATIVE_VALUE_ERROR_FACTORY = new CardinalValueVisitor.ErrorFactory() {
@Override
public AssemblyMessage createMessage() {
return new IncbinLengthMustNotBeNegativeErrorMessage();
}
};
private IncbinDirective() {
}
@Override
void assemble(M68KAssemblyContext context) throws IOException {
if (context.numberOfOperands < 1) {
context.addWrongNumberOfOperandsErrorMessage();
return;
}
if (context.numberOfOperands > 3) {
context.addWrongNumberOfOperandsErrorMessage();
}
final String filePath = IncludeDirective.getFilePath(context, 0);
if (filePath != null) {
final byte[] data = context.builder.getAssembly().fetchBinaryFile(filePath);
if (data == null) {
throw new FileNotFoundException(filePath);
}
int start = 0;
int length = data.length;
if (context.numberOfOperands >= 2) {
final Value startOperand = evaluateExpressionOperand(context, 1);
final CardinalValueVisitor startVisitor = context.cardinalValueVisitor;
startVisitor.reset(start, START_NEGATIVE_VALUE_ERROR_FACTORY);
Value.accept(startOperand, startVisitor);
long startLong = startVisitor.getValue();
if (startLong > data.length) {
context.addTentativeMessage(new ValueOutOfRangeErrorMessage(startLong));
startLong = data.length;
}
start = (int) startLong;
length = data.length - start;
if (context.numberOfOperands >= 3) {
final Value lengthOperand = evaluateExpressionOperand(context, 2);
final CardinalValueVisitor lengthVisitor = context.cardinalValueVisitor;
lengthVisitor.reset(length, LENGTH_NEGATIVE_VALUE_ERROR_FACTORY);
Value.accept(lengthOperand, lengthVisitor);
long lengthLong = lengthVisitor.getValue();
if (lengthLong > data.length - start) {
context.addTentativeMessage(new ValueOutOfRangeErrorMessage(lengthLong));
lengthLong = data.length - start;
}
length = (int) lengthLong;
}
}
if (length != 0) {
context.builder.appendAssembledData(data, start, length);
}
}
}
}