mirror of
https://github.com/peterdell/wudsn-ide.git
synced 2024-05-31 17:41:28 +00:00
Reformat source
This commit is contained in:
parent
25a4d82719
commit
62030ab828
|
@ -45,174 +45,172 @@ import com.wudsn.ide.asm.compiler.syntax.CompilerSyntax;
|
||||||
*/
|
*/
|
||||||
public final class CompilerRegistry {
|
public final class CompilerRegistry {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The id of the extension point which provides the compilers.
|
* The id of the extension point which provides the compilers.
|
||||||
*/
|
*/
|
||||||
private static final String COMPILERS = "com.wudsn.ide.asm.compilers";
|
private static final String COMPILERS = "com.wudsn.ide.asm.compilers";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The registered compiler definition.
|
* The registered compiler definition.
|
||||||
*/
|
*/
|
||||||
private List<CompilerDefinition> compilerDefinitionList;
|
private List<CompilerDefinition> compilerDefinitionList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The cached map of compiler instances.
|
* The cached map of compiler instances.
|
||||||
*/
|
*/
|
||||||
private Map<String, Compiler> compilerMap;
|
private Map<String, Compiler> compilerMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creation is public.
|
* Creation is public.
|
||||||
*/
|
*/
|
||||||
public CompilerRegistry() {
|
public CompilerRegistry() {
|
||||||
compilerDefinitionList = Collections.emptyList();
|
compilerDefinitionList = Collections.emptyList();
|
||||||
compilerMap = Collections.emptyMap();
|
compilerMap = Collections.emptyMap();
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes the list of available compilers.
|
|
||||||
*/
|
|
||||||
public void init() {
|
|
||||||
|
|
||||||
compilerDefinitionList = new ArrayList<CompilerDefinition>();
|
|
||||||
compilerMap = new TreeMap<String, Compiler>();
|
|
||||||
|
|
||||||
IExtensionRegistry extensionRegistry = Platform.getExtensionRegistry();
|
|
||||||
IExtensionPoint extensionPoint = extensionRegistry.getExtensionPoint(COMPILERS);
|
|
||||||
if (extensionPoint == null) {
|
|
||||||
throw new IllegalStateException("Extension point '" + COMPILERS + "' is not defined.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IExtension[] extensions = extensionPoint.getExtensions();
|
/**
|
||||||
|
* Initializes the list of available compilers.
|
||||||
|
*/
|
||||||
|
public void init() {
|
||||||
|
|
||||||
for (IExtension extension : extensions) {
|
compilerDefinitionList = new ArrayList<CompilerDefinition>();
|
||||||
IConfigurationElement[] configurationElements = extension.getConfigurationElements();
|
compilerMap = new TreeMap<String, Compiler>();
|
||||||
for (IConfigurationElement configurationElement : configurationElements) {
|
|
||||||
|
|
||||||
try {
|
IExtensionRegistry extensionRegistry = Platform.getExtensionRegistry();
|
||||||
CompilerDefinition compilerDefinition;
|
IExtensionPoint extensionPoint = extensionRegistry.getExtensionPoint(COMPILERS);
|
||||||
compilerDefinition = new CompilerDefinition();
|
if (extensionPoint == null) {
|
||||||
compilerDefinition.setId(configurationElement.getAttribute("id"));
|
throw new IllegalStateException("Extension point '" + COMPILERS + "' is not defined.");
|
||||||
compilerDefinition.setName(configurationElement.getAttribute("name"));
|
|
||||||
compilerDefinition.setClassName(configurationElement.getAttribute("class"));
|
|
||||||
compilerDefinition.setHelpFilePaths(configurationElement.getAttribute("helpFilePaths"));
|
|
||||||
compilerDefinition.setHomePageURL(configurationElement.getAttribute("homePageURL"));
|
|
||||||
compilerDefinition.setDefaultParameters(configurationElement.getAttribute("defaultParameters"));
|
|
||||||
|
|
||||||
configurationElement.getChildren("supportedCPU");
|
|
||||||
IConfigurationElement[] supportedCPUArray;
|
|
||||||
supportedCPUArray = configurationElement.getChildren("supportedCPU");
|
|
||||||
List<CPU> supportedCPUs = new ArrayList<CPU>(supportedCPUArray.length);
|
|
||||||
for (IConfigurationElement supportedCPU : supportedCPUArray) {
|
|
||||||
supportedCPUs.add(CPU.valueOf(supportedCPU.getAttribute("cpu")));
|
|
||||||
}
|
|
||||||
supportedCPUs = Collections.unmodifiableList(supportedCPUs);
|
|
||||||
compilerDefinition.setSupportedCPUs(supportedCPUs);
|
|
||||||
compilerDefinition.setDefaultHardware(Hardware.valueOf(configurationElement
|
|
||||||
.getAttribute("defaultHardware")));
|
|
||||||
|
|
||||||
compilerDefinitionList.add(compilerDefinition);
|
|
||||||
|
|
||||||
addCompiler(configurationElement, compilerDefinition);
|
|
||||||
} catch (RuntimeException ex) {
|
|
||||||
throw new RuntimeException("Error during registration of compiler '"
|
|
||||||
+ configurationElement.getAttribute("id") + "'.", ex);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
IExtension[] extensions = extensionPoint.getExtensions();
|
||||||
|
|
||||||
|
for (IExtension extension : extensions) {
|
||||||
|
IConfigurationElement[] configurationElements = extension.getConfigurationElements();
|
||||||
|
for (IConfigurationElement configurationElement : configurationElements) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
CompilerDefinition compilerDefinition;
|
||||||
|
compilerDefinition = new CompilerDefinition();
|
||||||
|
compilerDefinition.setId(configurationElement.getAttribute("id"));
|
||||||
|
compilerDefinition.setName(configurationElement.getAttribute("name"));
|
||||||
|
compilerDefinition.setClassName(configurationElement.getAttribute("class"));
|
||||||
|
compilerDefinition.setHelpFilePaths(configurationElement.getAttribute("helpFilePaths"));
|
||||||
|
compilerDefinition.setHomePageURL(configurationElement.getAttribute("homePageURL"));
|
||||||
|
compilerDefinition.setDefaultParameters(configurationElement.getAttribute("defaultParameters"));
|
||||||
|
|
||||||
|
configurationElement.getChildren("supportedCPU");
|
||||||
|
IConfigurationElement[] supportedCPUArray;
|
||||||
|
supportedCPUArray = configurationElement.getChildren("supportedCPU");
|
||||||
|
List<CPU> supportedCPUs = new ArrayList<CPU>(supportedCPUArray.length);
|
||||||
|
for (IConfigurationElement supportedCPU : supportedCPUArray) {
|
||||||
|
supportedCPUs.add(CPU.valueOf(supportedCPU.getAttribute("cpu")));
|
||||||
|
}
|
||||||
|
supportedCPUs = Collections.unmodifiableList(supportedCPUs);
|
||||||
|
compilerDefinition.setSupportedCPUs(supportedCPUs);
|
||||||
|
compilerDefinition
|
||||||
|
.setDefaultHardware(Hardware.valueOf(configurationElement.getAttribute("defaultHardware")));
|
||||||
|
|
||||||
|
compilerDefinitionList.add(compilerDefinition);
|
||||||
|
|
||||||
|
addCompiler(configurationElement, compilerDefinition);
|
||||||
|
} catch (RuntimeException ex) {
|
||||||
|
throw new RuntimeException(
|
||||||
|
"Error during registration of compiler '" + configurationElement.getAttribute("id") + "'.",
|
||||||
|
ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
compilerDefinitionList = new ArrayList<CompilerDefinition>(compilerDefinitionList);
|
||||||
|
Collections.sort(compilerDefinitionList);
|
||||||
|
compilerDefinitionList = Collections.unmodifiableList(compilerDefinitionList);
|
||||||
|
compilerMap = Collections.unmodifiableMap(compilerMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
compilerDefinitionList = new ArrayList<CompilerDefinition>(compilerDefinitionList);
|
/**
|
||||||
Collections.sort(compilerDefinitionList);
|
* Adds a new compiler.
|
||||||
compilerDefinitionList = Collections.unmodifiableList(compilerDefinitionList);
|
*
|
||||||
compilerMap = Collections.unmodifiableMap(compilerMap);
|
* @param configurationElement The configuration element used as class instance
|
||||||
}
|
* factory, not <code>null</code>.
|
||||||
|
*
|
||||||
|
* @param compilerDefinition The compiler definition, not <code>null</code>.
|
||||||
|
*/
|
||||||
|
private void addCompiler(IConfigurationElement configurationElement, CompilerDefinition compilerDefinition) {
|
||||||
|
if (configurationElement == null) {
|
||||||
|
throw new IllegalArgumentException("Parameter 'configurationElement' must not be null.");
|
||||||
|
}
|
||||||
|
if (compilerDefinition == null) {
|
||||||
|
throw new IllegalArgumentException("Parameter 'compilerDefinition' must not be null.");
|
||||||
|
}
|
||||||
|
|
||||||
|
String id = compilerDefinition.getId();
|
||||||
|
Compiler compiler;
|
||||||
|
try {
|
||||||
|
// The class loading must be delegated to the framework.
|
||||||
|
compiler = (Compiler) configurationElement.createExecutableExtension("class");
|
||||||
|
} catch (CoreException ex) {
|
||||||
|
throw new RuntimeException("Cannot create compiler instance for id '" + id + "'.", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build the list of common and specific syntax definition files.
|
||||||
|
List<Class<?>> compilerClasses = new ArrayList<Class<?>>(2);
|
||||||
|
compilerClasses.add(compiler.getClass());
|
||||||
|
compilerClasses.add(Compiler.class);
|
||||||
|
|
||||||
|
CompilerSyntax syntax;
|
||||||
|
syntax = new CompilerSyntax(id);
|
||||||
|
|
||||||
|
syntax.loadXMLData(compilerClasses);
|
||||||
|
|
||||||
|
compilerDefinition.setSyntax(syntax);
|
||||||
|
|
||||||
|
compiler.setDefinition(compilerDefinition);
|
||||||
|
|
||||||
|
compiler = compilerMap.put(id, compiler);
|
||||||
|
if (compiler != null) {
|
||||||
|
throw new RuntimeException(
|
||||||
|
"Compiler id '" + id + "' is already registered to class '" + compiler.getClass().getName() + "'.");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a new compiler.
|
|
||||||
*
|
|
||||||
* @param configurationElement
|
|
||||||
* The configuration element used as class instance factory, not
|
|
||||||
* <code>null</code>.
|
|
||||||
*
|
|
||||||
* @param compilerDefinition
|
|
||||||
* The compiler definition, not <code>null</code>.
|
|
||||||
*/
|
|
||||||
private void addCompiler(IConfigurationElement configurationElement, CompilerDefinition compilerDefinition) {
|
|
||||||
if (configurationElement == null) {
|
|
||||||
throw new IllegalArgumentException("Parameter 'configurationElement' must not be null.");
|
|
||||||
}
|
|
||||||
if (compilerDefinition == null) {
|
|
||||||
throw new IllegalArgumentException("Parameter 'compilerDefinition' must not be null.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String id = compilerDefinition.getId();
|
/**
|
||||||
Compiler compiler;
|
* Gets the unmodifiable list of compiler definitions, sorted by their id.
|
||||||
try {
|
*
|
||||||
// The class loading must be delegated to the framework.
|
*
|
||||||
compiler = (Compiler) configurationElement.createExecutableExtension("class");
|
* @return The unmodifiable list of compiler definitions, sorted by their id,
|
||||||
} catch (CoreException ex) {
|
* may be empty, not <code>null</code>
|
||||||
throw new RuntimeException("Cannot create compiler instance for id '" + id + "'.", ex);
|
*
|
||||||
|
* @since 1.6.1
|
||||||
|
*/
|
||||||
|
public List<CompilerDefinition> getCompilerDefinitions() {
|
||||||
|
return compilerDefinitionList;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build the list of common and specific syntax definition files.
|
/**
|
||||||
List<Class<?>> compilerClasses = new ArrayList<Class<?>>(2);
|
* Gets the compiler for a given id. Instances of compiler are stateless
|
||||||
compilerClasses.add(compiler.getClass());
|
* singletons within the plugin.
|
||||||
compilerClasses.add(Compiler.class);
|
*
|
||||||
|
* @param compilerId The compiler id, not <code>null</code>.
|
||||||
|
*
|
||||||
|
* @return The compiler, not <code>null</code>.
|
||||||
|
*/
|
||||||
|
public Compiler getCompiler(String compilerId) {
|
||||||
|
if (compilerId == null) {
|
||||||
|
throw new IllegalArgumentException("Parameter 'compilerId' must not be null.");
|
||||||
|
}
|
||||||
|
Compiler result;
|
||||||
|
synchronized (compilerMap) {
|
||||||
|
|
||||||
CompilerSyntax syntax;
|
result = compilerMap.get(compilerId);
|
||||||
syntax = new CompilerSyntax(id);
|
}
|
||||||
|
if (result == null) {
|
||||||
|
|
||||||
syntax.loadXMLData(compilerClasses);
|
throw new IllegalArgumentException("Unknown compiler id '" + compilerId + "'.");
|
||||||
|
}
|
||||||
|
|
||||||
compilerDefinition.setSyntax(syntax);
|
return result;
|
||||||
|
|
||||||
compiler.setDefinition(compilerDefinition);
|
|
||||||
|
|
||||||
compiler = compilerMap.put(id, compiler);
|
|
||||||
if (compiler != null) {
|
|
||||||
throw new RuntimeException("Compiler id '" + id + "' is already registered to class '"
|
|
||||||
+ compiler.getClass().getName() + "'.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the unmodifiable list of compiler definitions, sorted by their id.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return The unmodifiable list of compiler definitions, sorted by their
|
|
||||||
* id, may be empty, not <code>null</code>
|
|
||||||
*
|
|
||||||
* @since 1.6.1
|
|
||||||
*/
|
|
||||||
public List<CompilerDefinition> getCompilerDefinitions() {
|
|
||||||
return compilerDefinitionList;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the compiler for a given id. Instances of compiler are stateless
|
|
||||||
* singletons within the plugin.
|
|
||||||
*
|
|
||||||
* @param compilerId
|
|
||||||
* The compiler id, not <code>null</code>.
|
|
||||||
*
|
|
||||||
* @return The compiler, not <code>null</code>.
|
|
||||||
*/
|
|
||||||
public Compiler getCompiler(String compilerId) {
|
|
||||||
if (compilerId == null) {
|
|
||||||
throw new IllegalArgumentException("Parameter 'compilerId' must not be null.");
|
|
||||||
}
|
|
||||||
Compiler result;
|
|
||||||
synchronized (compilerMap) {
|
|
||||||
|
|
||||||
result = compilerMap.get(compilerId);
|
|
||||||
}
|
|
||||||
if (result == null) {
|
|
||||||
|
|
||||||
throw new IllegalArgumentException("Unknown compiler id '" + compilerId + "'.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,79 +29,77 @@ import com.wudsn.ide.asm.Texts;
|
||||||
*/
|
*/
|
||||||
public final class CompilerSyntaxUtility {
|
public final class CompilerSyntaxUtility {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creation private.
|
* Creation private.
|
||||||
*/
|
*/
|
||||||
private CompilerSyntaxUtility() {
|
private CompilerSyntaxUtility() {
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the image path for an instruction type image.
|
|
||||||
*
|
|
||||||
* @param instruction
|
|
||||||
* The instruction, not <code>null</code>.
|
|
||||||
* @return The image path for the instruction type image, not empty and not
|
|
||||||
* <code>null</code>.
|
|
||||||
*/
|
|
||||||
public static String getTypeImagePath(Instruction instruction) {
|
|
||||||
if (instruction == null) {
|
|
||||||
throw new IllegalArgumentException("Parameter 'instruction' must not be null.");
|
|
||||||
}
|
|
||||||
String path;
|
|
||||||
|
|
||||||
if (instruction instanceof Directive) {
|
|
||||||
path = "instruction-type-directive-16x16.gif";
|
|
||||||
} else {
|
|
||||||
Opcode opcode = (Opcode) instruction;
|
|
||||||
switch (opcode.getType()) {
|
|
||||||
case InstructionType.LEGAL_OPCODE:
|
|
||||||
path = "instruction-type-legal-opcode-16x16.gif";
|
|
||||||
break;
|
|
||||||
case InstructionType.ILLEGAL_OPCODE:
|
|
||||||
path = "instruction-type-illegal-opcode-16x16.gif";
|
|
||||||
break;
|
|
||||||
case InstructionType.PSEUDO_OPCODE:
|
|
||||||
path = "instruction-type-pseudo-opcode-16x16.gif";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new IllegalStateException("Unknown opcode type " + opcode.getType() + ".");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the text for an instruction type.
|
* Gets the image path for an instruction type image.
|
||||||
*
|
*
|
||||||
* @param instruction
|
* @param instruction The instruction, not <code>null</code>.
|
||||||
* The instruction, not <code>null</code>.
|
* @return The image path for the instruction type image, not empty and not
|
||||||
* @return The text for the instruction type image, may be empty, not
|
* <code>null</code>.
|
||||||
* <code>null</code>.
|
*/
|
||||||
*/
|
public static String getTypeImagePath(Instruction instruction) {
|
||||||
public static String getTypeText(Instruction instruction) {
|
if (instruction == null) {
|
||||||
String text;
|
throw new IllegalArgumentException("Parameter 'instruction' must not be null.");
|
||||||
|
}
|
||||||
|
String path;
|
||||||
|
|
||||||
if (instruction instanceof Directive) {
|
if (instruction instanceof Directive) {
|
||||||
text = Texts.COMPILER_SYNTAX_INSTRUCTION_DIRECTIVE;
|
path = "instruction-type-directive-16x16.gif";
|
||||||
} else {
|
} else {
|
||||||
Opcode opcode = (Opcode) instruction;
|
Opcode opcode = (Opcode) instruction;
|
||||||
switch (opcode.getType()) {
|
switch (opcode.getType()) {
|
||||||
case InstructionType.LEGAL_OPCODE:
|
case InstructionType.LEGAL_OPCODE:
|
||||||
text = Texts.COMPILER_SYNTAX_LEGAL_OPCODE;
|
path = "instruction-type-legal-opcode-16x16.gif";
|
||||||
break;
|
break;
|
||||||
case InstructionType.ILLEGAL_OPCODE:
|
case InstructionType.ILLEGAL_OPCODE:
|
||||||
text = Texts.COMPILER_SYNTAX_ILLEGAL_OPCODE;
|
path = "instruction-type-illegal-opcode-16x16.gif";
|
||||||
break;
|
break;
|
||||||
case InstructionType.PSEUDO_OPCODE:
|
case InstructionType.PSEUDO_OPCODE:
|
||||||
text = Texts.COMPILER_SYNTAX_PSEUDO_OPCODE;
|
path = "instruction-type-pseudo-opcode-16x16.gif";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IllegalStateException("Unknown opcode type " + opcode.getType() + ".");
|
throw new IllegalStateException("Unknown opcode type " + opcode.getType() + ".");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the text for an instruction type.
|
||||||
|
*
|
||||||
|
* @param instruction The instruction, not <code>null</code>.
|
||||||
|
* @return The text for the instruction type image, may be empty, not
|
||||||
|
* <code>null</code>.
|
||||||
|
*/
|
||||||
|
public static String getTypeText(Instruction instruction) {
|
||||||
|
String text;
|
||||||
|
|
||||||
|
if (instruction instanceof Directive) {
|
||||||
|
text = Texts.COMPILER_SYNTAX_INSTRUCTION_DIRECTIVE;
|
||||||
|
} else {
|
||||||
|
Opcode opcode = (Opcode) instruction;
|
||||||
|
switch (opcode.getType()) {
|
||||||
|
case InstructionType.LEGAL_OPCODE:
|
||||||
|
text = Texts.COMPILER_SYNTAX_LEGAL_OPCODE;
|
||||||
|
break;
|
||||||
|
case InstructionType.ILLEGAL_OPCODE:
|
||||||
|
text = Texts.COMPILER_SYNTAX_ILLEGAL_OPCODE;
|
||||||
|
break;
|
||||||
|
case InstructionType.PSEUDO_OPCODE:
|
||||||
|
text = Texts.COMPILER_SYNTAX_PSEUDO_OPCODE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException("Unknown opcode type " + opcode.getType() + ".");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return text;
|
||||||
}
|
}
|
||||||
return text;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,297 +47,297 @@ import com.wudsn.ide.base.common.StringUtility;
|
||||||
*/
|
*/
|
||||||
public final class AppleFileWriter extends CompilerFileWriter {
|
public final class AppleFileWriter extends CompilerFileWriter {
|
||||||
|
|
||||||
private final static String HELLO_ENTRY_NAME = "HELLO";
|
private final static String HELLO_ENTRY_NAME = "HELLO";
|
||||||
private final static String OUTPUT_IMAGE_ENTRY_NAME = "WORLD";
|
private final static String OUTPUT_IMAGE_ENTRY_NAME = "WORLD";
|
||||||
|
|
||||||
private final class AppleSoftTokens {
|
private final class AppleSoftTokens {
|
||||||
public final static byte PRINT = (byte) 0xba;
|
public final static byte PRINT = (byte) 0xba;
|
||||||
public final static byte CHRS = (byte) 0xe7;
|
public final static byte CHRS = (byte) 0xe7;
|
||||||
public final static byte CALL = (byte) 0x8c;
|
public final static byte CALL = (byte) 0x8c;
|
||||||
|
|
||||||
// public String[] tokenNames = { "END", "FOR ", "NEXT ", "DATA ",
|
// public String[] tokenNames = { "END", "FOR ", "NEXT ", "DATA ",
|
||||||
// "INPUT ", "DEL", "DIM ", "READ ", "GR", "TEXT", "PR#", "IN#",
|
// "INPUT ", "DEL", "DIM ", "READ ", "GR", "TEXT", "PR#", "IN#",
|
||||||
// "CALL ", "PLOT", "HLIN ", "VLIN ", "HGR2", "HGR", "HCOLOR=",
|
// "CALL ", "PLOT", "HLIN ", "VLIN ", "HGR2", "HGR", "HCOLOR=",
|
||||||
// "HPLOT ", "DRAW ", "XDRAW ", "HTAB ", "HOME", "ROT=", "SCALE=",
|
// "HPLOT ", "DRAW ", "XDRAW ", "HTAB ", "HOME", "ROT=", "SCALE=",
|
||||||
// "SHLOAD", "TRACE", "NOTRACE", "NORMAL", "INVERSE", "FLASH",
|
// "SHLOAD", "TRACE", "NOTRACE", "NORMAL", "INVERSE", "FLASH",
|
||||||
// "COLOR=", "POP", "VTAB ", "HIMEM:", "LOMEM:", "ONERR ",
|
// "COLOR=", "POP", "VTAB ", "HIMEM:", "LOMEM:", "ONERR ",
|
||||||
// "RESUME", "RECALL", "STORE", "SPEED=", "LET ", "GOTO ", "RUN",
|
// "RESUME", "RECALL", "STORE", "SPEED=", "LET ", "GOTO ", "RUN",
|
||||||
// "IF ", "RESTORE", "& ", "GOSUB ", "RETURN", "REM ", "STOP",
|
// "IF ", "RESTORE", "& ", "GOSUB ", "RETURN", "REM ", "STOP",
|
||||||
// "ON ", "WAIT", "LOAD", "SAVE", "DEF", "POKE ", "PRINT ",
|
// "ON ", "WAIT", "LOAD", "SAVE", "DEF", "POKE ", "PRINT ",
|
||||||
// "CONT", "LIST", "CLEAR", "GET ", "NEW", "TAB(", "TO ", "FN",
|
// "CONT", "LIST", "CLEAR", "GET ", "NEW", "TAB(", "TO ", "FN",
|
||||||
// "SPC(", "THEN ", "AT ", "NOT ", "STEP ", "+ ", "- ", "* ",
|
// "SPC(", "THEN ", "AT ", "NOT ", "STEP ", "+ ", "- ", "* ",
|
||||||
// "/ ", "^ ", "AND ", "OR ", "> ", "= ", "< ", "SGN", "INT",
|
// "/ ", "^ ", "AND ", "OR ", "> ", "= ", "< ", "SGN", "INT",
|
||||||
// "ABS", "USR", "FRE", "SCRN(", "PDL", "POS ", "SQR", "RND",
|
// "ABS", "USR", "FRE", "SCRN(", "PDL", "POS ", "SQR", "RND",
|
||||||
// "LOG", "EXP", "COS", "SIN", "TAN", "ATN", "PEEK", "LEN",
|
// "LOG", "EXP", "COS", "SIN", "TAN", "ATN", "PEEK", "LEN",
|
||||||
// "STR$", "VAL", "ASC", "CHR$", "LEFT$", "RIGHT$", "MID$" };
|
// "STR$", "VAL", "ASC", "CHR$", "LEFT$", "RIGHT$", "MID$" };
|
||||||
|
|
||||||
// public int[] tokenAddresses = { 0xD870, 0xD766, 0xDCF9, 0xD995,
|
// public int[] tokenAddresses = { 0xD870, 0xD766, 0xDCF9, 0xD995,
|
||||||
// 0xDBB2,
|
// 0xDBB2,
|
||||||
// 0xF331, 0xDFD9, 0xDBE2, 0xF390, 0xF399, 0xF1E5, 0xF1DE, 0xF1D5,
|
// 0xF331, 0xDFD9, 0xDBE2, 0xF390, 0xF399, 0xF1E5, 0xF1DE, 0xF1D5,
|
||||||
// 0xF225, 0xF232, 0xF241, 0xF3D8, 0xF3E2, 0xF6E9, 0xF6FE, 0xF769,
|
// 0xF225, 0xF232, 0xF241, 0xF3D8, 0xF3E2, 0xF6E9, 0xF6FE, 0xF769,
|
||||||
// 0xF76F, 0xF7E7, 0xFC58, 0xF721, 0xF727, 0xF775, 0xF26D, 0xF26F,
|
// 0xF76F, 0xF7E7, 0xFC58, 0xF721, 0xF727, 0xF775, 0xF26D, 0xF26F,
|
||||||
// 0xF273, 0xF277, 0xF280, 0xF24F, 0xD96B, 0xF256, 0xF286, 0xF2A6,
|
// 0xF273, 0xF277, 0xF280, 0xF24F, 0xD96B, 0xF256, 0xF286, 0xF2A6,
|
||||||
// 0xF2CB, 0xF318, 0xF3BC, 0xF39F, 0xF262, 0xDA46, 0xD93E, 0xD912,
|
// 0xF2CB, 0xF318, 0xF3BC, 0xF39F, 0xF262, 0xDA46, 0xD93E, 0xD912,
|
||||||
// 0xD9C9, 0xD849, 0x03F5, 0xD921, 0xD96B, 0xD9DC, 0xD86E, 0xD9EC,
|
// 0xD9C9, 0xD849, 0x03F5, 0xD921, 0xD96B, 0xD9DC, 0xD86E, 0xD9EC,
|
||||||
// 0xE784, 0xD8C9, 0xD8B0, 0xE313, 0xE77B, 0xFDAD5, 0xD896,
|
// 0xE784, 0xD8C9, 0xD8B0, 0xE313, 0xE77B, 0xFDAD5, 0xD896,
|
||||||
// 0xD6A5, 0xD66A, 0xDBA0, 0xD649, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
// 0xD6A5, 0xD66A, 0xDBA0, 0xD649, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
// 0, 0, 0, 0, 0, 0, 0, 0, 0xEB90, 0xEC23, 0xEBAF, 0x000A, 0xE2DE,
|
// 0, 0, 0, 0, 0, 0, 0, 0, 0xEB90, 0xEC23, 0xEBAF, 0x000A, 0xE2DE,
|
||||||
// 0xD412, 0xDFCD, 0xE2FF, 0xEE8D, 0xEFAE, 0xE941, 0xEF09, 0xEFEA,
|
// 0xD412, 0xDFCD, 0xE2FF, 0xEE8D, 0xEFAE, 0xE941, 0xEF09, 0xEFEA,
|
||||||
// 0xEFF1, 0xF03A, 0xF09E, 0xE764, 0xE6D6, 0xE3C5, 0xE707, 0xE6E5,
|
// 0xEFF1, 0xF03A, 0xF09E, 0xE764, 0xE6D6, 0xE3C5, 0xE707, 0xE6E5,
|
||||||
// 0xE646, 0xE65A, 0xE686, 0xE691 };
|
// 0xE646, 0xE65A, 0xE686, 0xE691 };
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean createOrUpdateDiskImage(CompilerFiles files) {
|
public boolean createOrUpdateDiskImage(CompilerFiles files) {
|
||||||
String imageFilePath = files.outputFilePathWithoutExtension + ".dsk";
|
String imageFilePath = files.outputFilePathWithoutExtension + ".dsk";
|
||||||
String outputImageEntryName = OUTPUT_IMAGE_ENTRY_NAME;
|
String outputImageEntryName = OUTPUT_IMAGE_ENTRY_NAME;
|
||||||
String outputImageEntryTitle = "Loading " + files.outputFileNameWithoutExtension;
|
String outputImageEntryTitle = "Loading " + files.outputFileNameWithoutExtension;
|
||||||
boolean autoCreate = true;
|
boolean autoCreate = true;
|
||||||
|
|
||||||
if (StringUtility.isSpecified(imageFilePath)) {
|
if (StringUtility.isSpecified(imageFilePath)) {
|
||||||
File imageFile = new File(imageFilePath);
|
File imageFile = new File(imageFilePath);
|
||||||
if (!imageFile.exists()) {
|
if (!imageFile.exists()) {
|
||||||
|
|
||||||
// When auto creation is active, we copy a template file.
|
// When auto creation is active, we copy a template file.
|
||||||
// This is the only way to get a disk image which is not only
|
// This is the only way to get a disk image which is not only
|
||||||
// formatted but also has a boot loader which runs "HELLO".
|
// formatted but also has a boot loader which runs "HELLO".
|
||||||
if (autoCreate) {
|
if (autoCreate) {
|
||||||
String resource = "/lib/AppleDos.dsk";
|
String resource = "/lib/AppleDos.dsk";
|
||||||
InputStream inputStream = Disk.class.getClassLoader().getResourceAsStream(resource);
|
InputStream inputStream = Disk.class.getClassLoader().getResourceAsStream(resource);
|
||||||
if (inputStream == null) {
|
if (inputStream == null) {
|
||||||
throw new RuntimeException("Cannot get input stream for '" + resource + "'");
|
throw new RuntimeException("Cannot get input stream for '" + resource + "'");
|
||||||
}
|
}
|
||||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
byte[] buffer = new byte[8192];
|
byte[] buffer = new byte[8192];
|
||||||
int count;
|
int count;
|
||||||
do {
|
do {
|
||||||
try {
|
try {
|
||||||
count = inputStream.read(buffer);
|
count = inputStream.read(buffer);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
throw new RuntimeException("Cannot read input stream for '" + resource + "'", ex);
|
throw new RuntimeException("Cannot read input stream for '" + resource + "'", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count > 0) {
|
||||||
|
bos.write(buffer, 0, count);
|
||||||
|
|
||||||
|
}
|
||||||
|
} while (count > -1);
|
||||||
|
|
||||||
|
try {
|
||||||
|
bos.close();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
throw new RuntimeException(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
FileUtility.writeBytes(imageFile, bos.toByteArray());
|
||||||
|
} catch (CoreException ex) {
|
||||||
|
MarkerUtility.createMarker(files.mainSourceFile.iFile, 0, ex.getStatus().getSeverity(), "{0}",
|
||||||
|
ex.getStatus().getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else { // no auto creation
|
||||||
|
|
||||||
|
// ERROR: Disk image file '{0}' does not exist. Create a
|
||||||
|
// bootable disk image where the output file '{1}' can be
|
||||||
|
// stored.
|
||||||
|
MarkerUtility.createMarker(files.mainSourceFile.iFile, 0, IMarker.SEVERITY_ERROR,
|
||||||
|
Texts.MESSAGE_E132, imageFilePath, outputImageEntryName);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if (!imageFile.canWrite()) {
|
||||||
if (count > 0) {
|
// ERROR: Disk image file '{0}' is not writeable. Make the disk
|
||||||
bos.write(buffer, 0, count);
|
// image file writeable, so the output file '{1}' can be stored.
|
||||||
|
MarkerUtility.createMarker(files.mainSourceFile.iFile, 0, IMarker.SEVERITY_ERROR, Texts.MESSAGE_E133,
|
||||||
|
imageFilePath, outputImageEntryName);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
} while (count > -1);
|
}
|
||||||
|
Disk disk;
|
||||||
try {
|
try {
|
||||||
bos.close();
|
disk = new Disk(imageFilePath);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
throw new RuntimeException(ex);
|
// ERROR: Disk image file '{0}' cannot be opened for reading. System
|
||||||
}
|
// error: {1}
|
||||||
|
MarkerUtility.createMarker(files.mainSourceFile.iFile, 0, IMarker.SEVERITY_ERROR, Texts.MESSAGE_E134,
|
||||||
try {
|
imageFilePath, ex.getMessage());
|
||||||
FileUtility.writeBytes(imageFile, bos.toByteArray());
|
|
||||||
} catch (CoreException ex) {
|
|
||||||
MarkerUtility.createMarker(files.mainSourceFile.iFile, 0, ex.getStatus().getSeverity(), "{0}",
|
|
||||||
ex.getStatus().getMessage());
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
} else { // no auto creation
|
|
||||||
|
|
||||||
// ERROR: Disk image file '{0}' does not exist. Create a
|
|
||||||
// bootable disk image where the output file '{1}' can be
|
|
||||||
// stored.
|
|
||||||
MarkerUtility.createMarker(files.mainSourceFile.iFile, 0, IMarker.SEVERITY_ERROR,
|
|
||||||
Texts.MESSAGE_E132, imageFilePath, outputImageEntryName);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (!imageFile.canWrite()) {
|
|
||||||
// ERROR: Disk image file '{0}' is not writeable. Make the disk
|
|
||||||
// image file writeable, so the output file '{1}' can be stored.
|
|
||||||
MarkerUtility.createMarker(files.mainSourceFile.iFile, 0, IMarker.SEVERITY_ERROR, Texts.MESSAGE_E133,
|
|
||||||
imageFilePath, outputImageEntryName);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Disk disk;
|
|
||||||
try {
|
|
||||||
disk = new Disk(imageFilePath);
|
|
||||||
} catch (IOException ex) {
|
|
||||||
// ERROR: Disk image file '{0}' cannot be opened for reading. System
|
|
||||||
// error: {1}
|
|
||||||
MarkerUtility.createMarker(files.mainSourceFile.iFile, 0, IMarker.SEVERITY_ERROR, Texts.MESSAGE_E134,
|
|
||||||
imageFilePath, ex.getMessage());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
FormattedDisk[] formattedDisks = disk.getFormattedDisks();
|
FormattedDisk[] formattedDisks = disk.getFormattedDisks();
|
||||||
if (formattedDisks == null || formattedDisks.length == 0) {
|
if (formattedDisks == null || formattedDisks.length == 0) {
|
||||||
// ERROR: Disk image file '{0}' does not contain a valid file
|
// ERROR: Disk image file '{0}' does not contain a valid file
|
||||||
// system. Make sure the disk image is properly formatted, so
|
// system. Make sure the disk image is properly formatted, so
|
||||||
// the output file '{1}' can be stored.
|
// the output file '{1}' can be stored.
|
||||||
MarkerUtility.createMarker(files.mainSourceFile.iFile, 0, IMarker.SEVERITY_ERROR, Texts.MESSAGE_E135,
|
MarkerUtility.createMarker(files.mainSourceFile.iFile, 0, IMarker.SEVERITY_ERROR, Texts.MESSAGE_E135,
|
||||||
imageFilePath, outputImageEntryName);
|
imageFilePath, outputImageEntryName);
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
byte[] outputFileContent;
|
|
||||||
try {
|
|
||||||
outputFileContent = FileUtility.readBytes(files.outputFile, 65536, true);
|
|
||||||
} catch (CoreException ex) {
|
|
||||||
// ERROR: Cannot read output file.
|
|
||||||
MarkerUtility.createMarker(files.mainSourceFile.iFile, 0, ex.getStatus().getSeverity(), "{0}", ex
|
|
||||||
.getStatus().getMessage());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
FormattedDisk formattedDisk;
|
|
||||||
try {
|
|
||||||
formattedDisk = formattedDisks[0];
|
|
||||||
// Create HELLO with dummy address.
|
|
||||||
createHello(formattedDisk, outputImageEntryName, outputImageEntryTitle, 1234);
|
|
||||||
|
|
||||||
FileEntry entry = formattedDisk.getFile(outputImageEntryName);
|
|
||||||
if (entry == null) {
|
|
||||||
entry = formattedDisk.createFile();
|
|
||||||
// TODO This is required due to a BUG in AppleCommander
|
|
||||||
entry.setFilename(outputImageEntryName);
|
|
||||||
}
|
|
||||||
entry.setFiletype("B");
|
|
||||||
|
|
||||||
String fileName = files.outputFileName.toLowerCase();
|
|
||||||
int length = outputFileContent.length;
|
|
||||||
byte[] content = outputFileContent;
|
|
||||||
if (entry.needsAddress()) {
|
|
||||||
int address;
|
|
||||||
if (fileName.endsWith(".b") && length > 4) {
|
|
||||||
// // AppleDos 3.3 binary file:
|
|
||||||
// start-lo,start-hi,length-lo,length-hi,data
|
|
||||||
address = getWord(outputFileContent, 0);
|
|
||||||
length = length - 4;
|
|
||||||
content = getData(outputFileContent, 4);
|
|
||||||
} else if (fileName.endsWith(".prg") && length > 2) {
|
|
||||||
// C64 program file
|
|
||||||
// start-lo,start-hi,data
|
|
||||||
address = getWord(outputFileContent, 0);
|
|
||||||
length = length - 2;
|
|
||||||
content = getData(outputFileContent, 2);
|
|
||||||
} else if (fileName.endsWith(".xex") && length > 6
|
|
||||||
&& ((getWord(outputFileContent, 0) & 0xffff) == 0xffff)) {
|
|
||||||
// AtariDOS 2.5 binary file:
|
|
||||||
// $ff,$ff,start-lo,start-hi,end-lo,end-hi,data
|
|
||||||
address = getWord(outputFileContent, 2);
|
|
||||||
length = length - 6;
|
|
||||||
content = getData(outputFileContent, 6);
|
|
||||||
} else {
|
|
||||||
// ERROR: Output file {0} has unknown executable file
|
|
||||||
// extension or content. File extensions ".b", ".prg" and
|
|
||||||
// ".xex" are allowed.
|
|
||||||
MarkerUtility.createMarker(files.mainSourceFile.iFile, 0, IMarker.SEVERITY_ERROR,
|
|
||||||
Texts.MESSAGE_E138, files.outputFilePath);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
// Method setAddress must be called after method setFileData!
|
|
||||||
entry.setFileData(content);
|
|
||||||
entry.setAddress(address);
|
|
||||||
// Update HELLO with acual start address.
|
|
||||||
createHello(formattedDisk, outputImageEntryName, outputImageEntryTitle, address);
|
|
||||||
} else {
|
|
||||||
entry.setFileData(outputFileContent);
|
|
||||||
|
|
||||||
}
|
byte[] outputFileContent;
|
||||||
|
try {
|
||||||
|
outputFileContent = FileUtility.readBytes(files.outputFile, 65536, true);
|
||||||
|
} catch (CoreException ex) {
|
||||||
|
// ERROR: Cannot read output file.
|
||||||
|
MarkerUtility.createMarker(files.mainSourceFile.iFile, 0, ex.getStatus().getSeverity(), "{0}",
|
||||||
|
ex.getStatus().getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
} catch (DiskFullException ex) {
|
FormattedDisk formattedDisk;
|
||||||
// ERROR: Disk image file '{0}' is full. System
|
try {
|
||||||
// error: {1}
|
formattedDisk = formattedDisks[0];
|
||||||
MarkerUtility.createMarker(files.mainSourceFile.iFile, 0, IMarker.SEVERITY_ERROR, Texts.MESSAGE_E136,
|
// Create HELLO with dummy address.
|
||||||
imageFilePath, ex.getMessage());
|
createHello(formattedDisk, outputImageEntryName, outputImageEntryTitle, 1234);
|
||||||
return false;
|
|
||||||
|
FileEntry entry = formattedDisk.getFile(outputImageEntryName);
|
||||||
|
if (entry == null) {
|
||||||
|
entry = formattedDisk.createFile();
|
||||||
|
// TODO This is required due to a BUG in AppleCommander
|
||||||
|
entry.setFilename(outputImageEntryName);
|
||||||
|
}
|
||||||
|
entry.setFiletype("B");
|
||||||
|
|
||||||
|
String fileName = files.outputFileName.toLowerCase();
|
||||||
|
int length = outputFileContent.length;
|
||||||
|
byte[] content = outputFileContent;
|
||||||
|
if (entry.needsAddress()) {
|
||||||
|
int address;
|
||||||
|
if (fileName.endsWith(".b") && length > 4) {
|
||||||
|
// // AppleDos 3.3 binary file:
|
||||||
|
// start-lo,start-hi,length-lo,length-hi,data
|
||||||
|
address = getWord(outputFileContent, 0);
|
||||||
|
length = length - 4;
|
||||||
|
content = getData(outputFileContent, 4);
|
||||||
|
} else if (fileName.endsWith(".prg") && length > 2) {
|
||||||
|
// C64 program file
|
||||||
|
// start-lo,start-hi,data
|
||||||
|
address = getWord(outputFileContent, 0);
|
||||||
|
length = length - 2;
|
||||||
|
content = getData(outputFileContent, 2);
|
||||||
|
} else if (fileName.endsWith(".xex") && length > 6
|
||||||
|
&& ((getWord(outputFileContent, 0) & 0xffff) == 0xffff)) {
|
||||||
|
// AtariDOS 2.5 binary file:
|
||||||
|
// $ff,$ff,start-lo,start-hi,end-lo,end-hi,data
|
||||||
|
address = getWord(outputFileContent, 2);
|
||||||
|
length = length - 6;
|
||||||
|
content = getData(outputFileContent, 6);
|
||||||
|
} else {
|
||||||
|
// ERROR: Output file {0} has unknown executable file
|
||||||
|
// extension or content. File extensions ".b", ".prg" and
|
||||||
|
// ".xex" are allowed.
|
||||||
|
MarkerUtility.createMarker(files.mainSourceFile.iFile, 0, IMarker.SEVERITY_ERROR,
|
||||||
|
Texts.MESSAGE_E138, files.outputFilePath);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Method setAddress must be called after method setFileData!
|
||||||
|
entry.setFileData(content);
|
||||||
|
entry.setAddress(address);
|
||||||
|
// Update HELLO with actual start address.
|
||||||
|
createHello(formattedDisk, outputImageEntryName, outputImageEntryTitle, address);
|
||||||
|
} else {
|
||||||
|
entry.setFileData(outputFileContent);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (DiskFullException ex) {
|
||||||
|
// ERROR: Disk image file '{0}' is full. System
|
||||||
|
// error: {1}
|
||||||
|
MarkerUtility.createMarker(files.mainSourceFile.iFile, 0, IMarker.SEVERITY_ERROR, Texts.MESSAGE_E136,
|
||||||
|
imageFilePath, ex.getMessage());
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
formattedDisk.save();
|
||||||
|
|
||||||
|
} catch (IOException ex) {
|
||||||
|
|
||||||
|
// ERROR: Disk image file '{0}' cannot be opened for writing. System
|
||||||
|
// error: {1}
|
||||||
|
MarkerUtility.createMarker(files.mainSourceFile.iFile, 0, IMarker.SEVERITY_ERROR, Texts.MESSAGE_E137,
|
||||||
|
imageFilePath, ex.getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
private static FileEntry createHello(FormattedDisk formattedDisk, String outputImageEntryName,
|
||||||
formattedDisk.save();
|
String outputImageEntryTitle, int runAddress) throws DiskFullException {
|
||||||
|
if (formattedDisk == null) {
|
||||||
|
throw new IllegalArgumentException("Parameter 'formattedDisk' must not be null.");
|
||||||
|
}
|
||||||
|
if (outputImageEntryName == null) {
|
||||||
|
throw new IllegalArgumentException("Parameter 'OUTPUT_IMAGE_ENTRY_NAME' must not be null.");
|
||||||
|
}
|
||||||
|
if (StringUtility.isEmpty(outputImageEntryName)) {
|
||||||
|
throw new IllegalArgumentException("Parameter 'OUTPUT_IMAGE_ENTRY_NAME' must not be empty.");
|
||||||
|
}
|
||||||
|
if (outputImageEntryTitle == null) {
|
||||||
|
throw new IllegalArgumentException("Parameter 'outputImageEntryTitle' must not be null.");
|
||||||
|
}
|
||||||
|
FileEntry entry;
|
||||||
|
|
||||||
} catch (IOException ex) {
|
entry = formattedDisk.getFile(HELLO_ENTRY_NAME);
|
||||||
|
if (entry == null) {
|
||||||
|
entry = formattedDisk.createFile();
|
||||||
|
entry.setFilename(HELLO_ENTRY_NAME);
|
||||||
|
}
|
||||||
|
entry.setFiletype("A");
|
||||||
|
byte[] program;
|
||||||
|
try {
|
||||||
|
// See "Beneath Apple DOS.pdf", 4-11/12 for the binary and AppleSoft
|
||||||
|
// file format.
|
||||||
|
// See http://www.textfiles.com/apple/ANATOMY/cmd.brun.bload.txt for
|
||||||
|
// the bug in the BRUN routine. Instead of BRUN now BLOAD is sent to
|
||||||
|
// DOS via PRINT CHR$(4) and the program is started via CALL.
|
||||||
|
// 10 PRINT "LOADING <title>" : PRINT CHR$(4);"BRUN WORLD" : CALL
|
||||||
|
// <address>
|
||||||
|
|
||||||
// ERROR: Disk image file '{0}' cannot be opened for writing. System
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
// error: {1}
|
bos.write(new byte[] { 0x00, 0x08, 0x0A, 0x00 });
|
||||||
MarkerUtility.createMarker(files.mainSourceFile.iFile, 0, IMarker.SEVERITY_ERROR, Texts.MESSAGE_E137,
|
bos.write(new byte[] { AppleSoftTokens.PRINT, '"' });
|
||||||
imageFilePath, ex.getMessage());
|
bos.write(outputImageEntryTitle.getBytes("US-ASCII"));
|
||||||
return false;
|
bos.write(new byte[] { '"', ':' });
|
||||||
|
bos.write(new byte[] { AppleSoftTokens.PRINT, AppleSoftTokens.CHRS, '(', '4', ')', ';', '"', 'B', 'L', 'O',
|
||||||
|
'A', 'D', ' ' });
|
||||||
|
bos.write(outputImageEntryName.getBytes("US-ASCII"));
|
||||||
|
bos.write(new byte[] { '"', ':', AppleSoftTokens.CALL });
|
||||||
|
bos.write(Integer.toString(runAddress).getBytes("US-ASCII"));
|
||||||
|
bos.write(new byte[] { 0, 0, 0 });
|
||||||
|
program = bos.toByteArray();
|
||||||
|
program[0] = (byte) (program.length);
|
||||||
|
} catch (UnsupportedEncodingException ex) {
|
||||||
|
throw new RuntimeException(ex);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
throw new RuntimeException(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Byte is the line length in bytes
|
||||||
|
entry.setFileData(program);
|
||||||
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
private static int getWord(byte[] bytes, int index) {
|
||||||
|
if (bytes == null) {
|
||||||
|
throw new IllegalArgumentException("Parameter 'bytes' must not be null.");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
return (0xff & bytes[index]) + 256 * (0xff & bytes[index + 1]);
|
||||||
|
|
||||||
private static FileEntry createHello(FormattedDisk formattedDisk, String outputImageEntryName,
|
|
||||||
String outputImageEntryTitle, int runAddress) throws DiskFullException {
|
|
||||||
if (formattedDisk == null) {
|
|
||||||
throw new IllegalArgumentException("Parameter 'formattedDisk' must not be null.");
|
|
||||||
}
|
|
||||||
if (outputImageEntryName == null) {
|
|
||||||
throw new IllegalArgumentException("Parameter 'OUTPUT_IMAGE_ENTRY_NAME' must not be null.");
|
|
||||||
}
|
|
||||||
if (StringUtility.isEmpty(outputImageEntryName)) {
|
|
||||||
throw new IllegalArgumentException("Parameter 'OUTPUT_IMAGE_ENTRY_NAME' must not be empty.");
|
|
||||||
}
|
|
||||||
if (outputImageEntryTitle == null) {
|
|
||||||
throw new IllegalArgumentException("Parameter 'outputImageEntryTitle' must not be null.");
|
|
||||||
}
|
|
||||||
FileEntry entry;
|
|
||||||
|
|
||||||
entry = formattedDisk.getFile(HELLO_ENTRY_NAME);
|
|
||||||
if (entry == null) {
|
|
||||||
entry = formattedDisk.createFile();
|
|
||||||
entry.setFilename(HELLO_ENTRY_NAME);
|
|
||||||
}
|
|
||||||
entry.setFiletype("A");
|
|
||||||
byte[] program;
|
|
||||||
try {
|
|
||||||
// See "Beneath Apple DOS.pdf", 4-11/12 for the binary and AppleSoft
|
|
||||||
// file format.
|
|
||||||
// See http://www.textfiles.com/apple/ANATOMY/cmd.brun.bload.txt for
|
|
||||||
// the bug in the BRUN routine. Instead of BRUN now BLOAD is sent to
|
|
||||||
// DOS via PRINT CHR$(4) and the program is started via CALL.
|
|
||||||
// 10 PRINT "LOADING <title>" : PRINT CHR$(4);"BRUN WORLD" : CALL
|
|
||||||
// <address>
|
|
||||||
|
|
||||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
|
||||||
bos.write(new byte[] { 0x00, 0x08, 0x0A, 0x00 });
|
|
||||||
bos.write(new byte[] { AppleSoftTokens.PRINT, '"' });
|
|
||||||
bos.write(outputImageEntryTitle.getBytes("US-ASCII"));
|
|
||||||
bos.write(new byte[] { '"', ':' });
|
|
||||||
bos.write(new byte[] { AppleSoftTokens.PRINT, AppleSoftTokens.CHRS, '(', '4', ')', ';', '"', 'B', 'L', 'O',
|
|
||||||
'A', 'D', ' ' });
|
|
||||||
bos.write(outputImageEntryName.getBytes("US-ASCII"));
|
|
||||||
bos.write(new byte[] { '"', ':', AppleSoftTokens.CALL });
|
|
||||||
bos.write(Integer.toString(runAddress).getBytes("US-ASCII"));
|
|
||||||
bos.write(new byte[] { 0, 0, 0 });
|
|
||||||
program = bos.toByteArray();
|
|
||||||
program[0] = (byte) (program.length);
|
|
||||||
} catch (UnsupportedEncodingException ex) {
|
|
||||||
throw new RuntimeException(ex);
|
|
||||||
} catch (IOException ex) {
|
|
||||||
throw new RuntimeException(ex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Byte is the line length in bytes
|
private static byte[] getData(byte[] bytes, int index) {
|
||||||
entry.setFileData(program);
|
if (bytes == null) {
|
||||||
return entry;
|
throw new IllegalArgumentException("Parameter 'bytes' must not be null.");
|
||||||
}
|
}
|
||||||
|
int length = bytes.length - index;
|
||||||
private static int getWord(byte[] bytes, int index) {
|
byte[] result = new byte[length];
|
||||||
if (bytes == null) {
|
System.arraycopy(bytes, index, result, 0, length);
|
||||||
throw new IllegalArgumentException("Parameter 'bytes' must not be null.");
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (0xff & bytes[index]) + 256 * (0xff & bytes[index + 1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static byte[] getData(byte[] bytes, int index) {
|
|
||||||
if (bytes == null) {
|
|
||||||
throw new IllegalArgumentException("Parameter 'bytes' must not be null.");
|
|
||||||
}
|
|
||||||
int length = bytes.length - index;
|
|
||||||
byte[] result = new byte[length];
|
|
||||||
System.arraycopy(bytes, index, result, 0, length);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,485 +75,478 @@ import com.wudsn.ide.base.common.Profiler;
|
||||||
*/
|
*/
|
||||||
public abstract class AssemblerEditor extends TextEditor {
|
public abstract class AssemblerEditor extends TextEditor {
|
||||||
|
|
||||||
private AssemblerPlugin plugin;
|
private AssemblerPlugin plugin;
|
||||||
private AssemblerEditorFilesLogic filesLogic;
|
private AssemblerEditorFilesLogic filesLogic;
|
||||||
|
|
||||||
private Compiler compiler;
|
private Compiler compiler;
|
||||||
|
|
||||||
private AssemblerContentOutlinePage contentOutlinePage;
|
private AssemblerContentOutlinePage contentOutlinePage;
|
||||||
private ProjectionAnnotationModel annotationModel;
|
private ProjectionAnnotationModel annotationModel;
|
||||||
|
|
||||||
private Hardware hardware;
|
private Hardware hardware;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance. Constructor parameters are not useful, because
|
* Creates a new instance. Constructor parameters are not useful, because the
|
||||||
* the super constructor inverts the flow of control, so
|
* super constructor inverts the flow of control, so {@link #initializeEditor}
|
||||||
* {@link #initializeEditor} is called before the code in this constructor
|
* is called before the code in this constructor is executed.
|
||||||
* is executed.
|
*/
|
||||||
*/
|
protected AssemblerEditor() {
|
||||||
protected AssemblerEditor() {
|
filesLogic = AssemblerEditorFilesLogic.createInstance(this);
|
||||||
filesLogic = AssemblerEditorFilesLogic.createInstance(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the files logic associated with this editor.
|
|
||||||
*
|
|
||||||
* @return The files logic, not <code>null</code>.
|
|
||||||
*/
|
|
||||||
public AssemblerEditorFilesLogic getFilesLogic() {
|
|
||||||
return filesLogic;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the hardware for this editor.
|
|
||||||
*
|
|
||||||
* @return The hardware for this editor, not <code>null</code>.
|
|
||||||
*
|
|
||||||
* @since 1.6.1
|
|
||||||
*/
|
|
||||||
protected final Hardware getHardware() {
|
|
||||||
if (hardware != null) {
|
|
||||||
return hardware;
|
|
||||||
}
|
}
|
||||||
return compiler.getDefinition().getDefaultHardware();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the compiler id for this editor.
|
* Gets the files logic associated with this editor.
|
||||||
*
|
*
|
||||||
* @return The compiler id for this editor, not empty and not
|
* @return The files logic, not <code>null</code>.
|
||||||
* <code>null</code>.
|
*/
|
||||||
*/
|
public AssemblerEditorFilesLogic getFilesLogic() {
|
||||||
protected abstract String getCompilerId();
|
return filesLogic;
|
||||||
|
|
||||||
@Override
|
|
||||||
protected final void initializeEditor() {
|
|
||||||
super.initializeEditor();
|
|
||||||
|
|
||||||
plugin = AssemblerPlugin.getInstance();
|
|
||||||
compiler = plugin.getCompilerRegistry().getCompiler(getCompilerId());
|
|
||||||
|
|
||||||
setSourceViewerConfiguration(new AssemblerSourceViewerConfiguration(this, getPreferenceStore()));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the plugin this compiler instance belongs to.
|
|
||||||
*
|
|
||||||
* @return The plugin this compiler instance belongs to, not
|
|
||||||
* <code>null</code>.
|
|
||||||
*/
|
|
||||||
public final AssemblerPlugin getPlugin() {
|
|
||||||
if (plugin == null) {
|
|
||||||
throw new IllegalStateException("Field 'plugin' must not be null.");
|
|
||||||
}
|
}
|
||||||
return plugin;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the compiler preferences.
|
* Gets the hardware for this editor.
|
||||||
*
|
*
|
||||||
* @return The compiler preferences, not <code>null</code>.
|
* @return The hardware for this editor, not <code>null</code>.
|
||||||
*/
|
*
|
||||||
public final CompilerPreferences getCompilerPreferences() {
|
* @since 1.6.1
|
||||||
return plugin.getPreferences().getCompilerPreferences(getCompilerId(), getHardware());
|
*/
|
||||||
}
|
protected final Hardware getHardware() {
|
||||||
|
if (hardware != null) {
|
||||||
/**
|
return hardware;
|
||||||
* Gets the compiler for this editor.
|
|
||||||
*
|
|
||||||
* @return The compiler for this editor, not <code>null</code>.
|
|
||||||
*/
|
|
||||||
public final Compiler getCompiler() {
|
|
||||||
if (compiler == null) {
|
|
||||||
throw new IllegalStateException("Field 'compiler' must not be null.");
|
|
||||||
}
|
|
||||||
return compiler;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the compiler definition for this editor.
|
|
||||||
*
|
|
||||||
* @return The compiler definition for this editor, not <code>null</code>.
|
|
||||||
*
|
|
||||||
* @sine 1.6.1
|
|
||||||
*/
|
|
||||||
public final CompilerDefinition getCompilerDefinition() {
|
|
||||||
if (compiler == null) {
|
|
||||||
throw new IllegalStateException("Field 'compiler' must not be null.");
|
|
||||||
}
|
|
||||||
return compiler.getDefinition();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the compiler source parser for this editor and the currently
|
|
||||||
* selected instruction set.
|
|
||||||
*
|
|
||||||
* @return The compiler source parser for this editor, not <code>null</code>
|
|
||||||
* .
|
|
||||||
*/
|
|
||||||
public final CompilerSourceParser createCompilerSourceParser() {
|
|
||||||
CPU cpu;
|
|
||||||
CompilerSourceParser result;
|
|
||||||
if (compiler == null) {
|
|
||||||
throw new IllegalStateException("Field 'compiler' must not be null.");
|
|
||||||
}
|
|
||||||
cpu = getCompilerPreferences().getCPU();
|
|
||||||
result = compiler.createSourceParser();
|
|
||||||
result.init(compiler.getDefinition().getSyntax().getInstructionSet(cpu));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method is called whenever the input changes, i.e. after loading and
|
|
||||||
* after saving as new file.
|
|
||||||
*
|
|
||||||
* @param input
|
|
||||||
* The new input, may be <code>null</code>
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected final void doSetInput(IEditorInput input) throws CoreException {
|
|
||||||
super.doSetInput(input);
|
|
||||||
|
|
||||||
hardware = null;
|
|
||||||
if (input != null) {
|
|
||||||
IDocument document = getDocumentProvider().getDocument(getEditorInput());
|
|
||||||
|
|
||||||
CompilerSourcePartitionScanner partitionScanner = new CompilerSourcePartitionScanner(compiler
|
|
||||||
.getDefinition().getSyntax());
|
|
||||||
partitionScanner.createDocumentPartitioner(document);
|
|
||||||
|
|
||||||
AssemblerProperties properties = CompilerSourceParser.getDocumentProperties(document);
|
|
||||||
|
|
||||||
IFile iFile = getCurrentIFile();
|
|
||||||
if (iFile != null) {
|
|
||||||
try {
|
|
||||||
hardware = filesLogic.getHardware(iFile, properties);
|
|
||||||
} catch (InvalidAssemblerPropertyException ex) {
|
|
||||||
// Do not use MarkerUtility.gotoMarker to make sure this
|
|
||||||
// editor instance is used.
|
|
||||||
IDE.gotoMarker(this, ex.marker);
|
|
||||||
hardware = null;
|
|
||||||
}
|
}
|
||||||
}
|
return compiler.getDefinition().getDefaultHardware();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
/**
|
||||||
|
* Gets the compiler id for this editor.
|
||||||
|
*
|
||||||
|
* @return The compiler id for this editor, not empty and not <code>null</code>.
|
||||||
|
*/
|
||||||
|
protected abstract String getCompilerId();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected final void createActions() {
|
protected final void initializeEditor() {
|
||||||
super.createActions();
|
super.initializeEditor();
|
||||||
|
|
||||||
ResourceBundle bundle = ResourceBundle.getBundle("com.wudsn.ide.asm.Actions", Locale.getDefault(),
|
plugin = AssemblerPlugin.getInstance();
|
||||||
AssemblerEditor.class.getClassLoader());
|
compiler = plugin.getCompilerRegistry().getCompiler(getCompilerId());
|
||||||
|
|
||||||
String actionDefintionId;
|
setSourceViewerConfiguration(new AssemblerSourceViewerConfiguration(this, getPreferenceStore()));
|
||||||
String actionId;
|
|
||||||
actionDefintionId = ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS;
|
|
||||||
actionId = "com.wudsn.ide.asm.editor.ContentAssistProposal";
|
|
||||||
IAction action = new TextOperationAction(bundle, actionId + ".", this, ISourceViewer.CONTENTASSIST_PROPOSALS);
|
|
||||||
action.setActionDefinitionId(actionDefintionId);
|
|
||||||
setAction(actionId, action);
|
|
||||||
markAsStateDependentAction(actionId, true);
|
|
||||||
|
|
||||||
SourceViewer sourceViewer = (SourceViewer) getSourceViewer();
|
|
||||||
actionDefintionId = "com.wudsn.ide.asm.editor.AssemblerEditorToggleCommentCommand";
|
|
||||||
actionId = actionDefintionId;
|
|
||||||
action = new AssemblerEditorToggleCommentAction(bundle, actionId + ".", this, sourceViewer);
|
|
||||||
action.setActionDefinitionId(actionId);
|
|
||||||
setAction(actionId, action);
|
|
||||||
markAsStateDependentAction(actionId, true);
|
|
||||||
|
|
||||||
// Register rule double click.
|
|
||||||
ToggleBreakpointAction toggleBreakpointAction;
|
|
||||||
actionDefintionId = "org.eclipse.debug.ui.commands.ToggleBreakpoint";
|
|
||||||
actionId = "RulerDoubleClick";
|
|
||||||
action.setActionDefinitionId(actionId);
|
|
||||||
toggleBreakpointAction = new ToggleBreakpointAction(this, getDocumentProvider().getDocument(getEditorInput()),
|
|
||||||
getVerticalRuler());
|
|
||||||
toggleBreakpointAction.setId(actionId);
|
|
||||||
setAction(actionId, toggleBreakpointAction);
|
|
||||||
markAsStateDependentAction(actionId, true);
|
|
||||||
toggleBreakpointAction.update();
|
|
||||||
}
|
|
||||||
|
|
||||||
final ISourceViewer getSourceViewerInternal() {
|
|
||||||
return getSourceViewer();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Refreshes the editor after changes to the text attributes or the text
|
|
||||||
* content.
|
|
||||||
*
|
|
||||||
* Called by {@link #updateIdentifiers(CompilerSourceFile)} and
|
|
||||||
* {@link AssemblerSourceViewerConfiguration#preferencesChanged(com.wudsn.ide.asm.preferences.AssemblerPreferences, java.util.Set)}
|
|
||||||
* .
|
|
||||||
*/
|
|
||||||
final void refreshSourceViewer() {
|
|
||||||
ISourceViewer isv = getSourceViewer();
|
|
||||||
if (isv instanceof SourceViewer) {
|
|
||||||
((SourceViewer) getSourceViewer()).invalidateTextPresentation();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final void dispose() {
|
|
||||||
AssemblerSourceViewerConfiguration asvc;
|
|
||||||
asvc = (AssemblerSourceViewerConfiguration) getSourceViewerConfiguration();
|
|
||||||
asvc.dispose();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
@Override
|
|
||||||
public <T> T getAdapter(Class<T> adapter) {
|
|
||||||
if (IContentOutlinePage.class.equals(adapter)) {
|
|
||||||
if (contentOutlinePage == null) {
|
|
||||||
contentOutlinePage = new AssemblerContentOutlinePage(this);
|
|
||||||
// This causes double parsing upon starting with a new file
|
|
||||||
// currently.
|
|
||||||
updateContentOutlinePage();
|
|
||||||
}
|
|
||||||
return (T)contentOutlinePage;
|
|
||||||
}
|
|
||||||
return super.getAdapter(adapter);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the content in view of the outline page. Called by
|
|
||||||
* {@link AssemblerReconcilingStategy#parse}.
|
|
||||||
*/
|
|
||||||
final void updateContentOutlinePage() {
|
|
||||||
if (contentOutlinePage != null) {
|
|
||||||
IEditorInput input = getEditorInput();
|
|
||||||
|
|
||||||
if (input != null) {
|
|
||||||
contentOutlinePage.setInput(input);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the compiler source file of the last parse process.
|
|
||||||
*
|
|
||||||
* @return The compiler source file of the last parse process or
|
|
||||||
* <code>null</code>.
|
|
||||||
*/
|
|
||||||
final CompilerSourceFile getCompilerSourceFile() {
|
|
||||||
CompilerSourceFile result;
|
|
||||||
if (contentOutlinePage != null) {
|
|
||||||
result = contentOutlinePage.getCompilerSourceFile();
|
|
||||||
} else {
|
|
||||||
result = null;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final void createPartControl(Composite parent) {
|
|
||||||
if (parent == null) {
|
|
||||||
throw new IllegalArgumentException("Parameter 'parent' must not be null.");
|
|
||||||
}
|
|
||||||
super.createPartControl(parent);
|
|
||||||
ProjectionViewer viewer = (ProjectionViewer) getSourceViewer();
|
|
||||||
|
|
||||||
ProjectionSupport projectionSupport = new ProjectionSupport(viewer, getAnnotationAccess(), getSharedColors());
|
|
||||||
projectionSupport.install();
|
|
||||||
|
|
||||||
// turn projection mode on
|
|
||||||
viewer.doOperation(ProjectionViewer.TOGGLE);
|
|
||||||
|
|
||||||
annotationModel = viewer.getProjectionAnnotationModel();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected final ISourceViewer createSourceViewer(Composite parent, IVerticalRuler ruler, int styles) {
|
|
||||||
if (parent == null) {
|
|
||||||
throw new IllegalArgumentException("Parameter 'parent' must not be null.");
|
|
||||||
}
|
|
||||||
if (ruler == null) {
|
|
||||||
throw new IllegalArgumentException("Parameter 'ruler' must not be null.");
|
|
||||||
}
|
|
||||||
ISourceViewer viewer = new ProjectionViewer(parent, ruler, getOverviewRuler(), isOverviewRulerVisible(), styles);
|
|
||||||
|
|
||||||
// Ensure decoration support has been created and configured.
|
|
||||||
getSourceViewerDecorationSupport(viewer);
|
|
||||||
|
|
||||||
// The first single line comment delimiter is used as the default.
|
|
||||||
List<String> singleLineCommentDelimiters = compiler.getDefinition().getSyntax()
|
|
||||||
.getSingleLineCommentDelimiters();
|
|
||||||
String[] array = singleLineCommentDelimiters.toArray(new String[singleLineCommentDelimiters.size()]);
|
|
||||||
viewer.setDefaultPrefixes(array, IDocument.DEFAULT_CONTENT_TYPE);
|
|
||||||
viewer.setDefaultPrefixes(array, CompilerSourcePartitionScanner.PARTITION_COMMENT_SINGLE);
|
|
||||||
|
|
||||||
return viewer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the identifiers to be highlighted
|
|
||||||
*
|
|
||||||
* @param compilerSourceFile
|
|
||||||
* The compiler source file or <code>null</code>.
|
|
||||||
*/
|
|
||||||
final void updateIdentifiers(CompilerSourceFile compilerSourceFile) {
|
|
||||||
Profiler profiler = new Profiler(this.getClass());
|
|
||||||
|
|
||||||
AssemblerSourceViewerConfiguration asvc;
|
|
||||||
AssemblerSourceScanner ais;
|
|
||||||
asvc = (AssemblerSourceViewerConfiguration) getSourceViewerConfiguration();
|
|
||||||
ais = asvc.getAssemblerInstructionScanner();
|
|
||||||
|
|
||||||
List<CompilerSourceParserTreeObject> newIdentifiers;
|
|
||||||
if (compilerSourceFile == null) {
|
|
||||||
newIdentifiers = Collections.emptyList();
|
|
||||||
} else {
|
|
||||||
newIdentifiers = compilerSourceFile.getIdentifiers();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ais.setIdentifiers(newIdentifiers);
|
/**
|
||||||
profiler.begin("refreshSourceViewer");
|
* Gets the plugin this compiler instance belongs to.
|
||||||
// refreshSourceViewer();
|
*
|
||||||
profiler.end("refreshSourceViewer");
|
* @return The plugin this compiler instance belongs to, not <code>null</code>.
|
||||||
}
|
*/
|
||||||
|
public final AssemblerPlugin getPlugin() {
|
||||||
/**
|
if (plugin == null) {
|
||||||
* Update the folding structure with a given list of foldingPositions. Used
|
throw new IllegalStateException("Field 'plugin' must not be null.");
|
||||||
* by the editor updater of {@link AssemblerReconcilingStategy}.
|
}
|
||||||
*
|
return plugin;
|
||||||
* @param foldingPositions
|
|
||||||
* The list of foldingPositions, may be empty, not
|
|
||||||
* <code>null</code>.
|
|
||||||
*/
|
|
||||||
final void updateFoldingStructure(List<Position> foldingPositions) {
|
|
||||||
if (foldingPositions == null) {
|
|
||||||
throw new IllegalArgumentException("Parameter 'foldingPositions' must not be null.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a working copy.
|
/**
|
||||||
foldingPositions = new ArrayList<Position>(foldingPositions);
|
* Gets the compiler preferences.
|
||||||
List<ProjectionAnnotation> deletions = new ArrayList<ProjectionAnnotation>();
|
*
|
||||||
Object annotationObject = null;
|
* @return The compiler preferences, not <code>null</code>.
|
||||||
ProjectionAnnotation annotation = null;
|
*/
|
||||||
Position position = null;
|
public final CompilerPreferences getCompilerPreferences() {
|
||||||
|
return plugin.getPreferences().getCompilerPreferences(getCompilerId(), getHardware());
|
||||||
|
}
|
||||||
|
|
||||||
// Access to the annotationModel is intentionally not synchronized, as
|
/**
|
||||||
// otherwise deadlock would be the result.
|
* Gets the compiler for this editor.
|
||||||
for (@SuppressWarnings("rawtypes")
|
*
|
||||||
Iterator iter = annotationModel.getAnnotationIterator(); iter.hasNext();) {
|
* @return The compiler for this editor, not <code>null</code>.
|
||||||
annotationObject = iter.next();
|
*/
|
||||||
|
public final Compiler getCompiler() {
|
||||||
|
if (compiler == null) {
|
||||||
|
throw new IllegalStateException("Field 'compiler' must not be null.");
|
||||||
|
}
|
||||||
|
return compiler;
|
||||||
|
}
|
||||||
|
|
||||||
if (annotationObject instanceof ProjectionAnnotation) {
|
/**
|
||||||
annotation = (ProjectionAnnotation) annotationObject;
|
* Gets the compiler definition for this editor.
|
||||||
|
*
|
||||||
|
* @return The compiler definition for this editor, not <code>null</code>.
|
||||||
|
*
|
||||||
|
* @sine 1.6.1
|
||||||
|
*/
|
||||||
|
public final CompilerDefinition getCompilerDefinition() {
|
||||||
|
if (compiler == null) {
|
||||||
|
throw new IllegalStateException("Field 'compiler' must not be null.");
|
||||||
|
}
|
||||||
|
return compiler.getDefinition();
|
||||||
|
}
|
||||||
|
|
||||||
position = annotationModel.getPosition(annotation);
|
/**
|
||||||
|
* Gets the compiler source parser for this editor and the currently selected
|
||||||
|
* instruction set.
|
||||||
|
*
|
||||||
|
* @return The compiler source parser for this editor, not <code>null</code> .
|
||||||
|
*/
|
||||||
|
public final CompilerSourceParser createCompilerSourceParser() {
|
||||||
|
CPU cpu;
|
||||||
|
CompilerSourceParser result;
|
||||||
|
if (compiler == null) {
|
||||||
|
throw new IllegalStateException("Field 'compiler' must not be null.");
|
||||||
|
}
|
||||||
|
cpu = getCompilerPreferences().getCPU();
|
||||||
|
result = compiler.createSourceParser();
|
||||||
|
result.init(compiler.getDefinition().getSyntax().getInstructionSet(cpu));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
if (foldingPositions.contains(position)) {
|
/**
|
||||||
foldingPositions.remove(position);
|
* This method is called whenever the input changes, i.e. after loading and
|
||||||
|
* after saving as new file.
|
||||||
|
*
|
||||||
|
* @param input The new input, may be <code>null</code>
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected final void doSetInput(IEditorInput input) throws CoreException {
|
||||||
|
super.doSetInput(input);
|
||||||
|
|
||||||
|
hardware = null;
|
||||||
|
if (input != null) {
|
||||||
|
IDocument document = getDocumentProvider().getDocument(getEditorInput());
|
||||||
|
|
||||||
|
CompilerSourcePartitionScanner partitionScanner = new CompilerSourcePartitionScanner(
|
||||||
|
compiler.getDefinition().getSyntax());
|
||||||
|
partitionScanner.createDocumentPartitioner(document);
|
||||||
|
|
||||||
|
AssemblerProperties properties = CompilerSourceParser.getDocumentProperties(document);
|
||||||
|
|
||||||
|
IFile iFile = getCurrentIFile();
|
||||||
|
if (iFile != null) {
|
||||||
|
try {
|
||||||
|
hardware = filesLogic.getHardware(iFile, properties);
|
||||||
|
} catch (InvalidAssemblerPropertyException ex) {
|
||||||
|
// Do not use MarkerUtility.gotoMarker to make sure this
|
||||||
|
// editor instance is used.
|
||||||
|
IDE.gotoMarker(this, ex.marker);
|
||||||
|
hardware = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected final void createActions() {
|
||||||
|
super.createActions();
|
||||||
|
|
||||||
|
ResourceBundle bundle = ResourceBundle.getBundle("com.wudsn.ide.asm.Actions", Locale.getDefault(),
|
||||||
|
AssemblerEditor.class.getClassLoader());
|
||||||
|
|
||||||
|
String actionDefintionId;
|
||||||
|
String actionId;
|
||||||
|
actionDefintionId = ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS;
|
||||||
|
actionId = "com.wudsn.ide.asm.editor.ContentAssistProposal";
|
||||||
|
IAction action = new TextOperationAction(bundle, actionId + ".", this, ISourceViewer.CONTENTASSIST_PROPOSALS);
|
||||||
|
action.setActionDefinitionId(actionDefintionId);
|
||||||
|
setAction(actionId, action);
|
||||||
|
markAsStateDependentAction(actionId, true);
|
||||||
|
|
||||||
|
SourceViewer sourceViewer = (SourceViewer) getSourceViewer();
|
||||||
|
actionDefintionId = "com.wudsn.ide.asm.editor.AssemblerEditorToggleCommentCommand";
|
||||||
|
actionId = actionDefintionId;
|
||||||
|
action = new AssemblerEditorToggleCommentAction(bundle, actionId + ".", this, sourceViewer);
|
||||||
|
action.setActionDefinitionId(actionId);
|
||||||
|
setAction(actionId, action);
|
||||||
|
markAsStateDependentAction(actionId, true);
|
||||||
|
|
||||||
|
// Register rule double click.
|
||||||
|
ToggleBreakpointAction toggleBreakpointAction;
|
||||||
|
actionDefintionId = "org.eclipse.debug.ui.commands.ToggleBreakpoint";
|
||||||
|
actionId = "RulerDoubleClick";
|
||||||
|
action.setActionDefinitionId(actionId);
|
||||||
|
toggleBreakpointAction = new ToggleBreakpointAction(this, getDocumentProvider().getDocument(getEditorInput()),
|
||||||
|
getVerticalRuler());
|
||||||
|
toggleBreakpointAction.setId(actionId);
|
||||||
|
setAction(actionId, toggleBreakpointAction);
|
||||||
|
markAsStateDependentAction(actionId, true);
|
||||||
|
toggleBreakpointAction.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
final ISourceViewer getSourceViewerInternal() {
|
||||||
|
return getSourceViewer();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refreshes the editor after changes to the text attributes or the text
|
||||||
|
* content.
|
||||||
|
*
|
||||||
|
* Called by {@link #updateIdentifiers(CompilerSourceFile)} and
|
||||||
|
* {@link AssemblerSourceViewerConfiguration#preferencesChanged(com.wudsn.ide.asm.preferences.AssemblerPreferences, java.util.Set)}
|
||||||
|
* .
|
||||||
|
*/
|
||||||
|
final void refreshSourceViewer() {
|
||||||
|
ISourceViewer isv = getSourceViewer();
|
||||||
|
if (isv instanceof SourceViewer) {
|
||||||
|
((SourceViewer) getSourceViewer()).invalidateTextPresentation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void dispose() {
|
||||||
|
AssemblerSourceViewerConfiguration asvc;
|
||||||
|
asvc = (AssemblerSourceViewerConfiguration) getSourceViewerConfiguration();
|
||||||
|
asvc.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
public <T> T getAdapter(Class<T> adapter) {
|
||||||
|
if (IContentOutlinePage.class.equals(adapter)) {
|
||||||
|
if (contentOutlinePage == null) {
|
||||||
|
contentOutlinePage = new AssemblerContentOutlinePage(this);
|
||||||
|
// This causes double parsing upon starting with a new file
|
||||||
|
// currently.
|
||||||
|
updateContentOutlinePage();
|
||||||
|
}
|
||||||
|
return (T) contentOutlinePage;
|
||||||
|
}
|
||||||
|
return super.getAdapter(adapter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the content in view of the outline page. Called by
|
||||||
|
* {@link AssemblerReconcilingStategy#parse}.
|
||||||
|
*/
|
||||||
|
final void updateContentOutlinePage() {
|
||||||
|
if (contentOutlinePage != null) {
|
||||||
|
IEditorInput input = getEditorInput();
|
||||||
|
|
||||||
|
if (input != null) {
|
||||||
|
contentOutlinePage.setInput(input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the compiler source file of the last parse process.
|
||||||
|
*
|
||||||
|
* @return The compiler source file of the last parse process or
|
||||||
|
* <code>null</code>.
|
||||||
|
*/
|
||||||
|
final CompilerSourceFile getCompilerSourceFile() {
|
||||||
|
CompilerSourceFile result;
|
||||||
|
if (contentOutlinePage != null) {
|
||||||
|
result = contentOutlinePage.getCompilerSourceFile();
|
||||||
} else {
|
} else {
|
||||||
deletions.add(annotation);
|
result = null;
|
||||||
}
|
}
|
||||||
}
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void createPartControl(Composite parent) {
|
||||||
|
if (parent == null) {
|
||||||
|
throw new IllegalArgumentException("Parameter 'parent' must not be null.");
|
||||||
|
}
|
||||||
|
super.createPartControl(parent);
|
||||||
|
ProjectionViewer viewer = (ProjectionViewer) getSourceViewer();
|
||||||
|
|
||||||
|
ProjectionSupport projectionSupport = new ProjectionSupport(viewer, getAnnotationAccess(), getSharedColors());
|
||||||
|
projectionSupport.install();
|
||||||
|
|
||||||
|
// turn projection mode on
|
||||||
|
viewer.doOperation(ProjectionViewer.TOGGLE);
|
||||||
|
|
||||||
|
annotationModel = viewer.getProjectionAnnotationModel();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Annotation[] removeAnnotations = deletions.toArray(new Annotation[deletions.size()]);
|
@Override
|
||||||
|
protected final ISourceViewer createSourceViewer(Composite parent, IVerticalRuler ruler, int styles) {
|
||||||
|
if (parent == null) {
|
||||||
|
throw new IllegalArgumentException("Parameter 'parent' must not be null.");
|
||||||
|
}
|
||||||
|
if (ruler == null) {
|
||||||
|
throw new IllegalArgumentException("Parameter 'ruler' must not be null.");
|
||||||
|
}
|
||||||
|
ISourceViewer viewer = new ProjectionViewer(parent, ruler, getOverviewRuler(), isOverviewRulerVisible(),
|
||||||
|
styles);
|
||||||
|
|
||||||
// This will hold the new annotations along
|
// Ensure decoration support has been created and configured.
|
||||||
// with their corresponding folding positions.
|
getSourceViewerDecorationSupport(viewer);
|
||||||
HashMap<ProjectionAnnotation, Position> newAnnotations = new HashMap<ProjectionAnnotation, Position>();
|
|
||||||
|
|
||||||
for (int i = 0; i < foldingPositions.size(); i++) {
|
// The first single line comment delimiter is used as the default.
|
||||||
annotation = new ProjectionAnnotation();
|
List<String> singleLineCommentDelimiters = compiler.getDefinition().getSyntax()
|
||||||
newAnnotations.put(annotation, foldingPositions.get(i));
|
.getSingleLineCommentDelimiters();
|
||||||
|
String[] array = singleLineCommentDelimiters.toArray(new String[singleLineCommentDelimiters.size()]);
|
||||||
|
viewer.setDefaultPrefixes(array, IDocument.DEFAULT_CONTENT_TYPE);
|
||||||
|
viewer.setDefaultPrefixes(array, CompilerSourcePartitionScanner.PARTITION_COMMENT_SINGLE);
|
||||||
|
|
||||||
|
return viewer;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do not update anything if there is actual change to preserve the
|
/**
|
||||||
// current cursor positioning.
|
* Update the identifiers to be highlighted
|
||||||
if (removeAnnotations.length == 0 && newAnnotations.isEmpty()) {
|
*
|
||||||
return;
|
* @param compilerSourceFile The compiler source file or <code>null</code>.
|
||||||
|
*/
|
||||||
|
final void updateIdentifiers(CompilerSourceFile compilerSourceFile) {
|
||||||
|
Profiler profiler = new Profiler(this.getClass());
|
||||||
|
|
||||||
|
AssemblerSourceViewerConfiguration asvc;
|
||||||
|
AssemblerSourceScanner ais;
|
||||||
|
asvc = (AssemblerSourceViewerConfiguration) getSourceViewerConfiguration();
|
||||||
|
ais = asvc.getAssemblerInstructionScanner();
|
||||||
|
|
||||||
|
List<CompilerSourceParserTreeObject> newIdentifiers;
|
||||||
|
if (compilerSourceFile == null) {
|
||||||
|
newIdentifiers = Collections.emptyList();
|
||||||
|
} else {
|
||||||
|
newIdentifiers = compilerSourceFile.getIdentifiers();
|
||||||
|
}
|
||||||
|
|
||||||
|
ais.setIdentifiers(newIdentifiers);
|
||||||
|
profiler.begin("refreshSourceViewer");
|
||||||
|
// refreshSourceViewer();
|
||||||
|
profiler.end("refreshSourceViewer");
|
||||||
}
|
}
|
||||||
|
|
||||||
annotationModel.modifyAnnotations(removeAnnotations, newAnnotations, new Annotation[] {});
|
/**
|
||||||
}
|
* Update the folding structure with a given list of foldingPositions. Used by
|
||||||
|
* the editor updater of {@link AssemblerReconcilingStategy}.
|
||||||
|
*
|
||||||
|
* @param foldingPositions The list of foldingPositions, may be empty, not
|
||||||
|
* <code>null</code>.
|
||||||
|
*/
|
||||||
|
final void updateFoldingStructure(List<Position> foldingPositions) {
|
||||||
|
if (foldingPositions == null) {
|
||||||
|
throw new IllegalArgumentException("Parameter 'foldingPositions' must not be null.");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
// Create a working copy.
|
||||||
* Gets the directory of the current file.
|
foldingPositions = new ArrayList<Position>(foldingPositions);
|
||||||
*
|
List<ProjectionAnnotation> deletions = new ArrayList<ProjectionAnnotation>();
|
||||||
* @return The directory of the current file or <code>null</code>.
|
Object annotationObject = null;
|
||||||
*/
|
ProjectionAnnotation annotation = null;
|
||||||
public final File getCurrentDirectory() {
|
Position position = null;
|
||||||
File result;
|
|
||||||
result = getCurrentFile();
|
|
||||||
if (result != null) {
|
|
||||||
result = result.getParentFile();
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
// Access to the annotationModel is intentionally not synchronized, as
|
||||||
* Gets the the current file.
|
// otherwise deadlock would be the result.
|
||||||
*
|
for (@SuppressWarnings("rawtypes")
|
||||||
* @return The current file or <code>null</code>.
|
Iterator iter = annotationModel.getAnnotationIterator(); iter.hasNext();) {
|
||||||
*/
|
annotationObject = iter.next();
|
||||||
public final File getCurrentFile() {
|
|
||||||
File result;
|
|
||||||
IEditorInput editorInput = getEditorInput();
|
|
||||||
if (editorInput instanceof FileEditorInput) {
|
|
||||||
FileEditorInput fileEditorInput = (FileEditorInput) editorInput;
|
|
||||||
result = new File(fileEditorInput.getPath().toOSString());
|
|
||||||
} else {
|
|
||||||
result = null;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
if (annotationObject instanceof ProjectionAnnotation) {
|
||||||
* Gets the the current file.
|
annotation = (ProjectionAnnotation) annotationObject;
|
||||||
*
|
|
||||||
* @return The current file or <code>null</code>.
|
|
||||||
*/
|
|
||||||
public final IFile getCurrentIFile() {
|
|
||||||
IFile result;
|
|
||||||
IEditorInput editorInput = getEditorInput();
|
|
||||||
if (editorInput instanceof FileEditorInput) {
|
|
||||||
FileEditorInput fileEditorInput = (FileEditorInput) editorInput;
|
|
||||||
result = fileEditorInput.getFile();
|
|
||||||
|
|
||||||
} else {
|
position = annotationModel.getPosition(annotation);
|
||||||
result = null;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
if (foldingPositions.contains(position)) {
|
||||||
* Position the cursor to the specified line in the document.
|
foldingPositions.remove(position);
|
||||||
*
|
} else {
|
||||||
* @param line
|
deletions.add(annotation);
|
||||||
* The line number, a positive integer.
|
}
|
||||||
*
|
}
|
||||||
* @return <code>true</code> if the positioning was successful.
|
|
||||||
*/
|
}
|
||||||
public final boolean gotoLine(int line) {
|
|
||||||
if (line < 1) {
|
Annotation[] removeAnnotations = deletions.toArray(new Annotation[deletions.size()]);
|
||||||
throw new IllegalArgumentException("Parameter 'line' must be positive. Specified value is " + line + ".");
|
|
||||||
|
// This will hold the new annotations along
|
||||||
|
// with their corresponding folding positions.
|
||||||
|
HashMap<ProjectionAnnotation, Position> newAnnotations = new HashMap<ProjectionAnnotation, Position>();
|
||||||
|
|
||||||
|
for (int i = 0; i < foldingPositions.size(); i++) {
|
||||||
|
annotation = new ProjectionAnnotation();
|
||||||
|
newAnnotations.put(annotation, foldingPositions.get(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do not update anything if there is actual change to preserve the
|
||||||
|
// current cursor positioning.
|
||||||
|
if (removeAnnotations.length == 0 && newAnnotations.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
annotationModel.modifyAnnotations(removeAnnotations, newAnnotations, new Annotation[] {});
|
||||||
}
|
}
|
||||||
IDocumentProvider provider = getDocumentProvider();
|
|
||||||
IDocument document = provider.getDocument(getEditorInput());
|
/**
|
||||||
boolean result = false;
|
* Gets the directory of the current file.
|
||||||
try {
|
*
|
||||||
int startOffset = document.getLineOffset(line - 1);
|
* @return The directory of the current file or <code>null</code>.
|
||||||
int lineLength = document.getLineLength(line - 1);
|
*/
|
||||||
if (lineLength > 0) {
|
public final File getCurrentDirectory() {
|
||||||
lineLength = lineLength - 1;
|
File result;
|
||||||
}
|
result = getCurrentFile();
|
||||||
selectAndReveal(startOffset, lineLength);
|
if (result != null) {
|
||||||
result = true;
|
result = result.getParentFile();
|
||||||
} catch (BadLocationException ex) {
|
}
|
||||||
plugin.logError("Cannot position to line {0}.", new Object[] { String.valueOf(line) }, ex);
|
return result;
|
||||||
result = false;
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the the current file.
|
||||||
|
*
|
||||||
|
* @return The current file or <code>null</code>.
|
||||||
|
*/
|
||||||
|
public final File getCurrentFile() {
|
||||||
|
File result;
|
||||||
|
IEditorInput editorInput = getEditorInput();
|
||||||
|
if (editorInput instanceof FileEditorInput) {
|
||||||
|
FileEditorInput fileEditorInput = (FileEditorInput) editorInput;
|
||||||
|
result = new File(fileEditorInput.getPath().toOSString());
|
||||||
|
} else {
|
||||||
|
result = null;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the the current file.
|
||||||
|
*
|
||||||
|
* @return The current file or <code>null</code>.
|
||||||
|
*/
|
||||||
|
public final IFile getCurrentIFile() {
|
||||||
|
IFile result;
|
||||||
|
IEditorInput editorInput = getEditorInput();
|
||||||
|
if (editorInput instanceof FileEditorInput) {
|
||||||
|
FileEditorInput fileEditorInput = (FileEditorInput) editorInput;
|
||||||
|
result = fileEditorInput.getFile();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
result = null;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Position the cursor to the specified line in the document.
|
||||||
|
*
|
||||||
|
* @param line The line number, a positive integer.
|
||||||
|
*
|
||||||
|
* @return <code>true</code> if the positioning was successful.
|
||||||
|
*/
|
||||||
|
public final boolean gotoLine(int line) {
|
||||||
|
if (line < 1) {
|
||||||
|
throw new IllegalArgumentException("Parameter 'line' must be positive. Specified value is " + line + ".");
|
||||||
|
}
|
||||||
|
IDocumentProvider provider = getDocumentProvider();
|
||||||
|
IDocument document = provider.getDocument(getEditorInput());
|
||||||
|
boolean result = false;
|
||||||
|
try {
|
||||||
|
int startOffset = document.getLineOffset(line - 1);
|
||||||
|
int lineLength = document.getLineLength(line - 1);
|
||||||
|
if (lineLength > 0) {
|
||||||
|
lineLength = lineLength - 1;
|
||||||
|
}
|
||||||
|
selectAndReveal(startOffset, lineLength);
|
||||||
|
result = true;
|
||||||
|
} catch (BadLocationException ex) {
|
||||||
|
plugin.logError("Cannot position to line {0}.", new Object[] { String.valueOf(line) }, ex);
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,55 +39,50 @@ import com.wudsn.ide.asm.compiler.CompilerFiles;
|
||||||
*/
|
*/
|
||||||
public abstract class AssemblerEditorFilesCommandHandler extends AbstractHandler {
|
public abstract class AssemblerEditorFilesCommandHandler extends AbstractHandler {
|
||||||
|
|
||||||
public AssemblerEditorFilesCommandHandler() {
|
public AssemblerEditorFilesCommandHandler() {
|
||||||
super();
|
super();
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object execute(ExecutionEvent event) throws ExecutionException {
|
|
||||||
IEditorPart editor;
|
|
||||||
editor = HandlerUtil.getActiveEditorChecked(event);
|
|
||||||
if (!(editor instanceof AssemblerEditor)) {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AssemblerEditor assemblerEditor;
|
@Override
|
||||||
assemblerEditor = (AssemblerEditor) editor;
|
public Object execute(ExecutionEvent event) throws ExecutionException {
|
||||||
|
IEditorPart editor;
|
||||||
|
editor = HandlerUtil.getActiveEditorChecked(event);
|
||||||
|
if (!(editor instanceof AssemblerEditor)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
CompilerFiles files;
|
AssemblerEditor assemblerEditor;
|
||||||
files = AssemblerEditorFilesLogic.createInstance(assemblerEditor).createCompilerFiles();
|
assemblerEditor = (AssemblerEditor) editor;
|
||||||
|
|
||||||
if (files != null) {
|
CompilerFiles files;
|
||||||
execute(event, assemblerEditor, files);
|
files = AssemblerEditorFilesLogic.createInstance(assemblerEditor).createCompilerFiles();
|
||||||
} else {
|
|
||||||
try {
|
if (files != null) {
|
||||||
AssemblerPlugin.getInstance().showError(
|
execute(event, assemblerEditor, files);
|
||||||
assemblerEditor.getSite().getShell(),
|
} else {
|
||||||
"Operation '" + event.getCommand().getName()
|
try {
|
||||||
+ "' is not possible because the file in the editor is not located in the workspace.",
|
AssemblerPlugin.getInstance().showError(assemblerEditor.getSite().getShell(),
|
||||||
new Exception());
|
"Operation '" + event.getCommand().getName()
|
||||||
} catch (NotDefinedException ignore) {
|
+ "' is not possible because the file in the editor is not located in the workspace.",
|
||||||
// Ignore
|
new Exception("Cannot resolve compiler files of " + assemblerEditor.getEditorInput()));
|
||||||
}
|
} catch (NotDefinedException ignore) {
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform the action on the current editor and file.
|
* Perform the action on the current editor and file.
|
||||||
*
|
*
|
||||||
* @param event
|
* @param event The event, not <code>null</code>.
|
||||||
* The event, not <code>null</code>.
|
* @param assemblerEditor The assembler editor, not <code>null</code> and with
|
||||||
* @param assemblerEditor
|
* current files which are not <code>null</code>.
|
||||||
* The assembler editor, not <code>null</code> and with current
|
* @param files The current compiler files of the editor, not
|
||||||
* files which are not <code>null</code>.
|
* <code>null</code> .
|
||||||
* @param files
|
* @throws ExecutionException if an exception occurred during execution.
|
||||||
* The current compiler files of the editor, not
|
*/
|
||||||
* <code>null</code> .
|
protected abstract void execute(ExecutionEvent event, AssemblerEditor assemblerEditor, CompilerFiles files)
|
||||||
* @throws ExecutionException
|
throws ExecutionException;
|
||||||
* if an exception occurred during execution.
|
|
||||||
*/
|
|
||||||
protected abstract void execute(ExecutionEvent event, AssemblerEditor assemblerEditor, CompilerFiles files)
|
|
||||||
throws ExecutionException;
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -55,318 +55,310 @@ import com.wudsn.ide.base.common.StringUtility;
|
||||||
*/
|
*/
|
||||||
public final class AssemblerEditorFilesLogic {
|
public final class AssemblerEditorFilesLogic {
|
||||||
|
|
||||||
private AssemblerEditor assemblerEditor;
|
private AssemblerEditor assemblerEditor;
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new instance of the logic.
|
|
||||||
*
|
|
||||||
* @param assemblerEditor
|
|
||||||
* The assembler editor, not <code>null</code>.
|
|
||||||
*
|
|
||||||
* @return The new instance, not <code>null</code>.
|
|
||||||
*/
|
|
||||||
static AssemblerEditorFilesLogic createInstance(AssemblerEditor assemblerEditor) {
|
|
||||||
if (assemblerEditor == null) {
|
|
||||||
throw new IllegalArgumentException("Parameter 'assemblerEditor' must not be null.");
|
|
||||||
}
|
|
||||||
|
|
||||||
AssemblerEditorFilesLogic result = new AssemblerEditorFilesLogic();
|
|
||||||
result.assemblerEditor = assemblerEditor;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the container with all files related to the current files.
|
|
||||||
*
|
|
||||||
* @return The container with all files related to the current files or
|
|
||||||
* <code>null</code>.
|
|
||||||
*/
|
|
||||||
CompilerFiles createCompilerFiles() {
|
|
||||||
IFile sourceIFile;
|
|
||||||
CompilerFiles result;
|
|
||||||
sourceIFile = assemblerEditor.getCurrentIFile();
|
|
||||||
if (sourceIFile != null) {
|
|
||||||
|
|
||||||
IDocument document = assemblerEditor.getDocumentProvider().getDocument(assemblerEditor.getEditorInput());
|
|
||||||
AssemblerProperties sourceFileProperties = CompilerSourceParser.getDocumentProperties(document);
|
|
||||||
|
|
||||||
IFile mainSourceIFile;
|
|
||||||
AssemblerProperties mainSourceFileProperties;
|
|
||||||
|
|
||||||
mainSourceIFile = sourceIFile;
|
|
||||||
mainSourceFileProperties = sourceFileProperties;
|
|
||||||
|
|
||||||
AssemblerProperty property = sourceFileProperties.get(AssemblerProperties.MAIN_SOURCE_FILE);
|
|
||||||
if (property != null) {
|
|
||||||
if (StringUtility.isSpecified(property.value)) {
|
|
||||||
IPath mainSourceFileIPath;
|
|
||||||
mainSourceFileIPath = sourceIFile.getFullPath().removeLastSegments(1).append(property.value);
|
|
||||||
mainSourceIFile = ResourcesPlugin.getWorkspace().getRoot().getFile(mainSourceFileIPath);
|
|
||||||
File mainSourceFile = new File(mainSourceIFile.getLocation().toOSString());
|
|
||||||
|
|
||||||
try {
|
|
||||||
String mainSource;
|
|
||||||
|
|
||||||
mainSource = FileUtility.readString(mainSourceFile, FileUtility.MAX_SIZE_UNLIMITED);
|
|
||||||
document = new Document(mainSource);
|
|
||||||
mainSourceFileProperties = CompilerSourceParser.getDocumentProperties(document);
|
|
||||||
} catch (CoreException ex) {
|
|
||||||
AssemblerPlugin plugin = AssemblerPlugin.getInstance();
|
|
||||||
|
|
||||||
plugin.logError("Cannot read main source file '{0'}",
|
|
||||||
new Object[] { mainSourceFile.getPath() }, ex);
|
|
||||||
mainSourceFileProperties = new AssemblerProperties();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new instance of the logic.
|
||||||
|
*
|
||||||
|
* @param assemblerEditor The assembler editor, not <code>null</code>.
|
||||||
|
*
|
||||||
|
* @return The new instance, not <code>null</code>.
|
||||||
|
*/
|
||||||
|
static AssemblerEditorFilesLogic createInstance(AssemblerEditor assemblerEditor) {
|
||||||
|
if (assemblerEditor == null) {
|
||||||
|
throw new IllegalArgumentException("Parameter 'assemblerEditor' must not be null.");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
result = new CompilerFiles(mainSourceIFile, mainSourceFileProperties, sourceIFile, sourceFileProperties,
|
|
||||||
assemblerEditor.getCompilerPreferences());
|
|
||||||
} else {
|
|
||||||
result = null;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean removeMarkers(CompilerFiles files) {
|
AssemblerEditorFilesLogic result = new AssemblerEditorFilesLogic();
|
||||||
if (files == null) {
|
result.assemblerEditor = assemblerEditor;
|
||||||
throw new IllegalArgumentException("Parameter 'files' must not be null.");
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove markers from the current file.
|
/**
|
||||||
try {
|
* Gets the container with all files related to the current files.
|
||||||
files.sourceFile.iFile.deleteMarkers(IMarker.PROBLEM, true, IResource.DEPTH_INFINITE);
|
*
|
||||||
} catch (CoreException ex) {
|
* @return The container with all files related to the current files or
|
||||||
assemblerEditor.getPlugin().logError("Cannot remove markers", null, ex);
|
* <code>null</code>.
|
||||||
}
|
*/
|
||||||
|
CompilerFiles createCompilerFiles() {
|
||||||
|
IFile sourceIFile;
|
||||||
|
CompilerFiles result;
|
||||||
|
sourceIFile = assemblerEditor.getCurrentIFile();
|
||||||
|
if (sourceIFile != null) {
|
||||||
|
|
||||||
// If the main source file is not there, the error shall be related to
|
IDocument document = assemblerEditor.getDocumentProvider().getDocument(assemblerEditor.getEditorInput());
|
||||||
// the include source file. In all other cases, the main source file
|
AssemblerProperties sourceFileProperties = CompilerSourceParser.getDocumentProperties(document);
|
||||||
// exists and is the main message target.
|
|
||||||
if (!files.mainSourceFile.iFile.exists()) {
|
|
||||||
int lineNumber = files.sourceFile.assemblerProperties.get(AssemblerProperties.MAIN_SOURCE_FILE).lineNumber;
|
|
||||||
|
|
||||||
// ERROR: Main source file '{0}' does not exist.
|
IFile mainSourceIFile;
|
||||||
IMarker marker = MarkerUtility.createMarker(files.sourceFile.iFile, lineNumber, IMarker.SEVERITY_ERROR,
|
AssemblerProperties mainSourceFileProperties;
|
||||||
Texts.MESSAGE_E125, files.mainSourceFile.filePath);
|
|
||||||
MarkerUtility.gotoMarker(assemblerEditor, marker);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove markers from the other relevant files.
|
mainSourceIFile = sourceIFile;
|
||||||
// TODO Use (only) include files parsed from main source file
|
mainSourceFileProperties = sourceFileProperties;
|
||||||
try {
|
|
||||||
files.mainSourceFile.iFile.getParent().deleteMarkers(IMarker.PROBLEM, true, IResource.DEPTH_INFINITE);
|
|
||||||
} catch (CoreException ex) {
|
|
||||||
assemblerEditor.getPlugin().logError("Cannot remove markers", null, ex);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
AssemblerProperty property = sourceFileProperties.get(AssemblerProperties.MAIN_SOURCE_FILE);
|
||||||
* Determine the hardware defined by the property
|
if (property != null) {
|
||||||
* {@link AssemblerProperties#HARDWARE}.
|
if (StringUtility.isSpecified(property.value)) {
|
||||||
*
|
IPath mainSourceFileIPath;
|
||||||
* @param iFile
|
mainSourceFileIPath = sourceIFile.getFullPath().removeLastSegments(1).append(property.value);
|
||||||
* The iFIle to which error message will be associated, not
|
mainSourceIFile = ResourcesPlugin.getWorkspace().getRoot().getFile(mainSourceFileIPath);
|
||||||
* <code>null</code>.
|
File mainSourceFile = new File(mainSourceIFile.getLocation().toOSString());
|
||||||
* @param properties
|
|
||||||
* The assembler properties, not <code>null</code>.
|
|
||||||
*
|
|
||||||
* @return The hardware or <code>null</code> if is the not defined in the
|
|
||||||
* properties.
|
|
||||||
* @throws InvalidAssemblerPropertyException
|
|
||||||
* If the hardware is specified but invalid. Error message will
|
|
||||||
* be assigned to the iFile in this case.
|
|
||||||
*
|
|
||||||
* @since 1.6.1
|
|
||||||
*/
|
|
||||||
Hardware getHardware(IFile iFile, AssemblerProperties properties) throws InvalidAssemblerPropertyException {
|
|
||||||
if (iFile == null) {
|
|
||||||
throw new IllegalArgumentException("Parameter 'iFile' must not be null.");
|
|
||||||
}
|
|
||||||
Hardware hardware = null;
|
|
||||||
AssemblerProperty hardwareProperty = properties.get(AssemblerProperties.HARDWARE);
|
|
||||||
if (hardwareProperty != null) {
|
|
||||||
Map<String, Hardware> allowedValues = new TreeMap<String, Hardware>();
|
|
||||||
StringBuilder allowedValuesBuilder = new StringBuilder();
|
|
||||||
for (Hardware value : Hardware.values()) {
|
|
||||||
|
|
||||||
if (value != Hardware.GENERIC) {
|
try {
|
||||||
if (allowedValuesBuilder.length() > 0) {
|
String mainSource;
|
||||||
allowedValuesBuilder.append(",");
|
|
||||||
}
|
mainSource = FileUtility.readString(mainSourceFile, FileUtility.MAX_SIZE_UNLIMITED);
|
||||||
allowedValues.put(value.name(), value);
|
document = new Document(mainSource);
|
||||||
allowedValuesBuilder.append(value.name());
|
mainSourceFileProperties = CompilerSourceParser.getDocumentProperties(document);
|
||||||
|
} catch (CoreException ex) {
|
||||||
|
AssemblerPlugin plugin = AssemblerPlugin.getInstance();
|
||||||
|
|
||||||
|
plugin.logError("Cannot read main source file '{0'}", new Object[] { mainSourceFile.getPath() },
|
||||||
|
ex);
|
||||||
|
mainSourceFileProperties = new AssemblerProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result = new CompilerFiles(mainSourceIFile, mainSourceFileProperties, sourceIFile, sourceFileProperties,
|
||||||
|
assemblerEditor.getCompilerPreferences());
|
||||||
|
} else {
|
||||||
|
result = null;
|
||||||
}
|
}
|
||||||
}
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
String hardwarePropertyValue = hardwareProperty.value.toUpperCase();
|
public boolean removeMarkers(CompilerFiles files) {
|
||||||
if (StringUtility.isEmpty(hardwarePropertyValue)) {
|
if (files == null) {
|
||||||
|
throw new IllegalArgumentException("Parameter 'files' must not be null.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove markers from the current file.
|
||||||
try {
|
try {
|
||||||
iFile.deleteMarkers(IMarker.PROBLEM, true, IResource.DEPTH_ZERO);
|
files.sourceFile.iFile.deleteMarkers(IMarker.PROBLEM, true, IResource.DEPTH_INFINITE);
|
||||||
} catch (CoreException ex) {
|
} catch (CoreException ex) {
|
||||||
AssemblerPlugin.getInstance().logError("Cannot remove markers", null, ex);
|
assemblerEditor.getPlugin().logError("Cannot remove markers", null, ex);
|
||||||
}
|
}
|
||||||
// ERROR: Hardware not specified. Specify one of the
|
|
||||||
// following valid values '{0}'.
|
|
||||||
IMarker marker = MarkerUtility.createMarker(iFile, hardwareProperty.lineNumber, IMarker.SEVERITY_ERROR,
|
|
||||||
Texts.MESSAGE_E128, new String[] { allowedValuesBuilder.toString() });
|
|
||||||
throw new InvalidAssemblerPropertyException(hardwareProperty, marker);
|
|
||||||
}
|
|
||||||
hardware = allowedValues.get(hardwarePropertyValue);
|
|
||||||
|
|
||||||
if (hardware == null) {
|
// If the main source file is not there, the error shall be related to
|
||||||
|
// the include source file. In all other cases, the main source file
|
||||||
|
// exists and is the main message target.
|
||||||
|
if (!files.mainSourceFile.iFile.exists()) {
|
||||||
|
int lineNumber = files.sourceFile.assemblerProperties.get(AssemblerProperties.MAIN_SOURCE_FILE).lineNumber;
|
||||||
|
|
||||||
|
// ERROR: Main source file '{0}' does not exist.
|
||||||
|
IMarker marker = MarkerUtility.createMarker(files.sourceFile.iFile, lineNumber, IMarker.SEVERITY_ERROR,
|
||||||
|
Texts.MESSAGE_E125, files.mainSourceFile.filePath);
|
||||||
|
MarkerUtility.gotoMarker(assemblerEditor, marker);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove markers from the other relevant files.
|
||||||
|
// TODO Use (only) include files parsed from main source file
|
||||||
try {
|
try {
|
||||||
iFile.deleteMarkers(IMarker.PROBLEM, true, IResource.DEPTH_ZERO);
|
files.mainSourceFile.iFile.getParent().deleteMarkers(IMarker.PROBLEM, true, IResource.DEPTH_INFINITE);
|
||||||
} catch (CoreException ex) {
|
} catch (CoreException ex) {
|
||||||
assemblerEditor.getPlugin().logError("Cannot remove markers", null, ex);
|
assemblerEditor.getPlugin().logError("Cannot remove markers", null, ex);
|
||||||
}
|
}
|
||||||
// ERROR: Unknown hardware {0}. Specify one of the
|
return true;
|
||||||
// following valid values '{1}'.
|
|
||||||
IMarker marker = MarkerUtility.createMarker(iFile, hardwareProperty.lineNumber, IMarker.SEVERITY_ERROR,
|
|
||||||
Texts.MESSAGE_E124, new String[] { hardwarePropertyValue, allowedValuesBuilder.toString() });
|
|
||||||
throw new InvalidAssemblerPropertyException(hardwareProperty, marker);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return hardware;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine the hardware of the main source file and makes sure that the
|
|
||||||
* include file uses the same hardware.
|
|
||||||
*
|
|
||||||
* @param files
|
|
||||||
* The compiler files, not <code>null</code>.
|
|
||||||
* @return The hardware to be used, or <code>null</code> if errors have
|
|
||||||
* occurred.
|
|
||||||
*
|
|
||||||
* @since 1.6.1
|
|
||||||
*/
|
|
||||||
public Hardware getHardware(CompilerFiles files) {
|
|
||||||
if (files == null) {
|
|
||||||
throw new IllegalArgumentException("Parameter 'files' must not be null.");
|
|
||||||
}
|
|
||||||
Hardware mainSourceFileHardware;
|
|
||||||
Hardware sourceFileHardware;
|
|
||||||
try {
|
|
||||||
sourceFileHardware = getHardware(files.sourceFile.iFile, files.sourceFile.assemblerProperties);
|
|
||||||
} catch (InvalidAssemblerPropertyException ex) {
|
|
||||||
MarkerUtility.gotoMarker(assemblerEditor, ex.marker);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
mainSourceFileHardware = getHardware(files.mainSourceFile.iFile, files.mainSourceFile.assemblerProperties);
|
|
||||||
} catch (InvalidAssemblerPropertyException ex) {
|
|
||||||
MarkerUtility.gotoMarker(assemblerEditor, ex.marker);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
Hardware defaultHardware = assemblerEditor.getCompilerDefinition().getDefaultHardware();
|
|
||||||
int sourceFileLineNumber;
|
|
||||||
int mainSourceFileLineNumber;
|
|
||||||
if (sourceFileHardware == null) {
|
|
||||||
sourceFileHardware = defaultHardware;
|
|
||||||
sourceFileLineNumber = 0;
|
|
||||||
} else {
|
|
||||||
sourceFileLineNumber = files.sourceFile.assemblerProperties.get(AssemblerProperties.HARDWARE).lineNumber;
|
|
||||||
}
|
|
||||||
if (mainSourceFileHardware == null) {
|
|
||||||
mainSourceFileHardware = defaultHardware;
|
|
||||||
mainSourceFileLineNumber = 0;
|
|
||||||
} else {
|
|
||||||
mainSourceFileLineNumber = files.mainSourceFile.assemblerProperties.get(AssemblerProperties.HARDWARE).lineNumber;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sourceFileHardware.equals(mainSourceFileHardware)) {
|
/**
|
||||||
// ERROR: Main source file specifies or defaults to hardware {0}
|
* Determine the hardware defined by the property
|
||||||
// while include file specifies or defaults to hardware '{1}'.
|
* {@link AssemblerProperties#HARDWARE}.
|
||||||
MarkerUtility.createMarker(files.mainSourceFile.iFile, mainSourceFileLineNumber, IMarker.SEVERITY_ERROR,
|
*
|
||||||
Texts.MESSAGE_E129, new String[] { mainSourceFileHardware.name(), sourceFileHardware.name() });
|
* @param iFile The iFIle to which error message will be associated, not
|
||||||
MarkerUtility.createMarker(files.sourceFile.iFile, sourceFileLineNumber, IMarker.SEVERITY_ERROR,
|
* <code>null</code>.
|
||||||
Texts.MESSAGE_E129, new String[] { mainSourceFileHardware.name(), sourceFileHardware.name() });
|
* @param properties The assembler properties, not <code>null</code>.
|
||||||
return null;
|
*
|
||||||
}
|
* @return The hardware or <code>null</code> if is the not defined in the
|
||||||
return mainSourceFileHardware;
|
* properties.
|
||||||
}
|
* @throws InvalidAssemblerPropertyException If the hardware is specified but
|
||||||
|
* invalid. Error message will be
|
||||||
|
* assigned to the iFile in this case.
|
||||||
|
*
|
||||||
|
* @since 1.6.1
|
||||||
|
*/
|
||||||
|
Hardware getHardware(IFile iFile, AssemblerProperties properties) throws InvalidAssemblerPropertyException {
|
||||||
|
if (iFile == null) {
|
||||||
|
throw new IllegalArgumentException("Parameter 'iFile' must not be null.");
|
||||||
|
}
|
||||||
|
Hardware hardware = null;
|
||||||
|
AssemblerProperty hardwareProperty = properties.get(AssemblerProperties.HARDWARE);
|
||||||
|
if (hardwareProperty != null) {
|
||||||
|
Map<String, Hardware> allowedValues = new TreeMap<String, Hardware>();
|
||||||
|
StringBuilder allowedValuesBuilder = new StringBuilder();
|
||||||
|
for (Hardware value : Hardware.values()) {
|
||||||
|
|
||||||
/**
|
if (value != Hardware.GENERIC) {
|
||||||
* Validates the output file related settings of the compiler files.
|
if (allowedValuesBuilder.length() > 0) {
|
||||||
*
|
allowedValuesBuilder.append(",");
|
||||||
* @param files
|
}
|
||||||
* The compiler files, not <code>null</code>.
|
allowedValues.put(value.name(), value);
|
||||||
* @return <code>true</code> if all settings are correct, <code>false</code>
|
allowedValuesBuilder.append(value.name());
|
||||||
* otherwise.
|
}
|
||||||
*/
|
}
|
||||||
public boolean validateOutputFile(CompilerFiles files) {
|
|
||||||
if (files == null) {
|
|
||||||
throw new IllegalArgumentException("Parameter 'files' must not be null.");
|
|
||||||
}
|
|
||||||
CompilerDefinition compilerDefinition = assemblerEditor.getCompilerDefinition();
|
|
||||||
if (StringUtility.isEmpty(files.outputFileExtension)) {
|
|
||||||
// ERROR: Output file extension must be set in the preferences of
|
|
||||||
// compiler '{0}' or via the annotation '{1}'.
|
|
||||||
createMainSourceFileMessage(files, files.outputFileExtensionProperty, IMarker.SEVERITY_ERROR,
|
|
||||||
Texts.MESSAGE_E104, compilerDefinition.getName(), AssemblerProperties.OUTPUT_FILE_EXTENSION);
|
|
||||||
|
|
||||||
return false;
|
String hardwarePropertyValue = hardwareProperty.value.toUpperCase();
|
||||||
}
|
if (StringUtility.isEmpty(hardwarePropertyValue)) {
|
||||||
if (!files.outputFileExtension.startsWith(".")) {
|
try {
|
||||||
// ERROR: Output file extension {0} must start with ".".
|
iFile.deleteMarkers(IMarker.PROBLEM, true, IResource.DEPTH_ZERO);
|
||||||
createMainSourceFileMessage(files, files.outputFileExtensionProperty, IMarker.SEVERITY_ERROR,
|
} catch (CoreException ex) {
|
||||||
Texts.MESSAGE_E139, files.outputFileExtension);
|
AssemblerPlugin.getInstance().logError("Cannot remove markers", null, ex);
|
||||||
return false;
|
}
|
||||||
|
// ERROR: Hardware not specified. Specify one of the
|
||||||
|
// following valid values '{0}'.
|
||||||
|
IMarker marker = MarkerUtility.createMarker(iFile, hardwareProperty.lineNumber, IMarker.SEVERITY_ERROR,
|
||||||
|
Texts.MESSAGE_E128, new String[] { allowedValuesBuilder.toString() });
|
||||||
|
throw new InvalidAssemblerPropertyException(hardwareProperty, marker);
|
||||||
|
}
|
||||||
|
hardware = allowedValues.get(hardwarePropertyValue);
|
||||||
|
|
||||||
|
if (hardware == null) {
|
||||||
|
try {
|
||||||
|
iFile.deleteMarkers(IMarker.PROBLEM, true, IResource.DEPTH_ZERO);
|
||||||
|
} catch (CoreException ex) {
|
||||||
|
assemblerEditor.getPlugin().logError("Cannot remove markers", null, ex);
|
||||||
|
}
|
||||||
|
// ERROR: Unknown hardware {0}. Specify one of the
|
||||||
|
// following valid values '{1}'.
|
||||||
|
IMarker marker = MarkerUtility.createMarker(iFile, hardwareProperty.lineNumber, IMarker.SEVERITY_ERROR,
|
||||||
|
Texts.MESSAGE_E124, new String[] { hardwarePropertyValue, allowedValuesBuilder.toString() });
|
||||||
|
throw new InvalidAssemblerPropertyException(hardwareProperty, marker);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return hardware;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (StringUtility.isEmpty(files.outputFolderMode)) {
|
/**
|
||||||
// ERROR: Output folder mode be set in the preferences of
|
* Determine the hardware of the main source file and makes sure that the
|
||||||
// compiler '{0}' or via the annotation '{1}'.
|
* include file uses the same hardware.
|
||||||
createMainSourceFileMessage(files, files.outputFolderModeProperty, IMarker.SEVERITY_ERROR,
|
*
|
||||||
Texts.MESSAGE_E140, compilerDefinition.getName(), AssemblerProperties.OUTPUT_FOLDER_MODE);
|
* @param files The compiler files, not <code>null</code>.
|
||||||
|
* @return The hardware to be used, or <code>null</code> if errors have
|
||||||
return false;
|
* occurred.
|
||||||
}
|
*
|
||||||
if (!CompilerOutputFolderMode.isDefined(files.outputFolderMode)) {
|
* @since 1.6.1
|
||||||
// ERROR: Unknown output folder mode {0}. Specify one of the
|
*/
|
||||||
// following valid values '{1}'.
|
public Hardware getHardware(CompilerFiles files) {
|
||||||
createMainSourceFileMessage(files, files.outputFolderModeProperty, IMarker.SEVERITY_ERROR,
|
if (files == null) {
|
||||||
Texts.MESSAGE_E141, files.outputFolderMode, CompilerOutputFolderMode.getAllowedValues());
|
throw new IllegalArgumentException("Parameter 'files' must not be null.");
|
||||||
return false;
|
}
|
||||||
|
Hardware mainSourceFileHardware;
|
||||||
|
Hardware sourceFileHardware;
|
||||||
|
try {
|
||||||
|
sourceFileHardware = getHardware(files.sourceFile.iFile, files.sourceFile.assemblerProperties);
|
||||||
|
} catch (InvalidAssemblerPropertyException ex) {
|
||||||
|
MarkerUtility.gotoMarker(assemblerEditor, ex.marker);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
mainSourceFileHardware = getHardware(files.mainSourceFile.iFile, files.mainSourceFile.assemblerProperties);
|
||||||
|
} catch (InvalidAssemblerPropertyException ex) {
|
||||||
|
MarkerUtility.gotoMarker(assemblerEditor, ex.marker);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Hardware defaultHardware = assemblerEditor.getCompilerDefinition().getDefaultHardware();
|
||||||
|
int sourceFileLineNumber;
|
||||||
|
int mainSourceFileLineNumber;
|
||||||
|
if (sourceFileHardware == null) {
|
||||||
|
sourceFileHardware = defaultHardware;
|
||||||
|
sourceFileLineNumber = 0;
|
||||||
|
} else {
|
||||||
|
sourceFileLineNumber = files.sourceFile.assemblerProperties.get(AssemblerProperties.HARDWARE).lineNumber;
|
||||||
|
}
|
||||||
|
if (mainSourceFileHardware == null) {
|
||||||
|
mainSourceFileHardware = defaultHardware;
|
||||||
|
mainSourceFileLineNumber = 0;
|
||||||
|
} else {
|
||||||
|
mainSourceFileLineNumber = files.mainSourceFile.assemblerProperties
|
||||||
|
.get(AssemblerProperties.HARDWARE).lineNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sourceFileHardware.equals(mainSourceFileHardware)) {
|
||||||
|
// ERROR: Main source file specifies or defaults to hardware {0}
|
||||||
|
// while include file specifies or defaults to hardware '{1}'.
|
||||||
|
MarkerUtility.createMarker(files.mainSourceFile.iFile, mainSourceFileLineNumber, IMarker.SEVERITY_ERROR,
|
||||||
|
Texts.MESSAGE_E129, new String[] { mainSourceFileHardware.name(), sourceFileHardware.name() });
|
||||||
|
MarkerUtility.createMarker(files.sourceFile.iFile, sourceFileLineNumber, IMarker.SEVERITY_ERROR,
|
||||||
|
Texts.MESSAGE_E129, new String[] { mainSourceFileHardware.name(), sourceFileHardware.name() });
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return mainSourceFileHardware;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
/**
|
||||||
}
|
* Validates the output file related settings of the compiler files.
|
||||||
|
*
|
||||||
|
* @param files The compiler files, not <code>null</code>.
|
||||||
|
* @return <code>true</code> if all settings are correct, <code>false</code>
|
||||||
|
* otherwise.
|
||||||
|
*/
|
||||||
|
public boolean validateOutputFile(CompilerFiles files) {
|
||||||
|
if (files == null) {
|
||||||
|
throw new IllegalArgumentException("Parameter 'files' must not be null.");
|
||||||
|
}
|
||||||
|
CompilerDefinition compilerDefinition = assemblerEditor.getCompilerDefinition();
|
||||||
|
if (StringUtility.isEmpty(files.outputFileExtension)) {
|
||||||
|
// ERROR: Output file extension must be set in the preferences of
|
||||||
|
// compiler '{0}' or via the annotation '{1}'.
|
||||||
|
createMainSourceFileMessage(files, files.outputFileExtensionProperty, IMarker.SEVERITY_ERROR,
|
||||||
|
Texts.MESSAGE_E104, compilerDefinition.getName(), AssemblerProperties.OUTPUT_FILE_EXTENSION);
|
||||||
|
|
||||||
/**
|
return false;
|
||||||
* Creates a message associated with the main source file of an
|
}
|
||||||
* {@link AssemblerEditorFilesLogic} instance. The message is is bound to
|
if (!files.outputFileExtension.startsWith(".")) {
|
||||||
* the line number number of the property (if available). Also the editor is
|
// ERROR: Output file extension {0} must start with ".".
|
||||||
* position to the marker.
|
createMainSourceFileMessage(files, files.outputFileExtensionProperty, IMarker.SEVERITY_ERROR,
|
||||||
*
|
Texts.MESSAGE_E139, files.outputFileExtension);
|
||||||
* @param files
|
return false;
|
||||||
* The {@link AssemblerEditorFilesLogic} not <code>null</code>.
|
}
|
||||||
* @param property
|
|
||||||
* The assembler editor property to which the message belongs or
|
if (StringUtility.isEmpty(files.outputFolderMode)) {
|
||||||
* <code>null</code>.
|
// ERROR: Output folder mode be set in the preferences of
|
||||||
* @param severity
|
// compiler '{0}' or via the annotation '{1}'.
|
||||||
* The message severity, see {@link IMarker#SEVERITY}
|
createMainSourceFileMessage(files, files.outputFolderModeProperty, IMarker.SEVERITY_ERROR,
|
||||||
* @param message
|
Texts.MESSAGE_E140, compilerDefinition.getName(), AssemblerProperties.OUTPUT_FOLDER_MODE);
|
||||||
* The message, may contain parameter "{0}" to "{9}". May be
|
|
||||||
* empty, not <code>null</code>.
|
return false;
|
||||||
* @param parameters
|
}
|
||||||
* The format parameters for the message, may be empty, not
|
if (!CompilerOutputFolderMode.isDefined(files.outputFolderMode)) {
|
||||||
* <code>null</code>.
|
// ERROR: Unknown output folder mode {0}. Specify one of the
|
||||||
*/
|
// following valid values '{1}'.
|
||||||
private void createMainSourceFileMessage(CompilerFiles files, AssemblerProperty property, int severity,
|
createMainSourceFileMessage(files, files.outputFolderModeProperty, IMarker.SEVERITY_ERROR,
|
||||||
String message, String... parameters) {
|
Texts.MESSAGE_E141, files.outputFolderMode, CompilerOutputFolderMode.getAllowedValues());
|
||||||
if (files == null) {
|
return false;
|
||||||
throw new IllegalArgumentException("Parameter 'files' must not be null.");
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
IMarker marker = MarkerUtility.createMarker(files.mainSourceFile.iFile, (property == null ? 0
|
|
||||||
: property.lineNumber), severity, message, parameters);
|
|
||||||
MarkerUtility.gotoMarker(assemblerEditor, marker);
|
|
||||||
|
|
||||||
}
|
/**
|
||||||
|
* Creates a message associated with the main source file of an
|
||||||
|
* {@link AssemblerEditorFilesLogic} instance. The message is is bound to the
|
||||||
|
* line number number of the property (if available). Also the editor is
|
||||||
|
* position to the marker.
|
||||||
|
*
|
||||||
|
* @param files The {@link AssemblerEditorFilesLogic} not
|
||||||
|
* <code>null</code>.
|
||||||
|
* @param property The assembler editor property to which the message belongs
|
||||||
|
* or <code>null</code>.
|
||||||
|
* @param severity The message severity, see {@link IMarker#SEVERITY}
|
||||||
|
* @param message The message, may contain parameter "{0}" to "{9}". May be
|
||||||
|
* empty, not <code>null</code>.
|
||||||
|
* @param parameters The format parameters for the message, may be empty, not
|
||||||
|
* <code>null</code>.
|
||||||
|
*/
|
||||||
|
private void createMainSourceFileMessage(CompilerFiles files, AssemblerProperty property, int severity,
|
||||||
|
String message, String... parameters) {
|
||||||
|
if (files == null) {
|
||||||
|
throw new IllegalArgumentException("Parameter 'files' must not be null.");
|
||||||
|
}
|
||||||
|
IMarker marker = MarkerUtility.createMarker(files.mainSourceFile.iFile,
|
||||||
|
(property == null ? 0 : property.lineNumber), severity, message, parameters);
|
||||||
|
MarkerUtility.gotoMarker(assemblerEditor, marker);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -33,214 +33,208 @@ import com.wudsn.ide.base.common.StringUtility;
|
||||||
*/
|
*/
|
||||||
public final class CompilerPreferences {
|
public final class CompilerPreferences {
|
||||||
|
|
||||||
private AssemblerPreferences assemblerPreferences;
|
private AssemblerPreferences assemblerPreferences;
|
||||||
private Hardware hardware;
|
private Hardware hardware;
|
||||||
private String compilerId;
|
private String compilerId;
|
||||||
|
|
||||||
CompilerPreferences(AssemblerPreferences assemblerPreferences, String compilerId, Hardware hardware) {
|
CompilerPreferences(AssemblerPreferences assemblerPreferences, String compilerId, Hardware hardware) {
|
||||||
if (assemblerPreferences == null) {
|
if (assemblerPreferences == null) {
|
||||||
throw new IllegalArgumentException("Parameter 'assemblerPreferences' must not be null.");
|
throw new IllegalArgumentException("Parameter 'assemblerPreferences' must not be null.");
|
||||||
|
}
|
||||||
|
if (compilerId == null) {
|
||||||
|
throw new IllegalArgumentException("Parameter 'compilerId' must not be null.");
|
||||||
|
}
|
||||||
|
if (StringUtility.isEmpty(compilerId)) {
|
||||||
|
throw new IllegalArgumentException("Parameter 'compilerId' must not be empty.");
|
||||||
|
}
|
||||||
|
if (hardware == null) {
|
||||||
|
throw new IllegalArgumentException("Parameter 'hardware' must not be null.");
|
||||||
|
}
|
||||||
|
this.assemblerPreferences = assemblerPreferences;
|
||||||
|
this.compilerId = compilerId;
|
||||||
|
this.hardware = hardware;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (compilerId == null) {
|
/**
|
||||||
throw new IllegalArgumentException("Parameter 'compilerId' must not be null.");
|
* Gets the compiler id of the compiler.
|
||||||
|
*
|
||||||
|
* @return The compiler id of the compiler, not empty and not <code>null</code>.
|
||||||
|
*/
|
||||||
|
public String getCompilerId() {
|
||||||
|
return compilerId;
|
||||||
}
|
}
|
||||||
if (StringUtility.isEmpty(compilerId)) {
|
|
||||||
throw new IllegalArgumentException("Parameter 'compilerId' must not be empty.");
|
/**
|
||||||
|
* Gets the hardware for which the compiler is invoked.
|
||||||
|
*
|
||||||
|
* @return The hardware, not <code>null</code>.
|
||||||
|
*
|
||||||
|
* @since 1.6.1
|
||||||
|
*/
|
||||||
|
public Hardware getHardware() {
|
||||||
|
return hardware;
|
||||||
}
|
}
|
||||||
if (hardware == null) {
|
|
||||||
throw new IllegalArgumentException("Parameter 'hardware' must not be null.");
|
/**
|
||||||
|
* Gets the CPU for which the instructions shall be active.
|
||||||
|
*
|
||||||
|
* @return The CPU, not <code>null</code>.
|
||||||
|
*
|
||||||
|
* @since 1.6.1
|
||||||
|
*/
|
||||||
|
public CPU getCPU() {
|
||||||
|
CPU result;
|
||||||
|
String cpuString = assemblerPreferences
|
||||||
|
.getString(AssemblerPreferencesConstants.getCompilerCPUName(compilerId, hardware));
|
||||||
|
|
||||||
|
if (StringUtility.isEmpty(cpuString)) {
|
||||||
|
result = CPU.MOS6502;
|
||||||
|
} else {
|
||||||
|
result = CPU.valueOf(cpuString);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
this.assemblerPreferences = assemblerPreferences;
|
|
||||||
this.compilerId = compilerId;
|
|
||||||
this.hardware = hardware;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the compiler id of the compiler.
|
* Determines if illegal opcodes shall be highlighted and proposed.
|
||||||
*
|
*
|
||||||
* @return The compiler id of the compiler, not empty and not
|
* @return <code>true</code> if yet, <code>false</code> otherwise.
|
||||||
* <code>null</code>.
|
*/
|
||||||
*/
|
@Deprecated
|
||||||
public String getCompilerId() {
|
public boolean isIllegalOpcodesVisible() {
|
||||||
return compilerId;
|
return getCPU() == CPU.MOS6502_ILLEGAL;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the hardware for which the compiler is invoked.
|
|
||||||
*
|
|
||||||
* @return The hardware, not <code>null</code>.
|
|
||||||
*
|
|
||||||
* @since 1.6.1
|
|
||||||
*/
|
|
||||||
public Hardware getHardware() {
|
|
||||||
return hardware;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the CPU for which the instructions shall be active.
|
|
||||||
*
|
|
||||||
* @return The CPU, not <code>null</code>.
|
|
||||||
*
|
|
||||||
* @since 1.6.1
|
|
||||||
*/
|
|
||||||
public CPU getCPU() {
|
|
||||||
CPU result;
|
|
||||||
String cpuString = assemblerPreferences.getString(AssemblerPreferencesConstants.getCompilerCPUName(compilerId,
|
|
||||||
hardware));
|
|
||||||
|
|
||||||
if (StringUtility.isEmpty(cpuString)) {
|
|
||||||
result = CPU.MOS6502;
|
|
||||||
} else {
|
|
||||||
result = CPU.valueOf(cpuString);
|
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines if illegal opcodes shall be highlighted and proposed.
|
* Determines if W65816 opcodes shall be highlighted and proposed.
|
||||||
*
|
*
|
||||||
* @return <code>true</code> if yet, <code>false</code> otherwise.
|
* @return <code>true</code> if yet, <code>false</code> otherwise.
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public boolean isIllegalOpcodesVisible() {
|
public boolean isW65816OpcodesVisible() {
|
||||||
return getCPU() == CPU.MOS6502_ILLEGAL;
|
return getCPU() == CPU.MOS65816;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines if W65816 opcodes shall be highlighted and proposed.
|
|
||||||
*
|
|
||||||
* @return <code>true</code> if yet, <code>false</code> otherwise.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public boolean isW65816OpcodesVisible() {
|
|
||||||
return getCPU() == CPU.MOS65816;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the parameters for the compiler.
|
|
||||||
*
|
|
||||||
* @return The parameters path for the compiler, may be empty, not
|
|
||||||
* <code>null</code>.
|
|
||||||
*/
|
|
||||||
public String getParameters() {
|
|
||||||
return assemblerPreferences.getString(AssemblerPreferencesConstants.getCompilerParametersName(compilerId,
|
|
||||||
hardware));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the output folder mode for the compiler.
|
|
||||||
*
|
|
||||||
* @return The output folder mode for the compiler, see
|
|
||||||
* {@link CompilerOutputFolderMode}, may be empty, not
|
|
||||||
* <code>null</code>.
|
|
||||||
*/
|
|
||||||
public String getOutputFolderMode() {
|
|
||||||
|
|
||||||
return assemblerPreferences.getString(AssemblerPreferencesConstants.getCompilerOutputFolderModeName(compilerId,
|
|
||||||
hardware));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the output folder for the compiler in case the output folder mode is
|
|
||||||
* {@link CompilerOutputFolderMode#FIXED_FOLDER}.
|
|
||||||
*
|
|
||||||
* @return The output folder mode for the compiler, see
|
|
||||||
* {@link CompilerOutputFolderMode#FIXED_FOLDER}, may be empty, not
|
|
||||||
* <code>null</code>.
|
|
||||||
*/
|
|
||||||
public String getOutputFolderPath() {
|
|
||||||
|
|
||||||
return assemblerPreferences.getString(AssemblerPreferencesConstants.getCompilerOutputFolderPathName(compilerId,
|
|
||||||
hardware));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the output file extension for the compiler.
|
|
||||||
*
|
|
||||||
* @return The output file extension may be empty, not <code>null</code>.
|
|
||||||
*/
|
|
||||||
public String getOutputFileExtension() {
|
|
||||||
|
|
||||||
return assemblerPreferences.getString(AssemblerPreferencesConstants.getCompilerOutputFileExtensionName(
|
|
||||||
compilerId, hardware));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the id of the default runner to run the output file.
|
|
||||||
*
|
|
||||||
* @return The id of the runner to run the output file, not empty and not
|
|
||||||
* <code>null</code>.
|
|
||||||
*/
|
|
||||||
public String getRunnerId() {
|
|
||||||
String result = assemblerPreferences.getString(AssemblerPreferencesConstants.getCompilerRunnerIdName(
|
|
||||||
compilerId, hardware));
|
|
||||||
if (StringUtility.isEmpty(result)) {
|
|
||||||
result = RunnerId.DEFAULT_APPLICATION;
|
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the executable path for the runner.
|
* Gets the parameters for the compiler.
|
||||||
*
|
*
|
||||||
* @param runnerId
|
* @return The parameters path for the compiler, may be empty, not
|
||||||
* The runner id, not empty and not <code>null</code>.
|
* <code>null</code>.
|
||||||
*
|
*/
|
||||||
* @return The executable path for the runner, may be empty, not
|
public String getParameters() {
|
||||||
* <code>null</code>.
|
return assemblerPreferences
|
||||||
*/
|
.getString(AssemblerPreferencesConstants.getCompilerParametersName(compilerId, hardware));
|
||||||
public String getRunnerExecutablePath(String runnerId) {
|
|
||||||
if (runnerId == null) {
|
|
||||||
throw new IllegalArgumentException("Parameter 'runnerId' must not be null.");
|
|
||||||
}
|
}
|
||||||
if (StringUtility.isEmpty(runnerId)) {
|
|
||||||
throw new IllegalArgumentException("Parameter 'runnerId' must not be empty.");
|
|
||||||
}
|
|
||||||
return assemblerPreferences.getString(AssemblerPreferencesConstants.getCompilerRunnerExecutablePathName(
|
|
||||||
compilerId, hardware, runnerId));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the parameters for the runner.
|
* Gets the output folder mode for the compiler.
|
||||||
*
|
*
|
||||||
* @param runnerId
|
* @return The output folder mode for the compiler, see
|
||||||
* The runner id, not empty and not <code>null</code>.
|
* {@link CompilerOutputFolderMode}, may be empty, not
|
||||||
*
|
* <code>null</code>.
|
||||||
* @return The parameters for the runner, may be empty, not
|
*/
|
||||||
* <code>null</code>.
|
public String getOutputFolderMode() {
|
||||||
*/
|
|
||||||
public String getRunnerCommandLine(String runnerId) {
|
|
||||||
if (runnerId == null) {
|
|
||||||
throw new IllegalArgumentException("Parameter 'runnerId' must not be null.");
|
|
||||||
}
|
|
||||||
if (StringUtility.isEmpty(runnerId)) {
|
|
||||||
throw new IllegalArgumentException("Parameter 'runnerId' must not be empty.");
|
|
||||||
}
|
|
||||||
return assemblerPreferences.getString(AssemblerPreferencesConstants.getCompilerRunnerCommandLineName(
|
|
||||||
compilerId, hardware, runnerId));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
return assemblerPreferences
|
||||||
* Gets the wait for completion indicator for the runner.
|
.getString(AssemblerPreferencesConstants.getCompilerOutputFolderModeName(compilerId, hardware));
|
||||||
*
|
|
||||||
* @param runnerId
|
|
||||||
* The runner id, not empty and not <code>null</code>.
|
|
||||||
*
|
|
||||||
* @return <code>true</code>if waiting for completion is requested,
|
|
||||||
* <code>false</code> otherwise.
|
|
||||||
*
|
|
||||||
* @since 1.6.1
|
|
||||||
*/
|
|
||||||
public boolean isRunnerWaitForCompletion(String runnerId) {
|
|
||||||
if (runnerId == null) {
|
|
||||||
throw new IllegalArgumentException("Parameter 'runnerId' must not be null.");
|
|
||||||
}
|
}
|
||||||
if (StringUtility.isEmpty(runnerId)) {
|
|
||||||
throw new IllegalArgumentException("Parameter 'runnerId' must not be empty.");
|
/**
|
||||||
|
* Gets the output folder for the compiler in case the output folder mode is
|
||||||
|
* {@link CompilerOutputFolderMode#FIXED_FOLDER}.
|
||||||
|
*
|
||||||
|
* @return The output folder mode for the compiler, see
|
||||||
|
* {@link CompilerOutputFolderMode#FIXED_FOLDER}, may be empty, not
|
||||||
|
* <code>null</code>.
|
||||||
|
*/
|
||||||
|
public String getOutputFolderPath() {
|
||||||
|
|
||||||
|
return assemblerPreferences
|
||||||
|
.getString(AssemblerPreferencesConstants.getCompilerOutputFolderPathName(compilerId, hardware));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the output file extension for the compiler.
|
||||||
|
*
|
||||||
|
* @return The output file extension may be empty, not <code>null</code>.
|
||||||
|
*/
|
||||||
|
public String getOutputFileExtension() {
|
||||||
|
|
||||||
|
return assemblerPreferences
|
||||||
|
.getString(AssemblerPreferencesConstants.getCompilerOutputFileExtensionName(compilerId, hardware));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the id of the default runner to run the output file.
|
||||||
|
*
|
||||||
|
* @return The id of the runner to run the output file, not empty and not
|
||||||
|
* <code>null</code>.
|
||||||
|
*/
|
||||||
|
public String getRunnerId() {
|
||||||
|
String result = assemblerPreferences
|
||||||
|
.getString(AssemblerPreferencesConstants.getCompilerRunnerIdName(compilerId, hardware));
|
||||||
|
if (StringUtility.isEmpty(result)) {
|
||||||
|
result = RunnerId.DEFAULT_APPLICATION;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the executable path for the runner.
|
||||||
|
*
|
||||||
|
* @param runnerId The runner id, not empty and not <code>null</code>.
|
||||||
|
*
|
||||||
|
* @return The executable path for the runner, may be empty, not
|
||||||
|
* <code>null</code>.
|
||||||
|
*/
|
||||||
|
public String getRunnerExecutablePath(String runnerId) {
|
||||||
|
if (runnerId == null) {
|
||||||
|
throw new IllegalArgumentException("Parameter 'runnerId' must not be null.");
|
||||||
|
}
|
||||||
|
if (StringUtility.isEmpty(runnerId)) {
|
||||||
|
throw new IllegalArgumentException("Parameter 'runnerId' must not be empty.");
|
||||||
|
}
|
||||||
|
return assemblerPreferences.getString(
|
||||||
|
AssemblerPreferencesConstants.getCompilerRunnerExecutablePathName(compilerId, hardware, runnerId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the parameters for the runner.
|
||||||
|
*
|
||||||
|
* @param runnerId The runner id, not empty and not <code>null</code>.
|
||||||
|
*
|
||||||
|
* @return The parameters for the runner, may be empty, not <code>null</code>.
|
||||||
|
*/
|
||||||
|
public String getRunnerCommandLine(String runnerId) {
|
||||||
|
if (runnerId == null) {
|
||||||
|
throw new IllegalArgumentException("Parameter 'runnerId' must not be null.");
|
||||||
|
}
|
||||||
|
if (StringUtility.isEmpty(runnerId)) {
|
||||||
|
throw new IllegalArgumentException("Parameter 'runnerId' must not be empty.");
|
||||||
|
}
|
||||||
|
return assemblerPreferences.getString(
|
||||||
|
AssemblerPreferencesConstants.getCompilerRunnerCommandLineName(compilerId, hardware, runnerId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the wait for completion indicator for the runner.
|
||||||
|
*
|
||||||
|
* @param runnerId The runner id, not empty and not <code>null</code>.
|
||||||
|
*
|
||||||
|
* @return <code>true</code>if waiting for completion is requested,
|
||||||
|
* <code>false</code> otherwise.
|
||||||
|
*
|
||||||
|
* @since 1.6.1
|
||||||
|
*/
|
||||||
|
public boolean isRunnerWaitForCompletion(String runnerId) {
|
||||||
|
if (runnerId == null) {
|
||||||
|
throw new IllegalArgumentException("Parameter 'runnerId' must not be null.");
|
||||||
|
}
|
||||||
|
if (StringUtility.isEmpty(runnerId)) {
|
||||||
|
throw new IllegalArgumentException("Parameter 'runnerId' must not be empty.");
|
||||||
|
}
|
||||||
|
return assemblerPreferences.getBoolean(
|
||||||
|
AssemblerPreferencesConstants.getCompilerRunnerWaitForCompletionName(compilerId, hardware, runnerId));
|
||||||
}
|
}
|
||||||
return assemblerPreferences.getBoolean(AssemblerPreferencesConstants.getCompilerRunnerWaitForCompletionName(
|
|
||||||
compilerId, hardware, runnerId));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<classpath>
|
<classpath>
|
||||||
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
|
<classpathentry kind="con"
|
||||||
<classpathentry kind="src" path="src"/>
|
path="org.eclipse.pde.core.requiredPlugins" />
|
||||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
<classpathentry kind="src" path="src" />
|
||||||
<classpathentry combineaccessrules="false" kind="src" path="/com.wudsn.ide.base"/>
|
<classpathentry kind="con"
|
||||||
<classpathentry kind="output" path="bin"/>
|
path="org.eclipse.jdt.launching.JRE_CONTAINER" />
|
||||||
|
<classpathentry combineaccessrules="false" kind="src"
|
||||||
|
path="/com.wudsn.ide.base" />
|
||||||
|
<classpathentry kind="output" path="bin" />
|
||||||
</classpath>
|
</classpath>
|
||||||
|
|
|
@ -2,46 +2,42 @@ package com.wudsn.ide.hex;
|
||||||
|
|
||||||
public interface FileContent {
|
public interface FileContent {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the length of the file content.
|
* Gets the length of the file content.
|
||||||
*
|
*
|
||||||
* @return The length of the file content, a non-negative integer.
|
* @return The length of the file content, a non-negative integer.
|
||||||
*/
|
*/
|
||||||
public int getLength();
|
public int getLength();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a byte (8 bit) from the file content.
|
* Gets a byte (8 bit) from the file content.
|
||||||
*
|
*
|
||||||
* @param offset
|
* @param offset The offset, a non-negative integer.
|
||||||
* The offset, a non-negative integer.
|
* @return The byte from the file content.
|
||||||
* @return The byte from the file content.
|
*/
|
||||||
*/
|
public int getByte(long offset);
|
||||||
public int getByte(long offset);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a word (16 bit) in little endian format from the file content.
|
* Gets a word (16 bit) in little endian format from the file content.
|
||||||
*
|
*
|
||||||
* @param offset
|
* @param offset The offset, a non-negative integer.
|
||||||
* The offset, a non-negative integer.
|
* @return The word from the file content.
|
||||||
* @return The word from the file content.
|
*/
|
||||||
*/
|
public int getWord(long offset);
|
||||||
public int getWord(long offset);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a word (16 bit) in big endian format from the file content.
|
* Gets a word (16 bit) in big endian format from the file content.
|
||||||
*
|
*
|
||||||
* @param offset
|
* @param offset The offset, a non-negative integer.
|
||||||
* The offset, a non-negative integer.
|
* @return The word from the file content.
|
||||||
* @return The word from the file content.
|
*/
|
||||||
*/
|
public int getWordBigEndian(long offset);
|
||||||
public int getWordBigEndian(long offset);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a double word (32 bit) in big endian format from the file content.
|
* Gets a double word (32 bit) in big endian format from the file content.
|
||||||
*
|
*
|
||||||
* @param offset
|
* @param offset The offset, a non-negative integer.
|
||||||
* The offset, a non-negative integer.
|
* @return The word from the file content.
|
||||||
* @return The word from the file content.
|
*/
|
||||||
*/
|
public long getDoubleWordBigEndian(long offset);
|
||||||
public long getDoubleWordBigEndian(long offset);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,78 +1,74 @@
|
||||||
package com.wudsn.ide.hex;
|
package com.wudsn.ide.hex;
|
||||||
|
|
||||||
public class FileContentImpl implements FileContent{
|
public class FileContentImpl implements FileContent {
|
||||||
|
|
||||||
private byte[] fileContent;
|
private byte[] fileContent;
|
||||||
|
|
||||||
public FileContentImpl(byte[] fileContent) {
|
public FileContentImpl(byte[] fileContent) {
|
||||||
if (fileContent == null) {
|
if (fileContent == null) {
|
||||||
throw new IllegalArgumentException("Parameter 'fileContent' must not be null.");
|
throw new IllegalArgumentException("Parameter 'fileContent' must not be null.");
|
||||||
|
}
|
||||||
|
this.fileContent = fileContent;
|
||||||
}
|
}
|
||||||
this.fileContent = fileContent;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the length of the file content.
|
* Gets the length of the file content.
|
||||||
*
|
*
|
||||||
* @return The length of the file content, a non-negative integer.
|
* @return The length of the file content, a non-negative integer.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int getLength() {
|
public int getLength() {
|
||||||
return fileContent.length;
|
return fileContent.length;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a byte (8 bit) from the file content.
|
|
||||||
*
|
|
||||||
* @param offset
|
|
||||||
* The offset, a non-negative integer.
|
|
||||||
* @return The byte from the file content.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int getByte(long offset) {
|
|
||||||
if (offset < 0) {
|
|
||||||
throw new IllegalArgumentException("Parameter offset=" + offset + " must not be negative");
|
|
||||||
}
|
}
|
||||||
if (offset >= fileContent.length) {
|
|
||||||
throw new IllegalArgumentException(
|
/**
|
||||||
"Parameter offset=" + offset + " must be less than the file content size " + fileContent.length);
|
* Gets a byte (8 bit) from the file content.
|
||||||
|
*
|
||||||
|
* @param offset The offset, a non-negative integer.
|
||||||
|
* @return The byte from the file content.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int getByte(long offset) {
|
||||||
|
if (offset < 0) {
|
||||||
|
throw new IllegalArgumentException("Parameter offset=" + offset + " must not be negative");
|
||||||
|
}
|
||||||
|
if (offset >= fileContent.length) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Parameter offset=" + offset + " must be less than the file content size " + fileContent.length);
|
||||||
|
}
|
||||||
|
return fileContent[(int) offset] & 0xff;
|
||||||
}
|
}
|
||||||
return fileContent[(int) offset] & 0xff;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a word (16 bit) in little endian format from the file content.
|
* Gets a word (16 bit) in little endian format from the file content.
|
||||||
*
|
*
|
||||||
* @param offset
|
* @param offset The offset, a non-negative integer.
|
||||||
* The offset, a non-negative integer.
|
* @return The word from the file content.
|
||||||
* @return The word from the file content.
|
*/
|
||||||
*/
|
@Override
|
||||||
@Override
|
public int getWord(long offset) {
|
||||||
public int getWord(long offset) {
|
return getByte(offset) + 0x100 * getByte(offset + 1);
|
||||||
return getByte(offset) + 0x100 * getByte(offset + 1);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a word (16 bit) in big endian format from the file content.
|
* Gets a word (16 bit) in big endian format from the file content.
|
||||||
*
|
*
|
||||||
* @param offset
|
* @param offset The offset, a non-negative integer.
|
||||||
* The offset, a non-negative integer.
|
* @return The word from the file content.
|
||||||
* @return The word from the file content.
|
*/
|
||||||
*/
|
@Override
|
||||||
@Override
|
public int getWordBigEndian(long offset) {
|
||||||
public int getWordBigEndian(long offset) {
|
return getByte(offset + 1) + 0x100 * getByte(offset);
|
||||||
return getByte(offset + 1) + 0x100 * getByte(offset);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a double word (32 bit) in big endian format from the file content.
|
* Gets a double word (32 bit) in big endian format from the file content.
|
||||||
*
|
*
|
||||||
* @param offset
|
* @param offset The offset, a non-negative integer.
|
||||||
* The offset, a non-negative integer.
|
* @return The word from the file content.
|
||||||
* @return The word from the file content.
|
*/
|
||||||
*/
|
@Override
|
||||||
@Override
|
public long getDoubleWordBigEndian(long offset) {
|
||||||
public long getDoubleWordBigEndian(long offset) {
|
return getWordBigEndian(offset + 2) + 0x10000 * getWordBigEndian(offset);
|
||||||
return getWordBigEndian(offset + 2) + 0x10000 * getWordBigEndian(offset);
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,147 +37,147 @@ import com.wudsn.ide.base.common.NumberUtility;
|
||||||
*/
|
*/
|
||||||
public final class HexEditorClipboardCommandHandler extends HexEditorSelectionCommandHandler {
|
public final class HexEditorClipboardCommandHandler extends HexEditorSelectionCommandHandler {
|
||||||
|
|
||||||
public static final class CommandIds {
|
public static final class CommandIds {
|
||||||
|
|
||||||
private CommandIds() {
|
private CommandIds() {
|
||||||
}
|
|
||||||
|
|
||||||
public static final String COPY = "com.wudsn.ide.hex.HexEditorCopyToClipboardCommand";
|
|
||||||
public static final String COPY_AS_HEX_VALUES = "com.wudsn.ide.hex.HexEditorCopyToClipboardAsHexValuesCommand";
|
|
||||||
public static final String COPY_AS_DECIMAL_VALUES = "com.wudsn.ide.hex.HexEditorCopyToClipboardAsDecimalValuesCommand";
|
|
||||||
public static final String COPY_AS_DECIMAL_VALUES_BLOCK = "com.wudsn.ide.hex.HexEditorCopyToClipboardAsDecimalValuesBlockCommand";
|
|
||||||
public static final String COPY_AS_ASCII_STRING = "com.wudsn.ide.hex.HexEditorCopyToClipboardAsASCIIStringCommand";
|
|
||||||
public static final String PASTE = "com.wudsn.ide.hex.HexEditorPasteFromClipboardCommand";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creation is public. Called by extension point "org.eclipse.ui.handlers".
|
|
||||||
*/
|
|
||||||
public HexEditorClipboardCommandHandler() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void performAction() throws ExecutionException {
|
|
||||||
|
|
||||||
byte[] bytes;
|
|
||||||
bytes = hexEditorSelection.getBytes();
|
|
||||||
StringBuilder builder = new StringBuilder(5 * bytes.length);
|
|
||||||
String lineSeparator = System.getProperty("line.separator");
|
|
||||||
|
|
||||||
Object[] data;
|
|
||||||
Transfer[] transfers;
|
|
||||||
|
|
||||||
int bytesPerRow = hexEditor.getBytesPerRow();
|
|
||||||
if (commandId.equals(CommandIds.COPY) && !hexEditorSelection.isEmpty()) {
|
|
||||||
data = new Object[] { hexEditorSelection };
|
|
||||||
transfers = new Transfer[] { HexEditorSelectionTransfer.getInstance() };
|
|
||||||
copyToClipboard(bytes, data, transfers);
|
|
||||||
|
|
||||||
} else if ((commandId.equals(CommandIds.COPY_AS_HEX_VALUES)
|
|
||||||
|| commandId.equals(CommandIds.COPY_AS_DECIMAL_VALUES)
|
|
||||||
|| commandId.equals(CommandIds.COPY_AS_DECIMAL_VALUES_BLOCK)
|
|
||||||
|| commandId.equals(CommandIds.COPY_AS_ASCII_STRING)) && !hexEditorSelection.isEmpty()) {
|
|
||||||
if (commandId.equals(CommandIds.COPY_AS_HEX_VALUES)) {
|
|
||||||
builder.append(".byte ");
|
|
||||||
for (int i = 0; i < bytes.length; i++) {
|
|
||||||
builder.append("$");
|
|
||||||
builder.append(HexUtility.getByteValueHexString(bytes[i] & 0xff));
|
|
||||||
if ((i + 1) % bytesPerRow == 0) {
|
|
||||||
builder.append(lineSeparator);
|
|
||||||
if (i < bytes.length - 1) {
|
|
||||||
builder.append(".byte ");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (i < bytes.length - 1) {
|
|
||||||
builder.append(',');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (commandId.equals(CommandIds.COPY_AS_DECIMAL_VALUES)
|
|
||||||
|| commandId.equals(CommandIds.COPY_AS_DECIMAL_VALUES_BLOCK)) {
|
public static final String COPY = "com.wudsn.ide.hex.HexEditorCopyToClipboardCommand";
|
||||||
// In block mode, decimals are aligned to 3 digits.
|
public static final String COPY_AS_HEX_VALUES = "com.wudsn.ide.hex.HexEditorCopyToClipboardAsHexValuesCommand";
|
||||||
boolean block = commandId.equals(CommandIds.COPY_AS_DECIMAL_VALUES_BLOCK);
|
public static final String COPY_AS_DECIMAL_VALUES = "com.wudsn.ide.hex.HexEditorCopyToClipboardAsDecimalValuesCommand";
|
||||||
builder.append(".byte ");
|
public static final String COPY_AS_DECIMAL_VALUES_BLOCK = "com.wudsn.ide.hex.HexEditorCopyToClipboardAsDecimalValuesBlockCommand";
|
||||||
for (int i = 0; i < bytes.length; i++) {
|
public static final String COPY_AS_ASCII_STRING = "com.wudsn.ide.hex.HexEditorCopyToClipboardAsASCIIStringCommand";
|
||||||
int b = bytes[i] & 0xff;
|
public static final String PASTE = "com.wudsn.ide.hex.HexEditorPasteFromClipboardCommand";
|
||||||
if (block) {
|
}
|
||||||
if (b < 10) {
|
|
||||||
builder.append(" ");
|
/**
|
||||||
} else if (b < 100) {
|
* Creation is public. Called by extension point "org.eclipse.ui.handlers".
|
||||||
builder.append(' ');
|
*/
|
||||||
|
public HexEditorClipboardCommandHandler() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void performAction() throws ExecutionException {
|
||||||
|
|
||||||
|
byte[] bytes;
|
||||||
|
bytes = hexEditorSelection.getBytes();
|
||||||
|
StringBuilder builder = new StringBuilder(5 * bytes.length);
|
||||||
|
String lineSeparator = System.getProperty("line.separator");
|
||||||
|
|
||||||
|
Object[] data;
|
||||||
|
Transfer[] transfers;
|
||||||
|
|
||||||
|
int bytesPerRow = hexEditor.getBytesPerRow();
|
||||||
|
if (commandId.equals(CommandIds.COPY) && !hexEditorSelection.isEmpty()) {
|
||||||
|
data = new Object[] { hexEditorSelection };
|
||||||
|
transfers = new Transfer[] { HexEditorSelectionTransfer.getInstance() };
|
||||||
|
copyToClipboard(bytes, data, transfers);
|
||||||
|
|
||||||
|
} else if ((commandId.equals(CommandIds.COPY_AS_HEX_VALUES)
|
||||||
|
|| commandId.equals(CommandIds.COPY_AS_DECIMAL_VALUES)
|
||||||
|
|| commandId.equals(CommandIds.COPY_AS_DECIMAL_VALUES_BLOCK)
|
||||||
|
|| commandId.equals(CommandIds.COPY_AS_ASCII_STRING)) && !hexEditorSelection.isEmpty()) {
|
||||||
|
if (commandId.equals(CommandIds.COPY_AS_HEX_VALUES)) {
|
||||||
|
builder.append(".byte ");
|
||||||
|
for (int i = 0; i < bytes.length; i++) {
|
||||||
|
builder.append("$");
|
||||||
|
builder.append(HexUtility.getByteValueHexString(bytes[i] & 0xff));
|
||||||
|
if ((i + 1) % bytesPerRow == 0) {
|
||||||
|
builder.append(lineSeparator);
|
||||||
|
if (i < bytes.length - 1) {
|
||||||
|
builder.append(".byte ");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (i < bytes.length - 1) {
|
||||||
|
builder.append(',');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (commandId.equals(CommandIds.COPY_AS_DECIMAL_VALUES)
|
||||||
|
|| commandId.equals(CommandIds.COPY_AS_DECIMAL_VALUES_BLOCK)) {
|
||||||
|
// In block mode, decimals are aligned to 3 digits.
|
||||||
|
boolean block = commandId.equals(CommandIds.COPY_AS_DECIMAL_VALUES_BLOCK);
|
||||||
|
builder.append(".byte ");
|
||||||
|
for (int i = 0; i < bytes.length; i++) {
|
||||||
|
int b = bytes[i] & 0xff;
|
||||||
|
if (block) {
|
||||||
|
if (b < 10) {
|
||||||
|
builder.append(" ");
|
||||||
|
} else if (b < 100) {
|
||||||
|
builder.append(' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
builder.append(Integer.toString(b));
|
||||||
|
if ((i + 1) % bytesPerRow == 0) {
|
||||||
|
builder.append(lineSeparator);
|
||||||
|
if (i < bytes.length - 1) {
|
||||||
|
builder.append(".byte ");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (i < bytes.length - 1) {
|
||||||
|
builder.append(',');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (commandId.equals(CommandIds.COPY_AS_ASCII_STRING)) {
|
||||||
|
for (int i = 0; i < bytes.length; i++) {
|
||||||
|
char c = (char) (bytes[i] & 0xff);
|
||||||
|
builder.append(c);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Unknown command '" + commandId + "'.");
|
||||||
}
|
}
|
||||||
}
|
data = new Object[] { builder.toString(), hexEditorSelection };
|
||||||
builder.append(Integer.toString(b));
|
transfers = new Transfer[] { TextTransfer.getInstance(), HexEditorSelectionTransfer.getInstance() };
|
||||||
if ((i + 1) % bytesPerRow == 0) {
|
copyToClipboard(bytes, data, transfers);
|
||||||
builder.append(lineSeparator);
|
|
||||||
if (i < bytes.length - 1) {
|
} else if (commandId.equals(CommandIds.PASTE)) {
|
||||||
builder.append(".byte ");
|
pasteFromClipboard();
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (i < bytes.length - 1) {
|
|
||||||
builder.append(',');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (commandId.equals(CommandIds.COPY_AS_ASCII_STRING)) {
|
|
||||||
for (int i = 0; i < bytes.length; i++) {
|
}
|
||||||
char c = (char) (bytes[i] & 0xff);
|
|
||||||
builder.append(c);
|
private void copyToClipboard(byte[] bytes, Object[] data, Transfer[] transfers) throws ExecutionException {
|
||||||
|
if (bytes == null) {
|
||||||
|
throw new IllegalArgumentException("Parameter 'bytes' must not be null.");
|
||||||
}
|
}
|
||||||
} else {
|
if (data == null) {
|
||||||
throw new IllegalArgumentException("Unknown command '" + commandId + "'.");
|
throw new IllegalArgumentException("Parameter 'data' must not be null.");
|
||||||
}
|
}
|
||||||
data = new Object[] { builder.toString(), hexEditorSelection };
|
if (transfers == null) {
|
||||||
transfers = new Transfer[] { TextTransfer.getInstance(), HexEditorSelectionTransfer.getInstance() };
|
throw new IllegalArgumentException("Parameter 'transfers' must not be null.");
|
||||||
copyToClipboard(bytes, data, transfers);
|
}
|
||||||
|
IWorkbenchSite site = HandlerUtil.getActiveSiteChecked(event);
|
||||||
|
Clipboard clipboard = new Clipboard(site.getShell().getDisplay());
|
||||||
|
try {
|
||||||
|
|
||||||
} else if (commandId.equals(CommandIds.PASTE)) {
|
clipboard.setContents(data, transfers);
|
||||||
pasteFromClipboard();
|
|
||||||
|
} finally {
|
||||||
|
clipboard.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
// INFO: ${0} ({1}) bytes copied to clipboard.
|
||||||
|
messageManager.sendMessage(0, IStatus.OK, Texts.MESSAGE_I302, HexUtility.getLongValueHexString(bytes.length),
|
||||||
|
NumberUtility.getLongValueDecimalString(bytes.length));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
private void pasteFromClipboard() throws ExecutionException {
|
||||||
|
|
||||||
|
IWorkbenchSite site = HandlerUtil.getActiveSiteChecked(event);
|
||||||
|
Clipboard clipboard = new Clipboard(site.getShell().getDisplay());
|
||||||
|
try {
|
||||||
|
|
||||||
|
Object data = clipboard.getContents(HexEditorSelectionTransfer.getInstance());
|
||||||
|
if (data != null) {
|
||||||
|
byte[] bytes = ((HexEditorSelection) data).getBytes();
|
||||||
|
hexEditor.pasteFromClipboard(bytes);
|
||||||
|
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
clipboard.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
private void copyToClipboard(byte[] bytes, Object[] data, Transfer[] transfers) throws ExecutionException {
|
|
||||||
if (bytes == null) {
|
|
||||||
throw new IllegalArgumentException("Parameter 'bytes' must not be null.");
|
|
||||||
}
|
}
|
||||||
if (data == null) {
|
|
||||||
throw new IllegalArgumentException("Parameter 'data' must not be null.");
|
|
||||||
}
|
|
||||||
if (transfers == null) {
|
|
||||||
throw new IllegalArgumentException("Parameter 'transfers' must not be null.");
|
|
||||||
}
|
|
||||||
IWorkbenchSite site = HandlerUtil.getActiveSiteChecked(event);
|
|
||||||
Clipboard clipboard = new Clipboard(site.getShell().getDisplay());
|
|
||||||
try {
|
|
||||||
|
|
||||||
clipboard.setContents(data, transfers);
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
clipboard.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
// INFO: ${0} ({1}) bytes copied to clipboard.
|
|
||||||
messageManager.sendMessage(0, IStatus.OK, Texts.MESSAGE_I302, HexUtility.getLongValueHexString(bytes.length),
|
|
||||||
NumberUtility.getLongValueDecimalString(bytes.length));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void pasteFromClipboard() throws ExecutionException {
|
|
||||||
|
|
||||||
IWorkbenchSite site = HandlerUtil.getActiveSiteChecked(event);
|
|
||||||
Clipboard clipboard = new Clipboard(site.getShell().getDisplay());
|
|
||||||
try {
|
|
||||||
|
|
||||||
Object data = clipboard.getContents(HexEditorSelectionTransfer.getInstance());
|
|
||||||
if (data != null) {
|
|
||||||
byte[] bytes = ((HexEditorSelection) data).getBytes();
|
|
||||||
hexEditor.pasteFromClipboard(bytes);
|
|
||||||
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
clipboard.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,50 +31,50 @@ import org.eclipse.swt.graphics.Image;
|
||||||
*/
|
*/
|
||||||
final class HexEditorContentOutlineLabelProvider extends DelegatingStyledCellLabelProvider {
|
final class HexEditorContentOutlineLabelProvider extends DelegatingStyledCellLabelProvider {
|
||||||
|
|
||||||
/** Outline segment image */
|
/** Outline segment image */
|
||||||
private final Image segmentImage;
|
private final Image segmentImage;
|
||||||
|
|
||||||
private static class HexEditorStyledLabelProvider extends LabelProvider implements IStyledLabelProvider {
|
private static class HexEditorStyledLabelProvider extends LabelProvider implements IStyledLabelProvider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creation is local.
|
||||||
|
*/
|
||||||
|
HexEditorStyledLabelProvider() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StyledString getStyledText(Object element) {
|
||||||
|
if (element == null) {
|
||||||
|
throw new IllegalArgumentException("Parameter 'element' must not be null.");
|
||||||
|
}
|
||||||
|
HexEditorContentOutlineTreeObject treeObject;
|
||||||
|
treeObject = (HexEditorContentOutlineTreeObject) element;
|
||||||
|
return treeObject.getStyledString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creation is local.
|
* Creates a new instance.
|
||||||
|
*
|
||||||
|
* Called by
|
||||||
|
* {@link HexEditorContentOutlinePage#createControl(org.eclipse.swt.widgets.Composite)}
|
||||||
|
* .
|
||||||
*/
|
*/
|
||||||
HexEditorStyledLabelProvider() {
|
HexEditorContentOutlineLabelProvider() {
|
||||||
|
super(new HexEditorStyledLabelProvider());
|
||||||
|
HexPlugin plugin;
|
||||||
|
plugin = HexPlugin.getInstance();
|
||||||
|
segmentImage = plugin.getImage("hex-editor-segment-16x16.gif");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public StyledString getStyledText(Object element) {
|
public Image getImage(Object element) {
|
||||||
if (element == null) {
|
Image result;
|
||||||
throw new IllegalArgumentException("Parameter 'element' must not be null.");
|
|
||||||
}
|
result = segmentImage;
|
||||||
HexEditorContentOutlineTreeObject treeObject;
|
|
||||||
treeObject = (HexEditorContentOutlineTreeObject) element;
|
return result;
|
||||||
return treeObject.getStyledString();
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new instance.
|
|
||||||
*
|
|
||||||
* Called by
|
|
||||||
* {@link HexEditorContentOutlinePage#createControl(org.eclipse.swt.widgets.Composite)}
|
|
||||||
* .
|
|
||||||
*/
|
|
||||||
HexEditorContentOutlineLabelProvider() {
|
|
||||||
super(new HexEditorStyledLabelProvider());
|
|
||||||
HexPlugin plugin;
|
|
||||||
plugin = HexPlugin.getInstance();
|
|
||||||
segmentImage = plugin.getImage("hex-editor-segment-16x16.gif");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Image getImage(Object element) {
|
|
||||||
Image result;
|
|
||||||
|
|
||||||
result = segmentImage;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,52 +34,52 @@ import org.eclipse.ui.views.contentoutline.ContentOutlinePage;
|
||||||
*/
|
*/
|
||||||
final class HexEditorContentOutlinePage extends ContentOutlinePage {
|
final class HexEditorContentOutlinePage extends ContentOutlinePage {
|
||||||
|
|
||||||
private HexEditor editor;
|
private HexEditor editor;
|
||||||
private Object input;
|
private Object input;
|
||||||
|
|
||||||
|
HexEditorContentOutlinePage(HexEditor editor) {
|
||||||
|
if (editor == null) {
|
||||||
|
throw new IllegalArgumentException("Parameter 'editor' must not be null.");
|
||||||
|
}
|
||||||
|
this.editor = editor;
|
||||||
|
|
||||||
HexEditorContentOutlinePage(HexEditor editor) {
|
|
||||||
if (editor == null) {
|
|
||||||
throw new IllegalArgumentException("Parameter 'editor' must not be null.");
|
|
||||||
}
|
}
|
||||||
this.editor = editor;
|
|
||||||
|
|
||||||
}
|
@Override
|
||||||
|
public void createControl(Composite parent) {
|
||||||
|
super.createControl(parent);
|
||||||
|
|
||||||
@Override
|
TreeViewer viewer = getTreeViewer();
|
||||||
public void createControl(Composite parent) {
|
viewer.getControl().setFont(JFaceResources.getTextFont());
|
||||||
super.createControl(parent);
|
viewer.setContentProvider(new HexEditorContentOutlineTreeContentProvider());
|
||||||
|
viewer.setLabelProvider(new HexEditorContentOutlineLabelProvider());
|
||||||
|
viewer.addSelectionChangedListener(this);
|
||||||
|
viewer.setAutoExpandLevel(AbstractTreeViewer.ALL_LEVELS);
|
||||||
|
|
||||||
TreeViewer viewer = getTreeViewer();
|
updateTreeView();
|
||||||
viewer.getControl().setFont(JFaceResources.getTextFont());
|
|
||||||
viewer.setContentProvider(new HexEditorContentOutlineTreeContentProvider());
|
|
||||||
viewer.setLabelProvider(new HexEditorContentOutlineLabelProvider());
|
|
||||||
viewer.addSelectionChangedListener(this);
|
|
||||||
viewer.setAutoExpandLevel(AbstractTreeViewer.ALL_LEVELS);
|
|
||||||
|
|
||||||
updateTreeView();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void selectionChanged(SelectionChangedEvent event) {
|
|
||||||
super.selectionChanged(event);
|
|
||||||
|
|
||||||
ISelection selection = event.getSelection();
|
|
||||||
editor.setSelection(selection);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setInput(Object input) {
|
|
||||||
if (input == null) {
|
|
||||||
throw new IllegalArgumentException("Parameter 'input' must not be null.");
|
|
||||||
}
|
}
|
||||||
this.input = input;
|
|
||||||
updateTreeView();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateTreeView() {
|
@Override
|
||||||
TreeViewer viewer = getTreeViewer();
|
public void selectionChanged(SelectionChangedEvent event) {
|
||||||
if (viewer != null) {
|
super.selectionChanged(event);
|
||||||
viewer.setInput(input);
|
|
||||||
|
ISelection selection = event.getSelection();
|
||||||
|
editor.setSelection(selection);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setInput(Object input) {
|
||||||
|
if (input == null) {
|
||||||
|
throw new IllegalArgumentException("Parameter 'input' must not be null.");
|
||||||
|
}
|
||||||
|
this.input = input;
|
||||||
|
updateTreeView();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateTreeView() {
|
||||||
|
TreeViewer viewer = getTreeViewer();
|
||||||
|
if (viewer != null) {
|
||||||
|
viewer.setInput(input);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,63 +31,63 @@ import org.eclipse.jface.viewers.Viewer;
|
||||||
*/
|
*/
|
||||||
final class HexEditorContentOutlineTreeContentProvider implements ITreeContentProvider {
|
final class HexEditorContentOutlineTreeContentProvider implements ITreeContentProvider {
|
||||||
|
|
||||||
HexEditorContentOutlineTreeContentProvider() {
|
HexEditorContentOutlineTreeContentProvider() {
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Object[] getChildren(Object parentElement) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Object getParent(Object element) {
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean hasChildren(Object element) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Object[] getElements(Object inputElement) {
|
|
||||||
Object[] result;
|
|
||||||
if (inputElement instanceof List<?>) {
|
|
||||||
result = ((List<?>) inputElement).toArray();
|
|
||||||
} else {
|
|
||||||
result = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
/**
|
||||||
}
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Object[] getChildren(Object parentElement) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void dispose() {
|
public Object getParent(Object element) {
|
||||||
|
|
||||||
}
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
|
public boolean hasChildren(Object element) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Object[] getElements(Object inputElement) {
|
||||||
|
Object[] result;
|
||||||
|
if (inputElement instanceof List<?>) {
|
||||||
|
result = ((List<?>) inputElement).toArray();
|
||||||
|
} else {
|
||||||
|
result = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void dispose() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,122 +28,117 @@ import org.eclipse.jface.viewers.StyledString;
|
||||||
*/
|
*/
|
||||||
public final class HexEditorContentOutlineTreeObject {
|
public final class HexEditorContentOutlineTreeObject {
|
||||||
|
|
||||||
private final StyledString styledString;
|
private final StyledString styledString;
|
||||||
private long fileStartOffset;
|
private long fileStartOffset;
|
||||||
private long textStartOffset;
|
private long textStartOffset;
|
||||||
private long fileEndOffset;
|
private long fileEndOffset;
|
||||||
private long textEndOffset;
|
private long textEndOffset;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new instance.
|
* Create a new instance.
|
||||||
*
|
*
|
||||||
* @param styledString
|
* @param styledString The styled string of the instance, may be empty not
|
||||||
* The styled string of the instance, may be empty not
|
* <code>null</code>.
|
||||||
* <code>null</code>.
|
*/
|
||||||
*/
|
public HexEditorContentOutlineTreeObject(StyledString styledString) {
|
||||||
public HexEditorContentOutlineTreeObject(StyledString styledString) {
|
if (styledString == null) {
|
||||||
if (styledString == null) {
|
throw new IllegalArgumentException("Parameter 'styledString' must not be null.");
|
||||||
throw new IllegalArgumentException("Parameter 'styledString' must not be null.");
|
}
|
||||||
|
this.styledString = new StyledString().append(styledString);
|
||||||
}
|
}
|
||||||
this.styledString = new StyledString().append(styledString);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the styled string of the object.
|
* Gets the styled string of the object.
|
||||||
*
|
*
|
||||||
* @return The styled string, not <code>null</code>.
|
* @return The styled string, not <code>null</code>.
|
||||||
*/
|
*/
|
||||||
public StyledString getStyledString() {
|
public StyledString getStyledString() {
|
||||||
return styledString;
|
return styledString;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the start offset of the tree object in the file.
|
|
||||||
*
|
|
||||||
* @return The start offset, a non-negative integer.
|
|
||||||
*/
|
|
||||||
public long getFileStartOffset() {
|
|
||||||
return fileStartOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the start offset of the tree object in the file.
|
|
||||||
*
|
|
||||||
* @param fileOffset
|
|
||||||
* The start offset, a non-negative integer or <code>-1</code> if
|
|
||||||
* the offset is not defined.
|
|
||||||
*/
|
|
||||||
public void setFileStartOffset(long fileOffset) {
|
|
||||||
|
|
||||||
this.fileStartOffset = fileOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the end offset of the tree object in the file.
|
|
||||||
*
|
|
||||||
* @return The end offset, a non-negative integer or <code>-1</code> if the
|
|
||||||
* offset is not defined.
|
|
||||||
*/
|
|
||||||
public long getFileEndOffset() {
|
|
||||||
return fileEndOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the end offset of the tree object in the file or <code>-1</code> if
|
|
||||||
* the offset is not defined.
|
|
||||||
*
|
|
||||||
* @param fileOffset
|
|
||||||
* The end offset, a non-negative integer or <code>-1</code> if
|
|
||||||
* the offset is not defined.
|
|
||||||
*/
|
|
||||||
public void setFileEndOffset(long fileOffset) {
|
|
||||||
|
|
||||||
this.fileEndOffset = fileOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the start offset of the tree object in the text.
|
|
||||||
*
|
|
||||||
* @return The offset, a non-negative integer.
|
|
||||||
*/
|
|
||||||
public long getTextStartOffset() {
|
|
||||||
return textStartOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets text start offset of the tree object in the text
|
|
||||||
*
|
|
||||||
* @param textOffset
|
|
||||||
* The offset, a non-negative integer.
|
|
||||||
*/
|
|
||||||
public void setTextStartOffset(long textOffset) {
|
|
||||||
if (textOffset < 0) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Parameter 'textOffset' must not be negative. Specified value is " + textOffset + ".");
|
|
||||||
}
|
}
|
||||||
this.textStartOffset = textOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the end offset of the tree object in the text.
|
* Gets the start offset of the tree object in the file.
|
||||||
*
|
*
|
||||||
* @return The offset, a non-negative integer.
|
* @return The start offset, a non-negative integer.
|
||||||
*/
|
*/
|
||||||
public long getTextEndOffset() {
|
public long getFileStartOffset() {
|
||||||
return textEndOffset;
|
return fileStartOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets text end offset of the tree object in the text
|
* Sets the start offset of the tree object in the file.
|
||||||
*
|
*
|
||||||
* @param textOffset
|
* @param fileOffset The start offset, a non-negative integer or <code>-1</code>
|
||||||
* The offset, a non-negative integer.
|
* if the offset is not defined.
|
||||||
*/
|
*/
|
||||||
public void setTextEndOffset(int textOffset) {
|
public void setFileStartOffset(long fileOffset) {
|
||||||
if (textOffset < 0) {
|
|
||||||
throw new IllegalArgumentException(
|
this.fileStartOffset = fileOffset;
|
||||||
"Parameter 'textOffset' must not be negative. Specified value is " + textOffset + ".");
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the end offset of the tree object in the file.
|
||||||
|
*
|
||||||
|
* @return The end offset, a non-negative integer or <code>-1</code> if the
|
||||||
|
* offset is not defined.
|
||||||
|
*/
|
||||||
|
public long getFileEndOffset() {
|
||||||
|
return fileEndOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the end offset of the tree object in the file or <code>-1</code> if the
|
||||||
|
* offset is not defined.
|
||||||
|
*
|
||||||
|
* @param fileOffset The end offset, a non-negative integer or <code>-1</code>
|
||||||
|
* if the offset is not defined.
|
||||||
|
*/
|
||||||
|
public void setFileEndOffset(long fileOffset) {
|
||||||
|
|
||||||
|
this.fileEndOffset = fileOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the start offset of the tree object in the text.
|
||||||
|
*
|
||||||
|
* @return The offset, a non-negative integer.
|
||||||
|
*/
|
||||||
|
public long getTextStartOffset() {
|
||||||
|
return textStartOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets text start offset of the tree object in the text
|
||||||
|
*
|
||||||
|
* @param textOffset The offset, a non-negative integer.
|
||||||
|
*/
|
||||||
|
public void setTextStartOffset(long textOffset) {
|
||||||
|
if (textOffset < 0) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Parameter 'textOffset' must not be negative. Specified value is " + textOffset + ".");
|
||||||
|
}
|
||||||
|
this.textStartOffset = textOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the end offset of the tree object in the text.
|
||||||
|
*
|
||||||
|
* @return The offset, a non-negative integer.
|
||||||
|
*/
|
||||||
|
public long getTextEndOffset() {
|
||||||
|
return textEndOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets text end offset of the tree object in the text
|
||||||
|
*
|
||||||
|
* @param textOffset The offset, a non-negative integer.
|
||||||
|
*/
|
||||||
|
public void setTextEndOffset(int textOffset) {
|
||||||
|
if (textOffset < 0) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Parameter 'textOffset' must not be negative. Specified value is " + textOffset + ".");
|
||||||
|
}
|
||||||
|
this.textEndOffset = textOffset;
|
||||||
}
|
}
|
||||||
this.textEndOffset = textOffset;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,10 +28,10 @@ import com.wudsn.ide.base.editor.CommonOpenEditorCommandHandler;
|
||||||
*/
|
*/
|
||||||
public final class HexEditorOpenCommandHandler extends CommonOpenEditorCommandHandler {
|
public final class HexEditorOpenCommandHandler extends CommonOpenEditorCommandHandler {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creation is public. Called by extension "org.eclipse.ui.popupMenus".
|
* Creation is public. Called by extension "org.eclipse.ui.popupMenus".
|
||||||
*/
|
*/
|
||||||
public HexEditorOpenCommandHandler() {
|
public HexEditorOpenCommandHandler() {
|
||||||
super(HexEditor.ID);
|
super(HexEditor.ID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,169 +28,150 @@ import com.wudsn.ide.base.common.TextUtility;
|
||||||
|
|
||||||
public abstract class HexEditorParser {
|
public abstract class HexEditorParser {
|
||||||
|
|
||||||
private HexEditorParserComponent owner;
|
private HexEditorParserComponent owner;
|
||||||
protected Styler offsetStyler;
|
protected Styler offsetStyler;
|
||||||
protected Styler addressStyler;
|
protected Styler addressStyler;
|
||||||
protected FileContent fileContent;
|
protected FileContent fileContent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creation is protected.
|
* Creation is protected.
|
||||||
*/
|
*/
|
||||||
protected HexEditorParser() {
|
protected HexEditorParser() {
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialized by owner.
|
|
||||||
*
|
|
||||||
* @param owner
|
|
||||||
* The owner, not <code>null</code>.
|
|
||||||
* @param offsetStyler
|
|
||||||
* The offset styler, not <code>null</code>.
|
|
||||||
* @param addressStyler
|
|
||||||
* The address styler, not <code>null</code>.
|
|
||||||
*/
|
|
||||||
void init(HexEditorParserComponent owner, Styler offsetStyler, Styler addressStyler) {
|
|
||||||
if (owner == null) {
|
|
||||||
throw new IllegalArgumentException("Parameter 'owner' must not be null.");
|
|
||||||
}
|
|
||||||
if (offsetStyler == null) {
|
|
||||||
throw new IllegalArgumentException("Parameter 'offsetStyler' must not be null.");
|
|
||||||
}
|
|
||||||
if (addressStyler == null) {
|
|
||||||
throw new IllegalArgumentException("Parameter 'offsetStyler' must not be null.");
|
|
||||||
}
|
|
||||||
this.owner = owner;
|
|
||||||
this.offsetStyler = offsetStyler;
|
|
||||||
this.addressStyler = addressStyler;
|
|
||||||
this.fileContent = owner.getFileContent();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Public API for parsing.
|
|
||||||
*
|
|
||||||
* @param contentBuilder
|
|
||||||
* The content builder, not <code>null</code>.
|
|
||||||
* @return <code>true</code> if parsing was OK, <code>false</code>otherwise.
|
|
||||||
*/
|
|
||||||
public abstract boolean parse(StyledString contentBuilder);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prints a block header in the context area and adds a block to the
|
|
||||||
* outline.
|
|
||||||
*
|
|
||||||
* @param contentBuilder
|
|
||||||
* The content builder, not <code>null</code>.
|
|
||||||
* @param blockHeaderText
|
|
||||||
* The header text for the block, may be empty, not
|
|
||||||
* <code>null</code>.
|
|
||||||
* @param blockHeaderNumber
|
|
||||||
* The block count or <code>-1</code> if count shall not be
|
|
||||||
* displayed.
|
|
||||||
* @param blockHeaderParameterText
|
|
||||||
* The pattern text of the form "{0}-{1} ({2})"
|
|
||||||
* @param offset
|
|
||||||
* The start offset, a non-negative integer.
|
|
||||||
* @param startAddress
|
|
||||||
* The start address, a non-negative integer.
|
|
||||||
* @param endAddress
|
|
||||||
* The end address, a non-negative integer.
|
|
||||||
*
|
|
||||||
* @return The tree object representing the block.
|
|
||||||
*/
|
|
||||||
protected final HexEditorContentOutlineTreeObject printBlockHeader(StyledString contentBuilder,
|
|
||||||
String blockHeaderText, int blockHeaderNumber, String blockHeaderParameterText, long offset,
|
|
||||||
long startAddress, long endAddress) {
|
|
||||||
|
|
||||||
if (contentBuilder == null) {
|
|
||||||
throw new IllegalArgumentException("Parameter 'contentBuilder' must not be null.");
|
|
||||||
}
|
|
||||||
long blockLength = endAddress - startAddress + 1;
|
|
||||||
String blockHeaderNumberText;
|
|
||||||
if (blockHeaderNumber >= 0) {
|
|
||||||
blockHeaderNumberText = NumberUtility.getLongValueDecimalString(blockHeaderNumber);
|
|
||||||
} else {
|
|
||||||
blockHeaderNumberText = "";
|
|
||||||
}
|
|
||||||
int length = Math.max(4, HexUtility.getLongValueHexLength(endAddress));
|
|
||||||
String hexText = TextUtility.format(blockHeaderParameterText,
|
|
||||||
HexUtility.getLongValueHexString(startAddress, length),
|
|
||||||
HexUtility.getLongValueHexString(endAddress, length),
|
|
||||||
HexUtility.getLongValueHexString(blockLength, length));
|
|
||||||
|
|
||||||
String decimalText = TextUtility.format(blockHeaderParameterText,
|
|
||||||
NumberUtility.getLongValueDecimalString(startAddress),
|
|
||||||
NumberUtility.getLongValueDecimalString(endAddress),
|
|
||||||
NumberUtility.getLongValueDecimalString(blockLength));
|
|
||||||
|
|
||||||
StyledString styledString;
|
|
||||||
styledString = new StyledString();
|
|
||||||
styledString.append(blockHeaderText, offsetStyler);
|
|
||||||
if (blockHeaderNumber >= 0) {
|
|
||||||
styledString.append(" ");
|
|
||||||
styledString.append(blockHeaderNumberText, offsetStyler);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
if (StringUtility.isSpecified(blockHeaderParameterText)) {
|
|
||||||
styledString.append(" : ");
|
/**
|
||||||
styledString.append(hexText, addressStyler);
|
* Initialized by owner.
|
||||||
styledString.append(" : ");
|
*
|
||||||
styledString.append(decimalText);
|
* @param owner The owner, not <code>null</code>.
|
||||||
|
* @param offsetStyler The offset styler, not <code>null</code>.
|
||||||
|
* @param addressStyler The address styler, not <code>null</code>.
|
||||||
|
*/
|
||||||
|
void init(HexEditorParserComponent owner, Styler offsetStyler, Styler addressStyler) {
|
||||||
|
if (owner == null) {
|
||||||
|
throw new IllegalArgumentException("Parameter 'owner' must not be null.");
|
||||||
|
}
|
||||||
|
if (offsetStyler == null) {
|
||||||
|
throw new IllegalArgumentException("Parameter 'offsetStyler' must not be null.");
|
||||||
|
}
|
||||||
|
if (addressStyler == null) {
|
||||||
|
throw new IllegalArgumentException("Parameter 'offsetStyler' must not be null.");
|
||||||
|
}
|
||||||
|
this.owner = owner;
|
||||||
|
this.offsetStyler = offsetStyler;
|
||||||
|
this.addressStyler = addressStyler;
|
||||||
|
this.fileContent = owner.getFileContent();
|
||||||
}
|
}
|
||||||
|
|
||||||
contentBuilder.append(blockHeaderText, offsetStyler);
|
/**
|
||||||
if (blockHeaderNumber >= 0) {
|
* Public API for parsing.
|
||||||
contentBuilder.append(" ");
|
*
|
||||||
contentBuilder.append(blockHeaderNumberText, offsetStyler);
|
* @param contentBuilder The content builder, not <code>null</code>.
|
||||||
|
* @return <code>true</code> if parsing was OK, <code>false</code>otherwise.
|
||||||
|
*/
|
||||||
|
public abstract boolean parse(StyledString contentBuilder);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints a block header in the context area and adds a block to the outline.
|
||||||
|
*
|
||||||
|
* @param contentBuilder The content builder, not <code>null</code>.
|
||||||
|
* @param blockHeaderText The header text for the block, may be empty,
|
||||||
|
* not <code>null</code>.
|
||||||
|
* @param blockHeaderNumber The block count or <code>-1</code> if count
|
||||||
|
* shall not be displayed.
|
||||||
|
* @param blockHeaderParameterText The pattern text of the form "{0}-{1} ({2})"
|
||||||
|
* @param offset The start offset, a non-negative integer.
|
||||||
|
* @param startAddress The start address, a non-negative integer.
|
||||||
|
* @param endAddress The end address, a non-negative integer.
|
||||||
|
*
|
||||||
|
* @return The tree object representing the block.
|
||||||
|
*/
|
||||||
|
protected final HexEditorContentOutlineTreeObject printBlockHeader(StyledString contentBuilder,
|
||||||
|
String blockHeaderText, int blockHeaderNumber, String blockHeaderParameterText, long offset,
|
||||||
|
long startAddress, long endAddress) {
|
||||||
|
|
||||||
|
if (contentBuilder == null) {
|
||||||
|
throw new IllegalArgumentException("Parameter 'contentBuilder' must not be null.");
|
||||||
|
}
|
||||||
|
long blockLength = endAddress - startAddress + 1;
|
||||||
|
String blockHeaderNumberText;
|
||||||
|
if (blockHeaderNumber >= 0) {
|
||||||
|
blockHeaderNumberText = NumberUtility.getLongValueDecimalString(blockHeaderNumber);
|
||||||
|
} else {
|
||||||
|
blockHeaderNumberText = "";
|
||||||
|
}
|
||||||
|
int length = Math.max(4, HexUtility.getLongValueHexLength(endAddress));
|
||||||
|
String hexText = TextUtility.format(blockHeaderParameterText,
|
||||||
|
HexUtility.getLongValueHexString(startAddress, length),
|
||||||
|
HexUtility.getLongValueHexString(endAddress, length),
|
||||||
|
HexUtility.getLongValueHexString(blockLength, length));
|
||||||
|
|
||||||
|
String decimalText = TextUtility.format(blockHeaderParameterText,
|
||||||
|
NumberUtility.getLongValueDecimalString(startAddress),
|
||||||
|
NumberUtility.getLongValueDecimalString(endAddress),
|
||||||
|
NumberUtility.getLongValueDecimalString(blockLength));
|
||||||
|
|
||||||
|
StyledString styledString;
|
||||||
|
styledString = new StyledString();
|
||||||
|
styledString.append(blockHeaderText, offsetStyler);
|
||||||
|
if (blockHeaderNumber >= 0) {
|
||||||
|
styledString.append(" ");
|
||||||
|
styledString.append(blockHeaderNumberText, offsetStyler);
|
||||||
|
|
||||||
|
}
|
||||||
|
if (StringUtility.isSpecified(blockHeaderParameterText)) {
|
||||||
|
styledString.append(" : ");
|
||||||
|
styledString.append(hexText, addressStyler);
|
||||||
|
styledString.append(" : ");
|
||||||
|
styledString.append(decimalText);
|
||||||
|
}
|
||||||
|
|
||||||
|
contentBuilder.append(blockHeaderText, offsetStyler);
|
||||||
|
if (blockHeaderNumber >= 0) {
|
||||||
|
contentBuilder.append(" ");
|
||||||
|
contentBuilder.append(blockHeaderNumberText, offsetStyler);
|
||||||
|
}
|
||||||
|
contentBuilder.append("\n");
|
||||||
|
return owner.printBlockHeader(contentBuilder, styledString, offset);
|
||||||
}
|
}
|
||||||
contentBuilder.append("\n");
|
|
||||||
return owner.printBlockHeader(contentBuilder, styledString, offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a block to the outline.
|
* Adds a block to the outline.
|
||||||
*
|
*
|
||||||
* @param contentBuilder
|
* @param contentBuilder The content builder, not <code>null</code>.
|
||||||
* The content builder, not <code>null</code>.
|
* @param headerStyledString The style string for the block header in the
|
||||||
* @param headerStyledString
|
* outline, not <code>null</code>.
|
||||||
* The style string for the block header in the outline, not
|
* @param offset The start offset, a non-negative integer.
|
||||||
* <code>null</code>.
|
*
|
||||||
* @param offset
|
* @return The tree object representing the block.
|
||||||
* The start offset, a non-negative integer.
|
*/
|
||||||
*
|
protected final HexEditorContentOutlineTreeObject printBlockHeader(StyledString contentBuilder,
|
||||||
* @return The tree object representing the block.
|
StyledString headerStyledString, long offset) {
|
||||||
*/
|
return owner.printBlockHeader(contentBuilder, headerStyledString, offset);
|
||||||
protected final HexEditorContentOutlineTreeObject printBlockHeader(StyledString contentBuilder,
|
}
|
||||||
StyledString headerStyledString, long offset) {
|
|
||||||
return owner.printBlockHeader(contentBuilder, headerStyledString, offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prints the last block in case if contains an error like the wrong number
|
* Prints the last block in case if contains an error like the wrong number of
|
||||||
* of bytes.
|
* bytes.
|
||||||
*
|
*
|
||||||
* @param contentBuilder
|
* @param contentBuilder The content builder, not <code>null</code>.
|
||||||
* The content builder, not <code>null</code>.
|
* @param errorText The error text, not empty and not <code>null</code>.
|
||||||
* @param errorText
|
* @param length The length of the last block, a non-negative integer.
|
||||||
* The error text, not empty and not <code>null</code>.
|
* @param offset The offset of the last block, a non-negative integer.
|
||||||
* @param length
|
*/
|
||||||
* The length of the last block, a non-negative integer.
|
protected final void printBlockWithError(StyledString contentBuilder, String errorText, long length, long offset) {
|
||||||
* @param offset
|
owner.printBlockWithError(contentBuilder, errorText, length, offset);
|
||||||
* The offset of the last block, a non-negative integer.
|
}
|
||||||
*/
|
|
||||||
protected final void printBlockWithError(StyledString contentBuilder, String errorText, long length, long offset) {
|
|
||||||
owner.printBlockWithError(contentBuilder, errorText, length, offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected final void skipByteTextIndex(long offset) {
|
protected final void skipByteTextIndex(long offset) {
|
||||||
owner.skipByteTextIndex(offset);
|
owner.skipByteTextIndex(offset);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final long printBytes(HexEditorContentOutlineTreeObject treeObject, StyledString contentBuilder,
|
protected final long printBytes(HexEditorContentOutlineTreeObject treeObject, StyledString contentBuilder,
|
||||||
long offset, long maxOffset, boolean withStartAddress, int startAddress) {
|
long offset, long maxOffset, boolean withStartAddress, int startAddress) {
|
||||||
return owner.printBytes(treeObject, contentBuilder, offset, maxOffset, withStartAddress, startAddress);
|
return owner.printBytes(treeObject, contentBuilder, offset, maxOffset, withStartAddress, startAddress);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -36,43 +36,43 @@ import com.wudsn.ide.base.common.TextUtility;
|
||||||
|
|
||||||
public final class HexEditorSaveSelectionAsCommandHandler extends HexEditorSelectionCommandHandler {
|
public final class HexEditorSaveSelectionAsCommandHandler extends HexEditorSelectionCommandHandler {
|
||||||
|
|
||||||
public static final class CommandIds {
|
public static final class CommandIds {
|
||||||
|
|
||||||
private CommandIds() {
|
private CommandIds() {
|
||||||
}
|
|
||||||
|
|
||||||
public static final String SAVE_SELECTION_AS = "com.wudsn.ide.hex.HexEditorSaveSelectionAsCommand";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void performAction() throws ExecutionException {
|
|
||||||
if (commandId.equals(CommandIds.SAVE_SELECTION_AS) && !hexEditorSelection.isEmpty()) {
|
|
||||||
Shell shell = HandlerUtil.getActiveShell(event);
|
|
||||||
if (shell == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
byte[] content = hexEditorSelection.getBytes();
|
|
||||||
|
|
||||||
FileDialog dialog = new FileDialog(shell, SWT.SAVE);
|
|
||||||
int length = content.length;
|
|
||||||
String hexLength = HexUtility.getLongValueHexString(length);
|
|
||||||
String decimalLength = NumberUtility.getLongValueDecimalString(length);
|
|
||||||
dialog.setText(
|
|
||||||
TextUtility.format(Texts.HEX_EDITOR_SAVE_SELECTION_AS_DIALOG_TITLE, hexLength, decimalLength));
|
|
||||||
dialog.setFileName(hexEditor.getSelectionSaveFilePath());
|
|
||||||
String filePath = dialog.open();
|
|
||||||
if (filePath != null) {
|
|
||||||
try {
|
|
||||||
FileUtility.writeBytes(new File(filePath), content);
|
|
||||||
// INFO: ${0} ({1}) bytes saved as '{2}'.
|
|
||||||
hexEditor.getMessageManager().sendMessage(0, IStatus.OK, Texts.MESSAGE_I303, hexLength,
|
|
||||||
decimalLength, filePath);
|
|
||||||
} catch (CoreException ex) {
|
|
||||||
throw new ExecutionException(ex.getMessage());
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public static final String SAVE_SELECTION_AS = "com.wudsn.ide.hex.HexEditorSaveSelectionAsCommand";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
@Override
|
||||||
|
protected void performAction() throws ExecutionException {
|
||||||
|
if (commandId.equals(CommandIds.SAVE_SELECTION_AS) && !hexEditorSelection.isEmpty()) {
|
||||||
|
Shell shell = HandlerUtil.getActiveShell(event);
|
||||||
|
if (shell == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
byte[] content = hexEditorSelection.getBytes();
|
||||||
|
|
||||||
|
FileDialog dialog = new FileDialog(shell, SWT.SAVE);
|
||||||
|
int length = content.length;
|
||||||
|
String hexLength = HexUtility.getLongValueHexString(length);
|
||||||
|
String decimalLength = NumberUtility.getLongValueDecimalString(length);
|
||||||
|
dialog.setText(
|
||||||
|
TextUtility.format(Texts.HEX_EDITOR_SAVE_SELECTION_AS_DIALOG_TITLE, hexLength, decimalLength));
|
||||||
|
dialog.setFileName(hexEditor.getSelectionSaveFilePath());
|
||||||
|
String filePath = dialog.open();
|
||||||
|
if (filePath != null) {
|
||||||
|
try {
|
||||||
|
FileUtility.writeBytes(new File(filePath), content);
|
||||||
|
// INFO: ${0} ({1}) bytes saved as '{2}'.
|
||||||
|
hexEditor.getMessageManager().sendMessage(0, IStatus.OK, Texts.MESSAGE_I303, hexLength,
|
||||||
|
decimalLength, filePath);
|
||||||
|
} catch (CoreException ex) {
|
||||||
|
throw new ExecutionException(ex.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,78 +29,75 @@ import org.eclipse.jface.viewers.ISelection;
|
||||||
*/
|
*/
|
||||||
final class HexEditorSelection implements ISelection {
|
final class HexEditorSelection implements ISelection {
|
||||||
|
|
||||||
private long startOffset;
|
private long startOffset;
|
||||||
private long endOffset;
|
private long endOffset;
|
||||||
private byte[] bytes;
|
private byte[] bytes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new selection.
|
* Creates a new selection.
|
||||||
*
|
*
|
||||||
* @param startOffset
|
* @param startOffset The start offset in the original array, a non-negative
|
||||||
* The start offset in the original array, a non-negative number.
|
* number.
|
||||||
* @param endOffset
|
* @param endOffset The end offset in the original array, a non-negative
|
||||||
* The end offset in the original array, a non-negative number
|
* number greater or equal to the start offset.
|
||||||
* greater or equal to the start offset.
|
* @param bytes The content of the selection, may be empty, not
|
||||||
* @param bytes
|
* <code>null</code>.
|
||||||
* The content of the selection, may be empty, not
|
*/
|
||||||
* <code>null</code>.
|
public HexEditorSelection(long startOffset, long endOffset, byte[] bytes) {
|
||||||
*/
|
|
||||||
public HexEditorSelection(long startOffset, long endOffset, byte[] bytes) {
|
|
||||||
|
|
||||||
if (startOffset < 0) {
|
if (startOffset < 0) {
|
||||||
throw new IllegalArgumentException("Parameter 'startOffset' must not be negative, specified value is "
|
throw new IllegalArgumentException(
|
||||||
+ startOffset + ".");
|
"Parameter 'startOffset' must not be negative, specified value is " + startOffset + ".");
|
||||||
|
}
|
||||||
|
if (endOffset < startOffset) {
|
||||||
|
throw new IllegalArgumentException("Parameter 'endOffset' must not be smaller than startOffset "
|
||||||
|
+ startOffset + ", specified value is " + endOffset + ".");
|
||||||
|
}
|
||||||
|
if (bytes == null) {
|
||||||
|
throw new IllegalArgumentException("Parameter 'bytes' must not be null.");
|
||||||
|
}
|
||||||
|
this.startOffset = startOffset;
|
||||||
|
this.endOffset = endOffset;
|
||||||
|
this.bytes = bytes;
|
||||||
}
|
}
|
||||||
if (endOffset < startOffset) {
|
|
||||||
throw new IllegalArgumentException("Parameter 'endOffset' must not be smaller than startOffset "
|
@Override
|
||||||
+ startOffset + ", specified value is " + endOffset + ".");
|
public boolean isEmpty() {
|
||||||
|
return bytes.length == 0;
|
||||||
}
|
}
|
||||||
if (bytes == null) {
|
|
||||||
throw new IllegalArgumentException("Parameter 'bytes' must not be null.");
|
/**
|
||||||
|
* Gets the start offset of the selection in the original array.
|
||||||
|
*
|
||||||
|
* @return The start offset in the original array, a non-negative number.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public long getStartOffset() {
|
||||||
|
return startOffset;
|
||||||
}
|
}
|
||||||
this.startOffset = startOffset;
|
|
||||||
this.endOffset = endOffset;
|
|
||||||
this.bytes = bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public boolean isEmpty() {
|
* Gets the end offset in the original array.
|
||||||
return bytes.length == 0;
|
*
|
||||||
}
|
* @return The end offset in the original array, a non-negative number greater
|
||||||
|
* or equal to the start offset.
|
||||||
|
*/
|
||||||
|
public long getEndOffset() {
|
||||||
|
return endOffset;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the start offset of the selection in the original array.
|
* Gets the content of the selection.
|
||||||
*
|
*
|
||||||
* @return The start offset in the original array, a non-negative number.
|
* @return The content of the selection, may be empty, not <code>null</code> .
|
||||||
*
|
*/
|
||||||
*/
|
public byte[] getBytes() {
|
||||||
public long getStartOffset() {
|
return bytes;
|
||||||
return startOffset;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Gets the end offset in the original array.
|
public String toString() {
|
||||||
*
|
return "HexEditorSelection from " + startOffset + " to " + endOffset + ": " + bytes.length + " bytes";
|
||||||
* @return The end offset in the original array, a non-negative number
|
}
|
||||||
* greater or equal to the start offset.
|
|
||||||
*/
|
|
||||||
public long getEndOffset() {
|
|
||||||
return endOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the content of the selection.
|
|
||||||
*
|
|
||||||
* @return The content of the selection, may be empty, not <code>null</code>
|
|
||||||
* .
|
|
||||||
*/
|
|
||||||
public byte[] getBytes() {
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "HexEditorSelection from " + startOffset + " to " + endOffset + ": " + bytes.length + " bytes";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,43 +35,43 @@ import com.wudsn.ide.base.gui.MessageManager;
|
||||||
*/
|
*/
|
||||||
public abstract class HexEditorSelectionCommandHandler extends AbstractHandler {
|
public abstract class HexEditorSelectionCommandHandler extends AbstractHandler {
|
||||||
|
|
||||||
protected ExecutionEvent event;
|
protected ExecutionEvent event;
|
||||||
protected String commandId;
|
protected String commandId;
|
||||||
protected HexEditorSelection hexEditorSelection;
|
protected HexEditorSelection hexEditorSelection;
|
||||||
protected HexEditor hexEditor;
|
protected HexEditor hexEditor;
|
||||||
protected MessageManager messageManager;
|
protected MessageManager messageManager;
|
||||||
|
|
||||||
/**
|
|
||||||
* Creation is protected.
|
|
||||||
*/
|
|
||||||
protected HexEditorSelectionCommandHandler() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final Object execute(ExecutionEvent event) throws ExecutionException {
|
|
||||||
IEditorPart editorPart;
|
|
||||||
ISelection menuEditorInputSelection;
|
|
||||||
editorPart = HandlerUtil.getActiveEditor(event);
|
|
||||||
menuEditorInputSelection = HandlerUtil.getActiveMenuSelection(event);
|
|
||||||
|
|
||||||
if (editorPart instanceof HexEditor && menuEditorInputSelection instanceof HexEditorSelection) {
|
|
||||||
|
|
||||||
this.event = event;
|
|
||||||
this.commandId = event.getCommand().getId();
|
|
||||||
this.hexEditorSelection = (HexEditorSelection) menuEditorInputSelection;
|
|
||||||
this.hexEditor = ((HexEditor) editorPart);
|
|
||||||
this.messageManager = hexEditor.getMessageManager();
|
|
||||||
messageManager.clearMessages();
|
|
||||||
|
|
||||||
performAction();
|
|
||||||
|
|
||||||
messageManager.displayMessages();
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creation is protected.
|
||||||
|
*/
|
||||||
|
protected HexEditorSelectionCommandHandler() {
|
||||||
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
@Override
|
||||||
}
|
public final Object execute(ExecutionEvent event) throws ExecutionException {
|
||||||
|
IEditorPart editorPart;
|
||||||
|
ISelection menuEditorInputSelection;
|
||||||
|
editorPart = HandlerUtil.getActiveEditor(event);
|
||||||
|
menuEditorInputSelection = HandlerUtil.getActiveMenuSelection(event);
|
||||||
|
|
||||||
protected abstract void performAction() throws ExecutionException;
|
if (editorPart instanceof HexEditor && menuEditorInputSelection instanceof HexEditorSelection) {
|
||||||
|
|
||||||
|
this.event = event;
|
||||||
|
this.commandId = event.getCommand().getId();
|
||||||
|
this.hexEditorSelection = (HexEditorSelection) menuEditorInputSelection;
|
||||||
|
this.hexEditor = ((HexEditor) editorPart);
|
||||||
|
this.messageManager = hexEditor.getMessageManager();
|
||||||
|
messageManager.clearMessages();
|
||||||
|
|
||||||
|
performAction();
|
||||||
|
|
||||||
|
messageManager.displayMessages();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void performAction() throws ExecutionException;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,86 +11,86 @@ import org.eclipse.swt.dnd.TransferData;
|
||||||
|
|
||||||
public final class HexEditorSelectionTransfer extends ByteArrayTransfer {
|
public final class HexEditorSelectionTransfer extends ByteArrayTransfer {
|
||||||
|
|
||||||
private static final String HEX_EDITOR_SELECTION_NAME = "HexEditorSelection";
|
private static final String HEX_EDITOR_SELECTION_NAME = "HexEditorSelection";
|
||||||
private static final int HEX_EDITOR_SELECTION_ID = registerType(HEX_EDITOR_SELECTION_NAME);
|
private static final int HEX_EDITOR_SELECTION_ID = registerType(HEX_EDITOR_SELECTION_NAME);
|
||||||
private static HexEditorSelectionTransfer instance = new HexEditorSelectionTransfer();
|
private static HexEditorSelectionTransfer instance = new HexEditorSelectionTransfer();
|
||||||
|
|
||||||
private HexEditorSelectionTransfer() {
|
private HexEditorSelectionTransfer() {
|
||||||
}
|
|
||||||
|
|
||||||
public static HexEditorSelectionTransfer getInstance() {
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void javaToNative(Object object, TransferData transferData) {
|
|
||||||
if (object == null || !(object instanceof HexEditorSelection))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (isSupportedType(transferData)) {
|
|
||||||
HexEditorSelection hexEditorSelection = (HexEditorSelection) object;
|
|
||||||
try {
|
|
||||||
// write data to a byte array and then ask super to convert to
|
|
||||||
// pMedium
|
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
|
||||||
DataOutputStream writeOut = new DataOutputStream(out);
|
|
||||||
byte[] bytes = hexEditorSelection.getBytes();
|
|
||||||
writeOut.writeLong(hexEditorSelection.getStartOffset());
|
|
||||||
writeOut.writeLong(hexEditorSelection.getEndOffset());
|
|
||||||
writeOut.writeInt(bytes.length);
|
|
||||||
writeOut.write(bytes);
|
|
||||||
|
|
||||||
byte[] buffer = out.toByteArray();
|
|
||||||
writeOut.close();
|
|
||||||
|
|
||||||
super.javaToNative(buffer, transferData);
|
|
||||||
|
|
||||||
} catch (IOException e) {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
public static HexEditorSelectionTransfer getInstance() {
|
||||||
public Object nativeToJava(TransferData transferData) {
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
if (isSupportedType(transferData)) {
|
@Override
|
||||||
|
public void javaToNative(Object object, TransferData transferData) {
|
||||||
|
if (object == null || !(object instanceof HexEditorSelection))
|
||||||
|
return;
|
||||||
|
|
||||||
byte[] buffer = (byte[]) super.nativeToJava(transferData);
|
if (isSupportedType(transferData)) {
|
||||||
if (buffer == null) {
|
HexEditorSelection hexEditorSelection = (HexEditorSelection) object;
|
||||||
return null;
|
try {
|
||||||
}
|
// write data to a byte array and then ask super to convert to
|
||||||
|
// pMedium
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
DataOutputStream writeOut = new DataOutputStream(out);
|
||||||
|
byte[] bytes = hexEditorSelection.getBytes();
|
||||||
|
writeOut.writeLong(hexEditorSelection.getStartOffset());
|
||||||
|
writeOut.writeLong(hexEditorSelection.getEndOffset());
|
||||||
|
writeOut.writeInt(bytes.length);
|
||||||
|
writeOut.write(bytes);
|
||||||
|
|
||||||
HexEditorSelection hexEditorSelection;
|
byte[] buffer = out.toByteArray();
|
||||||
hexEditorSelection = null;
|
writeOut.close();
|
||||||
try {
|
|
||||||
ByteArrayInputStream in = new ByteArrayInputStream(buffer);
|
|
||||||
DataInputStream readIn = new DataInputStream(in);
|
|
||||||
while (readIn.available() > 0) {
|
|
||||||
long startOffset = readIn.readLong();
|
|
||||||
long endOffset = readIn.readLong();
|
|
||||||
int size = readIn.readInt();
|
|
||||||
byte[] bytes = new byte[size];
|
|
||||||
readIn.read(bytes);
|
|
||||||
hexEditorSelection = new HexEditorSelection(startOffset, endOffset, bytes);
|
|
||||||
|
|
||||||
|
super.javaToNative(buffer, transferData);
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
readIn.close();
|
|
||||||
} catch (IOException ex) {
|
|
||||||
hexEditorSelection = null;
|
|
||||||
}
|
|
||||||
return hexEditorSelection;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
@Override
|
||||||
}
|
public Object nativeToJava(TransferData transferData) {
|
||||||
|
|
||||||
@Override
|
if (isSupportedType(transferData)) {
|
||||||
protected String[] getTypeNames() {
|
|
||||||
return new String[] { HEX_EDITOR_SELECTION_NAME };
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
byte[] buffer = (byte[]) super.nativeToJava(transferData);
|
||||||
protected int[] getTypeIds() {
|
if (buffer == null) {
|
||||||
return new int[] { HEX_EDITOR_SELECTION_ID };
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HexEditorSelection hexEditorSelection;
|
||||||
|
hexEditorSelection = null;
|
||||||
|
try {
|
||||||
|
ByteArrayInputStream in = new ByteArrayInputStream(buffer);
|
||||||
|
DataInputStream readIn = new DataInputStream(in);
|
||||||
|
while (readIn.available() > 0) {
|
||||||
|
long startOffset = readIn.readLong();
|
||||||
|
long endOffset = readIn.readLong();
|
||||||
|
int size = readIn.readInt();
|
||||||
|
byte[] bytes = new byte[size];
|
||||||
|
readIn.read(bytes);
|
||||||
|
hexEditorSelection = new HexEditorSelection(startOffset, endOffset, bytes);
|
||||||
|
|
||||||
|
}
|
||||||
|
readIn.close();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
hexEditorSelection = null;
|
||||||
|
}
|
||||||
|
return hexEditorSelection;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String[] getTypeNames() {
|
||||||
|
return new String[] { HEX_EDITOR_SELECTION_NAME };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int[] getTypeIds() {
|
||||||
|
return new int[] { HEX_EDITOR_SELECTION_ID };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,54 +9,54 @@ import com.wudsn.ide.base.common.AbstractIDEPlugin;
|
||||||
*/
|
*/
|
||||||
public class HexPlugin extends AbstractIDEPlugin {
|
public class HexPlugin extends AbstractIDEPlugin {
|
||||||
|
|
||||||
// The plug-in ID
|
// The plug-in ID
|
||||||
public static final String ID = "com.wudsn.ide.hex"; //$NON-NLS-1$
|
public static final String ID = "com.wudsn.ide.hex"; //$NON-NLS-1$
|
||||||
|
|
||||||
// The shared instance
|
// The shared instance
|
||||||
private static HexPlugin plugin;
|
private static HexPlugin plugin;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The constructor
|
* The constructor
|
||||||
*/
|
*/
|
||||||
public HexPlugin() {
|
public HexPlugin() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected String getPluginId() {
|
protected String getPluginId() {
|
||||||
return ID;
|
return ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void start(BundleContext context) throws Exception {
|
public void start(BundleContext context) throws Exception {
|
||||||
super.start(context);
|
super.start(context);
|
||||||
plugin = this;
|
plugin = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void stop(BundleContext context) throws Exception {
|
public void stop(BundleContext context) throws Exception {
|
||||||
plugin = null;
|
plugin = null;
|
||||||
super.stop(context);
|
super.stop(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the shared plugin instance
|
* Gets the shared plugin instance
|
||||||
*
|
*
|
||||||
* @return The plug-in, not <code>null</code>.
|
* @return The plug-in, not <code>null</code>.
|
||||||
*/
|
*/
|
||||||
public static HexPlugin getInstance() {
|
public static HexPlugin getInstance() {
|
||||||
if (plugin == null) {
|
if (plugin == null) {
|
||||||
throw new IllegalStateException("Plugin not initialized or already stopped");
|
throw new IllegalStateException("Plugin not initialized or already stopped");
|
||||||
|
}
|
||||||
|
return plugin;
|
||||||
}
|
}
|
||||||
return plugin;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,65 +28,65 @@ import org.eclipse.osgi.util.NLS;
|
||||||
*/
|
*/
|
||||||
public final class Texts extends NLS {
|
public final class Texts extends NLS {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hex editor
|
* Hex editor
|
||||||
*/
|
*/
|
||||||
public static String HEX_EDITOR_FILE_SIZE;
|
public static String HEX_EDITOR_FILE_SIZE;
|
||||||
|
|
||||||
public static String HEX_EDITOR_ATARI_COM_BLOCK_HEADER;
|
public static String HEX_EDITOR_ATARI_COM_BLOCK_HEADER;
|
||||||
public static String HEX_EDITOR_ATARI_COM_BLOCK_HEADER_PARAMETERS;
|
public static String HEX_EDITOR_ATARI_COM_BLOCK_HEADER_PARAMETERS;
|
||||||
public static String HEX_EDITOR_ATARI_COM_BLOCK_ERROR;
|
public static String HEX_EDITOR_ATARI_COM_BLOCK_ERROR;
|
||||||
|
|
||||||
public static String HEX_EDITOR_ATARI_DISK_IMAGE_HEADER;
|
public static String HEX_EDITOR_ATARI_DISK_IMAGE_HEADER;
|
||||||
public static String HEX_EDITOR_ATARI_SECTOR_HEADER;
|
public static String HEX_EDITOR_ATARI_SECTOR_HEADER;
|
||||||
public static String HEX_EDITOR_ATARI_SECTOR_HEADER_PARAMETERS;
|
public static String HEX_EDITOR_ATARI_SECTOR_HEADER_PARAMETERS;
|
||||||
public static String HEX_EDITOR_ATARI_SECTOR_ERROR;
|
public static String HEX_EDITOR_ATARI_SECTOR_ERROR;
|
||||||
|
|
||||||
public static String HEX_EDITOR_ATARI_MADS_RELOC_BLOCK_HEADER;
|
public static String HEX_EDITOR_ATARI_MADS_RELOC_BLOCK_HEADER;
|
||||||
public static String HEX_EDITOR_ATARI_MADS_UPDATE_RELOC_BLOCK_HEADER;
|
public static String HEX_EDITOR_ATARI_MADS_UPDATE_RELOC_BLOCK_HEADER;
|
||||||
public static String HEX_EDITOR_ATARI_MADS_UPDATE_SYMBOLS_BLOCK_HEADER;
|
public static String HEX_EDITOR_ATARI_MADS_UPDATE_SYMBOLS_BLOCK_HEADER;
|
||||||
public static String HEX_EDITOR_ATARI_MADS_DEFINE_SYMBOLS_BLOCK_HEADER;
|
public static String HEX_EDITOR_ATARI_MADS_DEFINE_SYMBOLS_BLOCK_HEADER;
|
||||||
public static String HEX_EDITOR_ATARI_MADS_DEFINE_SYMBOL_HEADER;
|
public static String HEX_EDITOR_ATARI_MADS_DEFINE_SYMBOL_HEADER;
|
||||||
public static String HEX_EDITOR_ATARI_MADS_BLOCK_ERROR;
|
public static String HEX_EDITOR_ATARI_MADS_BLOCK_ERROR;
|
||||||
|
|
||||||
public static String HEX_EDITOR_ATARI_SAP_FILE_HEADER;
|
public static String HEX_EDITOR_ATARI_SAP_FILE_HEADER;
|
||||||
|
|
||||||
public static String HEX_EDITOR_ATARI_SDX_NON_RELOC_BLOCK_HEADER;
|
public static String HEX_EDITOR_ATARI_SDX_NON_RELOC_BLOCK_HEADER;
|
||||||
public static String HEX_EDITOR_ATARI_SDX_NON_RELOC_BLOCK_HEADER_PARAMETERS;
|
public static String HEX_EDITOR_ATARI_SDX_NON_RELOC_BLOCK_HEADER_PARAMETERS;
|
||||||
public static String HEX_EDITOR_ATARI_SDX_RELOC_BLOCK_HEADER;
|
public static String HEX_EDITOR_ATARI_SDX_RELOC_BLOCK_HEADER;
|
||||||
public static String HEX_EDITOR_ATARI_SDX_UPDATE_RELOC_BLOCK_HEADER;
|
public static String HEX_EDITOR_ATARI_SDX_UPDATE_RELOC_BLOCK_HEADER;
|
||||||
public static String HEX_EDITOR_ATARI_SDX_UPDATE_SYMBOLS_BLOCK_HEADER;
|
public static String HEX_EDITOR_ATARI_SDX_UPDATE_SYMBOLS_BLOCK_HEADER;
|
||||||
public static String HEX_EDITOR_ATARI_SDX_DEFINE_SYMBOLS_BLOCK_HEADER;
|
public static String HEX_EDITOR_ATARI_SDX_DEFINE_SYMBOLS_BLOCK_HEADER;
|
||||||
public static String HEX_EDITOR_ATARI_SDX_BLOCK_ERROR;
|
public static String HEX_EDITOR_ATARI_SDX_BLOCK_ERROR;
|
||||||
|
|
||||||
public static String HEX_EDITOR_C64_PRG_HEADER;
|
public static String HEX_EDITOR_C64_PRG_HEADER;
|
||||||
public static String HEX_EDITOR_C64_PRG_HEADER_PARAMETERS;
|
public static String HEX_EDITOR_C64_PRG_HEADER_PARAMETERS;
|
||||||
public static String HEX_EDITOR_C64_PRG_ERROR;
|
public static String HEX_EDITOR_C64_PRG_ERROR;
|
||||||
|
|
||||||
public static String HEX_EDITOR_IFF_CHUNK;
|
public static String HEX_EDITOR_IFF_CHUNK;
|
||||||
public static String HEX_EDITOR_IFF_FORM_CHUNK;
|
public static String HEX_EDITOR_IFF_FORM_CHUNK;
|
||||||
public static String HEX_EDITOR_IFF_FILE_ERROR;
|
public static String HEX_EDITOR_IFF_FILE_ERROR;
|
||||||
|
|
||||||
public static String HEX_EDITOR_FILE_CONTENT_SIZE_FIELD_LABEL;
|
|
||||||
public static String HEX_EDITOR_FILE_CONTENT_SIZE_FIELD_TEXT;
|
|
||||||
public static String HEX_EDITOR_FILE_CONTENT_MODE_FIELD_LABEL;
|
|
||||||
public static String HEX_EDITOR_CHARACTER_SET_TYPE_FIELD_LABEL;
|
|
||||||
public static String HEX_EDITOR_BYTES_PER_ROW_FIELD_LABEL;
|
|
||||||
|
|
||||||
public static String HEX_EDITOR_SAVE_SELECTION_AS_DIALOG_TITLE;
|
public static String HEX_EDITOR_FILE_CONTENT_SIZE_FIELD_LABEL;
|
||||||
|
public static String HEX_EDITOR_FILE_CONTENT_SIZE_FIELD_TEXT;
|
||||||
|
public static String HEX_EDITOR_FILE_CONTENT_MODE_FIELD_LABEL;
|
||||||
|
public static String HEX_EDITOR_CHARACTER_SET_TYPE_FIELD_LABEL;
|
||||||
|
public static String HEX_EDITOR_BYTES_PER_ROW_FIELD_LABEL;
|
||||||
|
|
||||||
/**
|
public static String HEX_EDITOR_SAVE_SELECTION_AS_DIALOG_TITLE;
|
||||||
* Message for the {@link HexEditor}
|
|
||||||
*/
|
|
||||||
public static String MESSAGE_E300;
|
|
||||||
public static String MESSAGE_E301;
|
|
||||||
public static String MESSAGE_I302;
|
|
||||||
public static String MESSAGE_I303;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the constants.
|
* Message for the {@link HexEditor}
|
||||||
*/
|
*/
|
||||||
static {
|
public static String MESSAGE_E300;
|
||||||
NLS.initializeMessages(Texts.class.getName(), Texts.class);
|
public static String MESSAGE_E301;
|
||||||
}
|
public static String MESSAGE_I302;
|
||||||
|
public static String MESSAGE_I303;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the constants.
|
||||||
|
*/
|
||||||
|
static {
|
||||||
|
NLS.initializeMessages(Texts.class.getName(), Texts.class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,14 +23,14 @@ import org.eclipse.jface.viewers.StyledString;
|
||||||
|
|
||||||
public final class AtariCOMParser extends AtariParser {
|
public final class AtariCOMParser extends AtariParser {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean parse(StyledString contentBuilder) {
|
public boolean parse(StyledString contentBuilder) {
|
||||||
if (contentBuilder == null) {
|
if (contentBuilder == null) {
|
||||||
throw new IllegalArgumentException("Parameter 'contentBuilder' must not be null.");
|
throw new IllegalArgumentException("Parameter 'contentBuilder' must not be null.");
|
||||||
|
}
|
||||||
|
int offset = 0;
|
||||||
|
int fileContentLenght = fileContent.getLength();
|
||||||
|
return parseAtariCOMFile(contentBuilder, offset, fileContentLenght);
|
||||||
}
|
}
|
||||||
int offset = 0;
|
|
||||||
int fileContentLenght = fileContent.getLength();
|
|
||||||
return parseAtariCOMFile(contentBuilder, offset, fileContentLenght);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,27 +22,27 @@ package com.wudsn.ide.hex.parser;
|
||||||
import org.eclipse.jface.viewers.StyledString;
|
import org.eclipse.jface.viewers.StyledString;
|
||||||
|
|
||||||
public final class AtariDiskImageKFileParser extends AtariDiskImageParser {
|
public final class AtariDiskImageKFileParser extends AtariDiskImageParser {
|
||||||
// The offset where the COM file starts in an Atari Disk Image (k-file).
|
// The offset where the COM file starts in an Atari Disk Image (k-file).
|
||||||
public static final int ATARI_DISK_IMAGE_K_FILE_COM_FILE_OFFSET = 16 + 3 * 128;
|
public static final int ATARI_DISK_IMAGE_K_FILE_COM_FILE_OFFSET = 16 + 3 * 128;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean parse(StyledString contentBuilder) {
|
public boolean parse(StyledString contentBuilder) {
|
||||||
|
|
||||||
if (contentBuilder == null) {
|
if (contentBuilder == null) {
|
||||||
throw new IllegalArgumentException("Parameter 'contentBuilder' must not be null.");
|
throw new IllegalArgumentException("Parameter 'contentBuilder' must not be null.");
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean error = super.parse(contentBuilder);
|
||||||
|
|
||||||
|
// If the disk image is a k-file image, the contained COM file is parsed
|
||||||
|
// as well.
|
||||||
|
if (!error) {
|
||||||
|
// The length of the k-file is stored in $709/$70a.
|
||||||
|
int length = ATARI_DISK_IMAGE_K_FILE_COM_FILE_OFFSET + fileContent.getByte(0x19)
|
||||||
|
+ 256 * fileContent.getByte(0x1a);
|
||||||
|
error = parseAtariCOMFile(contentBuilder, ATARI_DISK_IMAGE_K_FILE_COM_FILE_OFFSET, length);
|
||||||
|
}
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean error = super.parse(contentBuilder);
|
|
||||||
|
|
||||||
// If the disk image is a k-file image, the contained COM file is parsed
|
|
||||||
// as well.
|
|
||||||
if (!error) {
|
|
||||||
// The length of the k-file is stored in $709/$70a.
|
|
||||||
int length = ATARI_DISK_IMAGE_K_FILE_COM_FILE_OFFSET + fileContent.getByte(0x19) + 256
|
|
||||||
* fileContent.getByte(0x1a);
|
|
||||||
error = parseAtariCOMFile(contentBuilder, ATARI_DISK_IMAGE_K_FILE_COM_FILE_OFFSET, length);
|
|
||||||
}
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,65 +26,65 @@ import com.wudsn.ide.hex.HexEditorContentOutlineTreeObject;
|
||||||
|
|
||||||
public class AtariDiskImageParser extends AtariParser {
|
public class AtariDiskImageParser extends AtariParser {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean parse(StyledString contentBuilder) {
|
public boolean parse(StyledString contentBuilder) {
|
||||||
|
|
||||||
if (contentBuilder == null) {
|
if (contentBuilder == null) {
|
||||||
throw new IllegalArgumentException("Parameter 'contentBuilder' must not be null.");
|
throw new IllegalArgumentException("Parameter 'contentBuilder' must not be null.");
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean error = false;
|
boolean error = false;
|
||||||
int length = fileContent.getLength();
|
int length = fileContent.getLength();
|
||||||
long offset = 0;
|
long offset = 0;
|
||||||
|
|
||||||
HexEditorContentOutlineTreeObject treeObject;
|
HexEditorContentOutlineTreeObject treeObject;
|
||||||
treeObject = printBlockHeader(contentBuilder, Texts.HEX_EDITOR_ATARI_DISK_IMAGE_HEADER, -1, "", offset, offset,
|
treeObject = printBlockHeader(contentBuilder, Texts.HEX_EDITOR_ATARI_DISK_IMAGE_HEADER, -1, "", offset, offset,
|
||||||
offset + 15);
|
offset + 15);
|
||||||
offset = printBytes(treeObject, contentBuilder, offset, offset + 15, true, 0);
|
offset = printBytes(treeObject, contentBuilder, offset, offset + 15, true, 0);
|
||||||
contentBuilder.append("\n");
|
|
||||||
|
|
||||||
boolean blockMode;
|
|
||||||
|
|
||||||
blockMode = true;
|
|
||||||
|
|
||||||
int mainSectorSize = fileContent.getByte(4) + 256 * fileContent.getByte(5);
|
|
||||||
int bootSectorSize = mainSectorSize;
|
|
||||||
|
|
||||||
if (bootSectorSize == 256 && (length % 256) == 128 + 16) {
|
|
||||||
bootSectorSize = 128;
|
|
||||||
}
|
|
||||||
int startAddress = 0;
|
|
||||||
int sectorCount;
|
|
||||||
int sectorSize;
|
|
||||||
|
|
||||||
sectorCount = 1;
|
|
||||||
sectorSize = bootSectorSize;
|
|
||||||
try {
|
|
||||||
while (blockMode && !error) {
|
|
||||||
treeObject = printBlockHeader(contentBuilder, Texts.HEX_EDITOR_ATARI_SECTOR_HEADER, sectorCount,
|
|
||||||
|
|
||||||
Texts.HEX_EDITOR_ATARI_SECTOR_HEADER_PARAMETERS, offset, startAddress,
|
|
||||||
startAddress + sectorSize - 1);
|
|
||||||
offset = printBytes(treeObject, contentBuilder, offset, offset + sectorSize - 1, true, startAddress);
|
|
||||||
contentBuilder.append("\n");
|
contentBuilder.append("\n");
|
||||||
|
|
||||||
if (offset >= length) {
|
boolean blockMode;
|
||||||
blockMode = false;
|
|
||||||
} else if (length - offset < sectorSize) {
|
blockMode = true;
|
||||||
error = true;
|
|
||||||
|
int mainSectorSize = fileContent.getByte(4) + 256 * fileContent.getByte(5);
|
||||||
|
int bootSectorSize = mainSectorSize;
|
||||||
|
|
||||||
|
if (bootSectorSize == 256 && (length % 256) == 128 + 16) {
|
||||||
|
bootSectorSize = 128;
|
||||||
}
|
}
|
||||||
sectorCount++;
|
int startAddress = 0;
|
||||||
if (sectorCount > 3) {
|
int sectorCount;
|
||||||
sectorSize = mainSectorSize;
|
int sectorSize;
|
||||||
|
|
||||||
|
sectorCount = 1;
|
||||||
|
sectorSize = bootSectorSize;
|
||||||
|
try {
|
||||||
|
while (blockMode && !error) {
|
||||||
|
treeObject = printBlockHeader(contentBuilder, Texts.HEX_EDITOR_ATARI_SECTOR_HEADER, sectorCount,
|
||||||
|
|
||||||
|
Texts.HEX_EDITOR_ATARI_SECTOR_HEADER_PARAMETERS, offset, startAddress,
|
||||||
|
startAddress + sectorSize - 1);
|
||||||
|
offset = printBytes(treeObject, contentBuilder, offset, offset + sectorSize - 1, true, startAddress);
|
||||||
|
contentBuilder.append("\n");
|
||||||
|
|
||||||
|
if (offset >= length) {
|
||||||
|
blockMode = false;
|
||||||
|
} else if (length - offset < sectorSize) {
|
||||||
|
error = true;
|
||||||
|
}
|
||||||
|
sectorCount++;
|
||||||
|
if (sectorCount > 3) {
|
||||||
|
sectorSize = mainSectorSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (RuntimeException ex) {
|
||||||
|
contentBuilder.append(ex.toString());
|
||||||
}
|
}
|
||||||
}
|
if (error) {
|
||||||
} catch (RuntimeException ex) {
|
printBlockWithError(contentBuilder, Texts.HEX_EDITOR_ATARI_SECTOR_ERROR, length, offset);
|
||||||
contentBuilder.append(ex.toString());
|
}
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
if (error) {
|
|
||||||
printBlockWithError(contentBuilder, Texts.HEX_EDITOR_ATARI_SECTOR_ERROR, length, offset);
|
|
||||||
}
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,188 +35,188 @@ import com.wudsn.ide.hex.HexEditorParser;
|
||||||
*/
|
*/
|
||||||
public class AtariMADSParser extends HexEditorParser {
|
public class AtariMADSParser extends HexEditorParser {
|
||||||
|
|
||||||
public static final int COM_HEADER = 0xffff;
|
public static final int COM_HEADER = 0xffff;
|
||||||
public static final int RELOC_HEADER = 0x524d;
|
public static final int RELOC_HEADER = 0x524d;
|
||||||
public static final int UPDATE_RELOC_HEADER = 0xffef;
|
public static final int UPDATE_RELOC_HEADER = 0xffef;
|
||||||
public static final int UPDATE_SYMBOLS_HEADER = 0xffee;
|
public static final int UPDATE_SYMBOLS_HEADER = 0xffee;
|
||||||
public static final int DEFINE_SYMBOLS_HEADER = 0xffed;
|
public static final int DEFINE_SYMBOLS_HEADER = 0xffed;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean parse(StyledString contentBuilder) {
|
public boolean parse(StyledString contentBuilder) {
|
||||||
if (contentBuilder == null) {
|
if (contentBuilder == null) {
|
||||||
throw new IllegalArgumentException("Parameter 'contentBuilder' must not be null.");
|
throw new IllegalArgumentException("Parameter 'contentBuilder' must not be null.");
|
||||||
}
|
|
||||||
|
|
||||||
boolean error;
|
|
||||||
long offset = 0;
|
|
||||||
|
|
||||||
// Skip offset bytes in lookup array.
|
|
||||||
skipByteTextIndex(offset);
|
|
||||||
|
|
||||||
HexEditorContentOutlineTreeObject treeObject;
|
|
||||||
int fileContentLength = fileContent.getLength();
|
|
||||||
|
|
||||||
error = (fileContentLength - offset) < 17;
|
|
||||||
boolean first = true;
|
|
||||||
boolean more = true;
|
|
||||||
try {
|
|
||||||
while (more && !error) {
|
|
||||||
if (!first) {
|
|
||||||
contentBuilder.append("\n");
|
|
||||||
}
|
}
|
||||||
first = false;
|
|
||||||
if (offset == fileContentLength) {
|
|
||||||
more = false;
|
|
||||||
} else {
|
|
||||||
int header = fileContent.getWord(offset);
|
|
||||||
if (header == COM_HEADER && fileContent.getWord(offset + 6) == RELOC_HEADER) {
|
|
||||||
int startAddress = fileContent.getWord(offset + 2);
|
|
||||||
int endAddress = fileContent.getWord(offset + 4);
|
|
||||||
int config = fileContent.getByte(offset + 9);
|
|
||||||
|
|
||||||
String headerText = TextUtility.format(Texts.HEX_EDITOR_ATARI_MADS_RELOC_BLOCK_HEADER,
|
boolean error;
|
||||||
HexUtility.getLongValueHexString(startAddress, 4),
|
long offset = 0;
|
||||||
HexUtility.getLongValueHexString(endAddress, 4),
|
|
||||||
HexUtility.getByteValueHexString(config));
|
|
||||||
|
|
||||||
treeObject = printHeader(contentBuilder, offset, headerText);
|
// Skip offset bytes in lookup array.
|
||||||
offset = printBytes(treeObject, contentBuilder, offset, offset + 15, true, 0);
|
skipByteTextIndex(offset);
|
||||||
|
|
||||||
long blockEnd = offset + endAddress - startAddress;
|
HexEditorContentOutlineTreeObject treeObject;
|
||||||
|
int fileContentLength = fileContent.getLength();
|
||||||
|
|
||||||
offset = printBytes(treeObject, contentBuilder, offset, blockEnd, true, startAddress);
|
error = (fileContentLength - offset) < 17;
|
||||||
|
boolean first = true;
|
||||||
} else if (header == UPDATE_RELOC_HEADER) {
|
boolean more = true;
|
||||||
|
try {
|
||||||
int type = fileContent.getByte(offset + 2);
|
while (more && !error) {
|
||||||
int dataLength = fileContent.getWord(offset + 3);
|
if (!first) {
|
||||||
|
contentBuilder.append("\n");
|
||||||
treeObject = printTypedHeader(contentBuilder, offset,
|
|
||||||
Texts.HEX_EDITOR_ATARI_MADS_UPDATE_RELOC_BLOCK_HEADER, type, dataLength);
|
|
||||||
offset = printBytes(treeObject, contentBuilder, offset, offset + 4, false, 0);
|
|
||||||
|
|
||||||
// The exception is an update block for address high
|
|
||||||
// bytes ">", where for such a block an extra BYTE is
|
|
||||||
// stored for each address (low byte of address being
|
|
||||||
// modified).
|
|
||||||
int dataSize = (type == '>' ? 3 : 2);
|
|
||||||
long blockEnd = offset + (dataLength * dataSize) - 1;
|
|
||||||
|
|
||||||
offset = printBytes(treeObject, contentBuilder, offset, blockEnd, false, 0);
|
|
||||||
|
|
||||||
} else if (header == UPDATE_SYMBOLS_HEADER) {
|
|
||||||
/**
|
|
||||||
* <pre>
|
|
||||||
* HEADER WORD ($FFEE)
|
|
||||||
* TYPE CHAR (B-YTE, W-ORD, L-ONG, D-WORD, <, >)
|
|
||||||
* DATA_LENGTH WORD
|
|
||||||
* LABEL_LENGTH WORD
|
|
||||||
* LABEL_NAME ATASCII
|
|
||||||
* DATA WORD .. .. .. (DATA_LENGTH words)
|
|
||||||
* </pre>
|
|
||||||
*/
|
|
||||||
int type = fileContent.getByte(offset + 2);
|
|
||||||
int dataLength = fileContent.getWord(offset + 3);
|
|
||||||
int labelLength = fileContent.getWord(offset + 5);
|
|
||||||
|
|
||||||
treeObject = printTypedHeader(contentBuilder, offset,
|
|
||||||
Texts.HEX_EDITOR_ATARI_MADS_UPDATE_SYMBOLS_BLOCK_HEADER, type, dataLength);
|
|
||||||
offset = printBytes(treeObject, contentBuilder, offset, offset + 6, false, 0);
|
|
||||||
offset = printBytes(treeObject, contentBuilder, offset, offset + labelLength - 1, false, 0);
|
|
||||||
offset = printBytes(treeObject, contentBuilder, offset, offset + dataLength * 2 - 1, false, 0);
|
|
||||||
|
|
||||||
} else if (header == DEFINE_SYMBOLS_HEADER) {
|
|
||||||
|
|
||||||
int length = fileContent.getWord(offset + 2);
|
|
||||||
String headerText = TextUtility.format(Texts.HEX_EDITOR_ATARI_MADS_DEFINE_SYMBOLS_BLOCK_HEADER,
|
|
||||||
HexUtility.getLongValueHexString(length, 4));
|
|
||||||
StyledString headerStyledString = new StyledString(headerText, offsetStyler);
|
|
||||||
contentBuilder.append(headerStyledString).append("\n\n");
|
|
||||||
treeObject = printBlockHeader(contentBuilder, headerStyledString, offset);
|
|
||||||
|
|
||||||
offset += 4;
|
|
||||||
for (int i = 0; i < length; i++) {
|
|
||||||
int type = fileContent.getByte(offset);
|
|
||||||
int labelType = fileContent.getByte(offset + 1);
|
|
||||||
int labelLength = fileContent.getWord(offset + 2);
|
|
||||||
String labelName = getLabelName(offset + 4, labelLength);
|
|
||||||
int address = fileContent.getWord(offset + 4 + labelLength);
|
|
||||||
long headerEnd = offset + 6 + labelLength - 1;
|
|
||||||
switch (labelType) {
|
|
||||||
case 'P':
|
|
||||||
int procType = fileContent.getByte(headerEnd + 1);
|
|
||||||
int paramCount = fileContent.getWord(headerEnd + 2);
|
|
||||||
headerEnd += 4;
|
|
||||||
for (int j = 0; j < paramCount; j++) {
|
|
||||||
switch (procType) {
|
|
||||||
case 'D':
|
|
||||||
break;
|
|
||||||
case 'R':
|
|
||||||
headerEnd += 1;
|
|
||||||
break;
|
|
||||||
case 'V':
|
|
||||||
headerEnd += 1;
|
|
||||||
int paramLenght = fileContent.getWord(headerEnd);
|
|
||||||
headerEnd += 2 + paramLenght;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
first = false;
|
||||||
case 'A':
|
if (offset == fileContentLength) {
|
||||||
break;
|
more = false;
|
||||||
case 'S':
|
} else {
|
||||||
break;
|
int header = fileContent.getWord(offset);
|
||||||
}
|
if (header == COM_HEADER && fileContent.getWord(offset + 6) == RELOC_HEADER) {
|
||||||
|
int startAddress = fileContent.getWord(offset + 2);
|
||||||
|
int endAddress = fileContent.getWord(offset + 4);
|
||||||
|
int config = fileContent.getByte(offset + 9);
|
||||||
|
|
||||||
headerText = TextUtility.format(Texts.HEX_EDITOR_ATARI_MADS_DEFINE_SYMBOL_HEADER,
|
String headerText = TextUtility.format(Texts.HEX_EDITOR_ATARI_MADS_RELOC_BLOCK_HEADER,
|
||||||
String.valueOf((char) type), String.valueOf((char) labelType), labelName,
|
HexUtility.getLongValueHexString(startAddress, 4),
|
||||||
HexUtility.getLongValueHexString(address, 4));
|
HexUtility.getLongValueHexString(endAddress, 4),
|
||||||
headerStyledString = new StyledString(headerText, offsetStyler);
|
HexUtility.getByteValueHexString(config));
|
||||||
contentBuilder.append(headerStyledString).append("\n");
|
|
||||||
treeObject = printBlockHeader(contentBuilder, headerStyledString, offset);
|
|
||||||
offset = printBytes(treeObject, contentBuilder, offset, headerEnd, false, 0);
|
|
||||||
|
|
||||||
|
treeObject = printHeader(contentBuilder, offset, headerText);
|
||||||
|
offset = printBytes(treeObject, contentBuilder, offset, offset + 15, true, 0);
|
||||||
|
|
||||||
|
long blockEnd = offset + endAddress - startAddress;
|
||||||
|
|
||||||
|
offset = printBytes(treeObject, contentBuilder, offset, blockEnd, true, startAddress);
|
||||||
|
|
||||||
|
} else if (header == UPDATE_RELOC_HEADER) {
|
||||||
|
|
||||||
|
int type = fileContent.getByte(offset + 2);
|
||||||
|
int dataLength = fileContent.getWord(offset + 3);
|
||||||
|
|
||||||
|
treeObject = printTypedHeader(contentBuilder, offset,
|
||||||
|
Texts.HEX_EDITOR_ATARI_MADS_UPDATE_RELOC_BLOCK_HEADER, type, dataLength);
|
||||||
|
offset = printBytes(treeObject, contentBuilder, offset, offset + 4, false, 0);
|
||||||
|
|
||||||
|
// The exception is an update block for address high
|
||||||
|
// bytes ">", where for such a block an extra BYTE is
|
||||||
|
// stored for each address (low byte of address being
|
||||||
|
// modified).
|
||||||
|
int dataSize = (type == '>' ? 3 : 2);
|
||||||
|
long blockEnd = offset + (dataLength * dataSize) - 1;
|
||||||
|
|
||||||
|
offset = printBytes(treeObject, contentBuilder, offset, blockEnd, false, 0);
|
||||||
|
|
||||||
|
} else if (header == UPDATE_SYMBOLS_HEADER) {
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* HEADER WORD ($FFEE)
|
||||||
|
* TYPE CHAR (B-YTE, W-ORD, L-ONG, D-WORD, <, >)
|
||||||
|
* DATA_LENGTH WORD
|
||||||
|
* LABEL_LENGTH WORD
|
||||||
|
* LABEL_NAME ATASCII
|
||||||
|
* DATA WORD .. .. .. (DATA_LENGTH words)
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
int type = fileContent.getByte(offset + 2);
|
||||||
|
int dataLength = fileContent.getWord(offset + 3);
|
||||||
|
int labelLength = fileContent.getWord(offset + 5);
|
||||||
|
|
||||||
|
treeObject = printTypedHeader(contentBuilder, offset,
|
||||||
|
Texts.HEX_EDITOR_ATARI_MADS_UPDATE_SYMBOLS_BLOCK_HEADER, type, dataLength);
|
||||||
|
offset = printBytes(treeObject, contentBuilder, offset, offset + 6, false, 0);
|
||||||
|
offset = printBytes(treeObject, contentBuilder, offset, offset + labelLength - 1, false, 0);
|
||||||
|
offset = printBytes(treeObject, contentBuilder, offset, offset + dataLength * 2 - 1, false, 0);
|
||||||
|
|
||||||
|
} else if (header == DEFINE_SYMBOLS_HEADER) {
|
||||||
|
|
||||||
|
int length = fileContent.getWord(offset + 2);
|
||||||
|
String headerText = TextUtility.format(Texts.HEX_EDITOR_ATARI_MADS_DEFINE_SYMBOLS_BLOCK_HEADER,
|
||||||
|
HexUtility.getLongValueHexString(length, 4));
|
||||||
|
StyledString headerStyledString = new StyledString(headerText, offsetStyler);
|
||||||
|
contentBuilder.append(headerStyledString).append("\n\n");
|
||||||
|
treeObject = printBlockHeader(contentBuilder, headerStyledString, offset);
|
||||||
|
|
||||||
|
offset += 4;
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
int type = fileContent.getByte(offset);
|
||||||
|
int labelType = fileContent.getByte(offset + 1);
|
||||||
|
int labelLength = fileContent.getWord(offset + 2);
|
||||||
|
String labelName = getLabelName(offset + 4, labelLength);
|
||||||
|
int address = fileContent.getWord(offset + 4 + labelLength);
|
||||||
|
long headerEnd = offset + 6 + labelLength - 1;
|
||||||
|
switch (labelType) {
|
||||||
|
case 'P':
|
||||||
|
int procType = fileContent.getByte(headerEnd + 1);
|
||||||
|
int paramCount = fileContent.getWord(headerEnd + 2);
|
||||||
|
headerEnd += 4;
|
||||||
|
for (int j = 0; j < paramCount; j++) {
|
||||||
|
switch (procType) {
|
||||||
|
case 'D':
|
||||||
|
break;
|
||||||
|
case 'R':
|
||||||
|
headerEnd += 1;
|
||||||
|
break;
|
||||||
|
case 'V':
|
||||||
|
headerEnd += 1;
|
||||||
|
int paramLenght = fileContent.getWord(headerEnd);
|
||||||
|
headerEnd += 2 + paramLenght;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'A':
|
||||||
|
break;
|
||||||
|
case 'S':
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
headerText = TextUtility.format(Texts.HEX_EDITOR_ATARI_MADS_DEFINE_SYMBOL_HEADER,
|
||||||
|
String.valueOf((char) type), String.valueOf((char) labelType), labelName,
|
||||||
|
HexUtility.getLongValueHexString(address, 4));
|
||||||
|
headerStyledString = new StyledString(headerText, offsetStyler);
|
||||||
|
contentBuilder.append(headerStyledString).append("\n");
|
||||||
|
treeObject = printBlockHeader(contentBuilder, headerStyledString, offset);
|
||||||
|
offset = printBytes(treeObject, contentBuilder, offset, headerEnd, false, 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
error = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} catch (RuntimeException ex) {
|
||||||
} else {
|
contentBuilder.append(ex.toString());
|
||||||
error = true;
|
error = true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} catch (RuntimeException ex) {
|
if (error) {
|
||||||
contentBuilder.append(ex.toString());
|
printBlockWithError(contentBuilder, Texts.HEX_EDITOR_ATARI_MADS_BLOCK_ERROR, fileContentLength, offset);
|
||||||
error = true;
|
}
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error) {
|
private HexEditorContentOutlineTreeObject printHeader(StyledString contentBuilder, long offset, String headerText) {
|
||||||
printBlockWithError(contentBuilder, Texts.HEX_EDITOR_ATARI_MADS_BLOCK_ERROR, fileContentLength, offset);
|
HexEditorContentOutlineTreeObject treeObject;
|
||||||
|
StyledString headerStyledString = new StyledString(headerText, offsetStyler);
|
||||||
|
contentBuilder.append(headerStyledString).append("\n");
|
||||||
|
treeObject = printBlockHeader(contentBuilder, headerStyledString, offset);
|
||||||
|
return treeObject;
|
||||||
}
|
}
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
private HexEditorContentOutlineTreeObject printHeader(StyledString contentBuilder, long offset, String headerText) {
|
private HexEditorContentOutlineTreeObject printTypedHeader(StyledString contentBuilder, long offset, String text,
|
||||||
HexEditorContentOutlineTreeObject treeObject;
|
int type, int dataLength) {
|
||||||
StyledString headerStyledString = new StyledString(headerText, offsetStyler);
|
HexEditorContentOutlineTreeObject treeObject;
|
||||||
contentBuilder.append(headerStyledString).append("\n");
|
String headerText = TextUtility.format(text, String.valueOf((char) type),
|
||||||
treeObject = printBlockHeader(contentBuilder, headerStyledString, offset);
|
HexUtility.getLongValueHexString(dataLength, 4));
|
||||||
return treeObject;
|
treeObject = printHeader(contentBuilder, offset, headerText);
|
||||||
}
|
return treeObject;
|
||||||
|
}
|
||||||
private HexEditorContentOutlineTreeObject printTypedHeader(StyledString contentBuilder, long offset, String text,
|
|
||||||
int type, int dataLength) {
|
private String getLabelName(long offset, int length) {
|
||||||
HexEditorContentOutlineTreeObject treeObject;
|
StringBuffer buffer = new StringBuffer(8);
|
||||||
String headerText = TextUtility.format(text, String.valueOf((char) type),
|
for (int i = 0; i < length; i++) {
|
||||||
HexUtility.getLongValueHexString(dataLength, 4));
|
buffer.append((char) fileContent.getByte(offset + i));
|
||||||
treeObject = printHeader(contentBuilder, offset, headerText);
|
}
|
||||||
return treeObject;
|
return buffer.toString();
|
||||||
}
|
|
||||||
|
|
||||||
private String getLabelName(long offset, int length) {
|
|
||||||
StringBuffer buffer = new StringBuffer(8);
|
|
||||||
for (int i = 0; i < length; i++) {
|
|
||||||
buffer.append((char) fileContent.getByte(offset + i));
|
|
||||||
}
|
}
|
||||||
return buffer.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,101 +27,101 @@ import com.wudsn.ide.hex.HexEditorParser;
|
||||||
|
|
||||||
public abstract class AtariParser extends HexEditorParser {
|
public abstract class AtariParser extends HexEditorParser {
|
||||||
|
|
||||||
public final static int COM_HEADER = 0xffff;
|
public final static int COM_HEADER = 0xffff;
|
||||||
|
|
||||||
protected final boolean parseAtariCOMFile(StyledString contentBuilder, long offset, int fileContentLength) {
|
protected final boolean parseAtariCOMFile(StyledString contentBuilder, long offset, int fileContentLength) {
|
||||||
if (contentBuilder == null) {
|
if (contentBuilder == null) {
|
||||||
throw new IllegalArgumentException("Parameter 'contentBuilder' must not be null.");
|
throw new IllegalArgumentException("Parameter 'contentBuilder' must not be null.");
|
||||||
}
|
|
||||||
boolean error;
|
|
||||||
int startAddress;
|
|
||||||
int endAddress;
|
|
||||||
|
|
||||||
int blockCount;
|
|
||||||
long blockEnd;
|
|
||||||
|
|
||||||
// Skip offset bytes in lookup array.
|
|
||||||
skipByteTextIndex(offset);
|
|
||||||
|
|
||||||
HexEditorContentOutlineTreeObject treeObject;
|
|
||||||
|
|
||||||
error = (fileContentLength - offset) < 7;
|
|
||||||
if (!error) {
|
|
||||||
startAddress = fileContent.getWord(offset + 2);
|
|
||||||
endAddress = fileContent.getWord(offset + 4);
|
|
||||||
|
|
||||||
blockCount = 1;
|
|
||||||
blockEnd = offset + endAddress - startAddress + 6;
|
|
||||||
treeObject = printBlockHeader(contentBuilder, Texts.HEX_EDITOR_ATARI_COM_BLOCK_HEADER, blockCount,
|
|
||||||
Texts.HEX_EDITOR_ATARI_COM_BLOCK_HEADER_PARAMETERS, offset, startAddress, endAddress);
|
|
||||||
offset = printBytes(treeObject, contentBuilder, offset, offset + 5, true, 0);
|
|
||||||
|
|
||||||
boolean blockMode;
|
|
||||||
blockMode = true;
|
|
||||||
error = blockEnd >= fileContentLength;
|
|
||||||
try {
|
|
||||||
while (blockMode && !error) {
|
|
||||||
offset = printBytes(treeObject, contentBuilder, offset, blockEnd, true, startAddress);
|
|
||||||
|
|
||||||
int headerLength = -1;
|
|
||||||
// No more bytes left?
|
|
||||||
if (offset == fileContentLength) {
|
|
||||||
blockMode = false;
|
|
||||||
} else
|
|
||||||
// At least 5 bytes available? (4 header bytes and 1 data
|
|
||||||
// byte)
|
|
||||||
if (fileContentLength - offset < 5) {
|
|
||||||
error = true;
|
|
||||||
} else {
|
|
||||||
boolean comHeader;
|
|
||||||
comHeader = fileContent.getWord(offset) == COM_HEADER;
|
|
||||||
if (comHeader) {
|
|
||||||
// At least 7 bytes available? (6 header bytes and 1
|
|
||||||
// data byte)
|
|
||||||
if (fileContentLength - offset < 7) {
|
|
||||||
error = true;
|
|
||||||
} else {
|
|
||||||
// Inner COM header found
|
|
||||||
headerLength = 6;
|
|
||||||
startAddress = fileContent.getByte(offset + 2) + 256 * fileContent.getByte(offset + 3);
|
|
||||||
endAddress = fileContent.getByte(offset + 4) + 256 * fileContent.getByte(offset + 5);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// No inner COM header found
|
|
||||||
headerLength = 4;
|
|
||||||
startAddress = fileContent.getByte(offset + 0) + 256 * fileContent.getByte(offset + 1);
|
|
||||||
endAddress = fileContent.getByte(offset + 2) + 256 * fileContent.getByte(offset + 3);
|
|
||||||
}
|
|
||||||
error = endAddress < startAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (blockMode) {
|
|
||||||
contentBuilder.append("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (blockMode && !error) {
|
|
||||||
blockCount++;
|
|
||||||
blockEnd = offset + endAddress - startAddress + headerLength;
|
|
||||||
if (blockEnd < fileContentLength) {
|
|
||||||
|
|
||||||
treeObject = printBlockHeader(contentBuilder, Texts.HEX_EDITOR_ATARI_COM_BLOCK_HEADER,
|
|
||||||
blockCount, Texts.HEX_EDITOR_ATARI_COM_BLOCK_HEADER_PARAMETERS, offset,
|
|
||||||
startAddress, endAddress);
|
|
||||||
offset = printBytes(treeObject, contentBuilder, offset, offset + headerLength - 1, true, 0);
|
|
||||||
} else {
|
|
||||||
error = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (RuntimeException ex) {
|
boolean error;
|
||||||
contentBuilder.append(ex.toString());
|
int startAddress;
|
||||||
error = true;
|
int endAddress;
|
||||||
}
|
|
||||||
|
int blockCount;
|
||||||
|
long blockEnd;
|
||||||
|
|
||||||
|
// Skip offset bytes in lookup array.
|
||||||
|
skipByteTextIndex(offset);
|
||||||
|
|
||||||
|
HexEditorContentOutlineTreeObject treeObject;
|
||||||
|
|
||||||
|
error = (fileContentLength - offset) < 7;
|
||||||
|
if (!error) {
|
||||||
|
startAddress = fileContent.getWord(offset + 2);
|
||||||
|
endAddress = fileContent.getWord(offset + 4);
|
||||||
|
|
||||||
|
blockCount = 1;
|
||||||
|
blockEnd = offset + endAddress - startAddress + 6;
|
||||||
|
treeObject = printBlockHeader(contentBuilder, Texts.HEX_EDITOR_ATARI_COM_BLOCK_HEADER, blockCount,
|
||||||
|
Texts.HEX_EDITOR_ATARI_COM_BLOCK_HEADER_PARAMETERS, offset, startAddress, endAddress);
|
||||||
|
offset = printBytes(treeObject, contentBuilder, offset, offset + 5, true, 0);
|
||||||
|
|
||||||
|
boolean blockMode;
|
||||||
|
blockMode = true;
|
||||||
|
error = blockEnd >= fileContentLength;
|
||||||
|
try {
|
||||||
|
while (blockMode && !error) {
|
||||||
|
offset = printBytes(treeObject, contentBuilder, offset, blockEnd, true, startAddress);
|
||||||
|
|
||||||
|
int headerLength = -1;
|
||||||
|
// No more bytes left?
|
||||||
|
if (offset == fileContentLength) {
|
||||||
|
blockMode = false;
|
||||||
|
} else
|
||||||
|
// At least 5 bytes available? (4 header bytes and 1 data
|
||||||
|
// byte)
|
||||||
|
if (fileContentLength - offset < 5) {
|
||||||
|
error = true;
|
||||||
|
} else {
|
||||||
|
boolean comHeader;
|
||||||
|
comHeader = fileContent.getWord(offset) == COM_HEADER;
|
||||||
|
if (comHeader) {
|
||||||
|
// At least 7 bytes available? (6 header bytes and 1
|
||||||
|
// data byte)
|
||||||
|
if (fileContentLength - offset < 7) {
|
||||||
|
error = true;
|
||||||
|
} else {
|
||||||
|
// Inner COM header found
|
||||||
|
headerLength = 6;
|
||||||
|
startAddress = fileContent.getByte(offset + 2) + 256 * fileContent.getByte(offset + 3);
|
||||||
|
endAddress = fileContent.getByte(offset + 4) + 256 * fileContent.getByte(offset + 5);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// No inner COM header found
|
||||||
|
headerLength = 4;
|
||||||
|
startAddress = fileContent.getByte(offset + 0) + 256 * fileContent.getByte(offset + 1);
|
||||||
|
endAddress = fileContent.getByte(offset + 2) + 256 * fileContent.getByte(offset + 3);
|
||||||
|
}
|
||||||
|
error = endAddress < startAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blockMode) {
|
||||||
|
contentBuilder.append("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blockMode && !error) {
|
||||||
|
blockCount++;
|
||||||
|
blockEnd = offset + endAddress - startAddress + headerLength;
|
||||||
|
if (blockEnd < fileContentLength) {
|
||||||
|
|
||||||
|
treeObject = printBlockHeader(contentBuilder, Texts.HEX_EDITOR_ATARI_COM_BLOCK_HEADER,
|
||||||
|
blockCount, Texts.HEX_EDITOR_ATARI_COM_BLOCK_HEADER_PARAMETERS, offset,
|
||||||
|
startAddress, endAddress);
|
||||||
|
offset = printBytes(treeObject, contentBuilder, offset, offset + headerLength - 1, true, 0);
|
||||||
|
} else {
|
||||||
|
error = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (RuntimeException ex) {
|
||||||
|
contentBuilder.append(ex.toString());
|
||||||
|
error = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (error) {
|
||||||
|
printBlockWithError(contentBuilder, Texts.HEX_EDITOR_ATARI_COM_BLOCK_ERROR, fileContentLength, offset);
|
||||||
|
}
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
if (error) {
|
|
||||||
printBlockWithError(contentBuilder, Texts.HEX_EDITOR_ATARI_COM_BLOCK_ERROR, fileContentLength, offset);
|
|
||||||
}
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,26 +26,26 @@ import com.wudsn.ide.hex.HexEditorContentOutlineTreeObject;
|
||||||
|
|
||||||
public final class AtariSAPParser extends AtariParser {
|
public final class AtariSAPParser extends AtariParser {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean parse(StyledString contentBuilder) {
|
public boolean parse(StyledString contentBuilder) {
|
||||||
if (contentBuilder == null) {
|
if (contentBuilder == null) {
|
||||||
throw new IllegalArgumentException("Parameter 'contentBuilder' must not be null.");
|
throw new IllegalArgumentException("Parameter 'contentBuilder' must not be null.");
|
||||||
}
|
}
|
||||||
long offset = 0;
|
long offset = 0;
|
||||||
int fileContentLenght = fileContent.getLength();
|
int fileContentLenght = fileContent.getLength();
|
||||||
int maxOffset = fileContentLenght - 2;
|
int maxOffset = fileContentLenght - 2;
|
||||||
while (offset < maxOffset && fileContent.getByte(offset) != 0xff && fileContent.getByte(offset) != 0xff) {
|
while (offset < maxOffset && fileContent.getByte(offset) != 0xff && fileContent.getByte(offset) != 0xff) {
|
||||||
offset++;
|
offset++;
|
||||||
}
|
}
|
||||||
if (offset == maxOffset) {
|
if (offset == maxOffset) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
HexEditorContentOutlineTreeObject treeObject = printBlockHeader(contentBuilder,
|
HexEditorContentOutlineTreeObject treeObject = printBlockHeader(contentBuilder,
|
||||||
Texts.HEX_EDITOR_ATARI_SAP_FILE_HEADER, -1, "", 0, 0, 0);
|
Texts.HEX_EDITOR_ATARI_SAP_FILE_HEADER, -1, "", 0, 0, 0);
|
||||||
printBytes(treeObject, contentBuilder, 0, offset - 1, false, 0);
|
printBytes(treeObject, contentBuilder, 0, offset - 1, false, 0);
|
||||||
contentBuilder.append("\n");
|
contentBuilder.append("\n");
|
||||||
|
|
||||||
return parseAtariCOMFile(contentBuilder, offset, fileContentLenght);
|
return parseAtariCOMFile(contentBuilder, offset, fileContentLenght);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,165 +30,164 @@ import com.wudsn.ide.hex.Texts;
|
||||||
|
|
||||||
public class AtariSDXParser extends HexEditorParser {
|
public class AtariSDXParser extends HexEditorParser {
|
||||||
|
|
||||||
public static final int NON_RELOC_HEADER = 0xfffa;
|
public static final int NON_RELOC_HEADER = 0xfffa;
|
||||||
public static final int RELOC_HEADER = 0xfffe;
|
public static final int RELOC_HEADER = 0xfffe;
|
||||||
public static final int UPDATE_RELOC_HEADER = 0xfffd;
|
public static final int UPDATE_RELOC_HEADER = 0xfffd;
|
||||||
public static final int UPDATE_SYMBOLS_HEADER = 0xfffb;
|
public static final int UPDATE_SYMBOLS_HEADER = 0xfffb;
|
||||||
public static final int DEFINE_SYMBOLS_HEADER = 0xfffc;
|
public static final int DEFINE_SYMBOLS_HEADER = 0xfffc;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean parse(StyledString contentBuilder) {
|
public boolean parse(StyledString contentBuilder) {
|
||||||
if (contentBuilder == null) {
|
if (contentBuilder == null) {
|
||||||
throw new IllegalArgumentException("Parameter 'contentBuilder' must not be null.");
|
throw new IllegalArgumentException("Parameter 'contentBuilder' must not be null.");
|
||||||
}
|
|
||||||
|
|
||||||
boolean error;
|
|
||||||
long offset = 0;
|
|
||||||
|
|
||||||
// Skip offset bytes in lookup array.
|
|
||||||
skipByteTextIndex(offset);
|
|
||||||
|
|
||||||
HexEditorContentOutlineTreeObject treeObject;
|
|
||||||
int fileContentLength = fileContent.getLength();
|
|
||||||
|
|
||||||
error = (fileContentLength - offset) < 7;
|
|
||||||
boolean first = true;
|
|
||||||
boolean more = true;
|
|
||||||
try {
|
|
||||||
while (more && !error) {
|
|
||||||
if (!first) {
|
|
||||||
contentBuilder.append("\n");
|
|
||||||
}
|
}
|
||||||
first = false;
|
|
||||||
if (offset == fileContentLength) {
|
|
||||||
more = false;
|
|
||||||
} else {
|
|
||||||
int header = fileContent.getWord(offset);
|
|
||||||
if (header == NON_RELOC_HEADER) {
|
|
||||||
int startAddress = fileContent.getWord(offset + 2);
|
|
||||||
int endAddress = fileContent.getWord(offset + 4);
|
|
||||||
|
|
||||||
treeObject = printBlockHeader(contentBuilder, Texts.HEX_EDITOR_ATARI_SDX_NON_RELOC_BLOCK_HEADER,
|
boolean error;
|
||||||
-1, Texts.HEX_EDITOR_ATARI_SDX_NON_RELOC_BLOCK_HEADER_PARAMETERS, offset, startAddress,
|
long offset = 0;
|
||||||
endAddress);
|
|
||||||
offset = printBytes(treeObject, contentBuilder, offset, offset + 5, true, 0);
|
|
||||||
|
|
||||||
long blockEnd = offset + endAddress - startAddress;
|
// Skip offset bytes in lookup array.
|
||||||
|
skipByteTextIndex(offset);
|
||||||
|
|
||||||
offset = printBytes(treeObject, contentBuilder, offset, blockEnd, true, startAddress);
|
HexEditorContentOutlineTreeObject treeObject;
|
||||||
|
int fileContentLength = fileContent.getLength();
|
||||||
|
|
||||||
} else if (header == RELOC_HEADER) {
|
error = (fileContentLength - offset) < 7;
|
||||||
int blockNumber = fileContent.getByte(offset + 2);
|
boolean first = true;
|
||||||
int blockId = fileContent.getByte(offset + 3);
|
boolean more = true;
|
||||||
int blockOffset = fileContent.getWord(offset + 4);
|
try {
|
||||||
int blockLength = fileContent.getWord(offset + 6);
|
while (more && !error) {
|
||||||
|
if (!first) {
|
||||||
|
contentBuilder.append("\n");
|
||||||
|
}
|
||||||
|
first = false;
|
||||||
|
if (offset == fileContentLength) {
|
||||||
|
more = false;
|
||||||
|
} else {
|
||||||
|
int header = fileContent.getWord(offset);
|
||||||
|
if (header == NON_RELOC_HEADER) {
|
||||||
|
int startAddress = fileContent.getWord(offset + 2);
|
||||||
|
int endAddress = fileContent.getWord(offset + 4);
|
||||||
|
|
||||||
String headerText = TextUtility.format(Texts.HEX_EDITOR_ATARI_SDX_RELOC_BLOCK_HEADER,
|
treeObject = printBlockHeader(contentBuilder, Texts.HEX_EDITOR_ATARI_SDX_NON_RELOC_BLOCK_HEADER,
|
||||||
NumberUtility.getLongValueDecimalString(blockNumber),
|
-1, Texts.HEX_EDITOR_ATARI_SDX_NON_RELOC_BLOCK_HEADER_PARAMETERS, offset, startAddress,
|
||||||
HexUtility.getByteValueHexString(blockId),
|
endAddress);
|
||||||
HexUtility.getLongValueHexString(blockOffset, 4),
|
offset = printBytes(treeObject, contentBuilder, offset, offset + 5, true, 0);
|
||||||
HexUtility.getLongValueHexString(blockLength, 4));
|
|
||||||
StyledString headerStyledString = new StyledString(headerText, offsetStyler);
|
|
||||||
contentBuilder.append(headerStyledString).append("\n");
|
|
||||||
treeObject = printBlockHeader(contentBuilder, headerStyledString, offset);
|
|
||||||
offset = printBytes(treeObject, contentBuilder, offset, offset + 7, true, 0);
|
|
||||||
|
|
||||||
long blockEnd = offset + blockLength - 1;
|
long blockEnd = offset + endAddress - startAddress;
|
||||||
|
|
||||||
// Print bytes only of the block is not marked as EMPTY
|
offset = printBytes(treeObject, contentBuilder, offset, blockEnd, true, startAddress);
|
||||||
if ((blockId & 0x80) != 0x80) {
|
|
||||||
offset = printBytes(treeObject, contentBuilder, offset, blockEnd, true, blockOffset);
|
} else if (header == RELOC_HEADER) {
|
||||||
|
int blockNumber = fileContent.getByte(offset + 2);
|
||||||
|
int blockId = fileContent.getByte(offset + 3);
|
||||||
|
int blockOffset = fileContent.getWord(offset + 4);
|
||||||
|
int blockLength = fileContent.getWord(offset + 6);
|
||||||
|
|
||||||
|
String headerText = TextUtility.format(Texts.HEX_EDITOR_ATARI_SDX_RELOC_BLOCK_HEADER,
|
||||||
|
NumberUtility.getLongValueDecimalString(blockNumber),
|
||||||
|
HexUtility.getByteValueHexString(blockId),
|
||||||
|
HexUtility.getLongValueHexString(blockOffset, 4),
|
||||||
|
HexUtility.getLongValueHexString(blockLength, 4));
|
||||||
|
StyledString headerStyledString = new StyledString(headerText, offsetStyler);
|
||||||
|
contentBuilder.append(headerStyledString).append("\n");
|
||||||
|
treeObject = printBlockHeader(contentBuilder, headerStyledString, offset);
|
||||||
|
offset = printBytes(treeObject, contentBuilder, offset, offset + 7, true, 0);
|
||||||
|
|
||||||
|
long blockEnd = offset + blockLength - 1;
|
||||||
|
|
||||||
|
// Print bytes only of the block is not marked as EMPTY
|
||||||
|
if ((blockId & 0x80) != 0x80) {
|
||||||
|
offset = printBytes(treeObject, contentBuilder, offset, blockEnd, true, blockOffset);
|
||||||
|
}
|
||||||
|
} else if (header == UPDATE_RELOC_HEADER) {
|
||||||
|
int blockNumber = fileContent.getByte(offset + 2);
|
||||||
|
int blockLength = fileContent.getWord(offset + 3);
|
||||||
|
|
||||||
|
String headerText = TextUtility.format(Texts.HEX_EDITOR_ATARI_SDX_UPDATE_RELOC_BLOCK_HEADER,
|
||||||
|
NumberUtility.getLongValueDecimalString(blockNumber),
|
||||||
|
HexUtility.getLongValueHexString(blockLength, 4));
|
||||||
|
StyledString headerStyledString = new StyledString(headerText, offsetStyler);
|
||||||
|
contentBuilder.append(headerStyledString).append("\n");
|
||||||
|
treeObject = printBlockHeader(contentBuilder, headerStyledString, offset);
|
||||||
|
offset = printBytes(treeObject, contentBuilder, offset, offset + 4, true, 0);
|
||||||
|
long blockEnd = getBlockEnd(offset);
|
||||||
|
offset = printBytes(treeObject, contentBuilder, offset, blockEnd, true, 0);
|
||||||
|
} else if (header == UPDATE_SYMBOLS_HEADER) {
|
||||||
|
String symbolName = getSymbolName(offset + 2);
|
||||||
|
int blockLength = fileContent.getWord(offset + 10);
|
||||||
|
|
||||||
|
String headerText = TextUtility.format(Texts.HEX_EDITOR_ATARI_SDX_UPDATE_SYMBOLS_BLOCK_HEADER,
|
||||||
|
symbolName, HexUtility.getLongValueHexString(blockLength, 4));
|
||||||
|
StyledString headerStyledString = new StyledString(headerText, offsetStyler);
|
||||||
|
contentBuilder.append(headerStyledString).append("\n");
|
||||||
|
treeObject = printBlockHeader(contentBuilder, headerStyledString, offset);
|
||||||
|
offset = printBytes(treeObject, contentBuilder, offset, offset + 11, true, 0);
|
||||||
|
long blockEnd = getBlockEnd(offset);
|
||||||
|
offset = printBytes(treeObject, contentBuilder, offset, blockEnd, true, 0);
|
||||||
|
} else if (header == DEFINE_SYMBOLS_HEADER) {
|
||||||
|
int blockNumber = fileContent.getByte(offset + 2);
|
||||||
|
int blockOffset = fileContent.getWord(offset + 3);
|
||||||
|
String symbolName = getSymbolName(offset + 5);
|
||||||
|
|
||||||
|
String headerText = TextUtility.format(Texts.HEX_EDITOR_ATARI_SDX_DEFINE_SYMBOLS_BLOCK_HEADER,
|
||||||
|
NumberUtility.getLongValueDecimalString(blockNumber),
|
||||||
|
HexUtility.getLongValueHexString(blockOffset), symbolName);
|
||||||
|
StyledString headerStyledString = new StyledString(headerText, offsetStyler);
|
||||||
|
contentBuilder.append(headerStyledString).append("\n");
|
||||||
|
treeObject = printBlockHeader(contentBuilder, headerStyledString, offset);
|
||||||
|
offset = printBytes(treeObject, contentBuilder, offset, offset + 12, true, 0);
|
||||||
|
} else {
|
||||||
|
error = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (header == UPDATE_RELOC_HEADER) {
|
} catch (RuntimeException ex) {
|
||||||
int blockNumber = fileContent.getByte(offset + 2);
|
contentBuilder.append(ex.toString());
|
||||||
int blockLength = fileContent.getWord(offset + 3);
|
|
||||||
|
|
||||||
String headerText = TextUtility.format(Texts.HEX_EDITOR_ATARI_SDX_UPDATE_RELOC_BLOCK_HEADER,
|
|
||||||
NumberUtility.getLongValueDecimalString(blockNumber),
|
|
||||||
HexUtility.getLongValueHexString(blockLength, 4));
|
|
||||||
StyledString headerStyledString = new StyledString(headerText, offsetStyler);
|
|
||||||
contentBuilder.append(headerStyledString).append("\n");
|
|
||||||
treeObject = printBlockHeader(contentBuilder, headerStyledString, offset);
|
|
||||||
offset = printBytes(treeObject, contentBuilder, offset, offset + 4, true, 0);
|
|
||||||
long blockEnd = getBlockEnd(offset);
|
|
||||||
offset = printBytes(treeObject, contentBuilder, offset, blockEnd, true, 0);
|
|
||||||
} else if (header == UPDATE_SYMBOLS_HEADER) {
|
|
||||||
String symbolName = getSymbolName(offset + 2);
|
|
||||||
int blockLength = fileContent.getWord(offset + 10);
|
|
||||||
|
|
||||||
String headerText = TextUtility.format(Texts.HEX_EDITOR_ATARI_SDX_UPDATE_SYMBOLS_BLOCK_HEADER,
|
|
||||||
symbolName, HexUtility.getLongValueHexString(blockLength, 4));
|
|
||||||
StyledString headerStyledString = new StyledString(headerText, offsetStyler);
|
|
||||||
contentBuilder.append(headerStyledString).append("\n");
|
|
||||||
treeObject = printBlockHeader(contentBuilder, headerStyledString, offset);
|
|
||||||
offset = printBytes(treeObject, contentBuilder, offset, offset + 11, true, 0);
|
|
||||||
long blockEnd = getBlockEnd(offset);
|
|
||||||
offset = printBytes(treeObject, contentBuilder, offset, blockEnd, true, 0);
|
|
||||||
} else if (header == DEFINE_SYMBOLS_HEADER) {
|
|
||||||
int blockNumber = fileContent.getByte(offset + 2);
|
|
||||||
int blockOffset = fileContent.getWord(offset + 3);
|
|
||||||
String symbolName = getSymbolName(offset + 5);
|
|
||||||
|
|
||||||
String headerText = TextUtility.format(Texts.HEX_EDITOR_ATARI_SDX_DEFINE_SYMBOLS_BLOCK_HEADER,
|
|
||||||
NumberUtility.getLongValueDecimalString(blockNumber),
|
|
||||||
HexUtility.getLongValueHexString(blockOffset), symbolName);
|
|
||||||
StyledString headerStyledString = new StyledString(headerText, offsetStyler);
|
|
||||||
contentBuilder.append(headerStyledString).append("\n");
|
|
||||||
treeObject = printBlockHeader(contentBuilder, headerStyledString, offset);
|
|
||||||
offset = printBytes(treeObject, contentBuilder, offset, offset + 12, true, 0);
|
|
||||||
} else {
|
|
||||||
error = true;
|
error = true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} catch (RuntimeException ex) {
|
if (error) {
|
||||||
contentBuilder.append(ex.toString());
|
printBlockWithError(contentBuilder, Texts.HEX_EDITOR_ATARI_SDX_BLOCK_ERROR, fileContentLength, offset);
|
||||||
error = true;
|
}
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error) {
|
/**
|
||||||
printBlockWithError(contentBuilder, Texts.HEX_EDITOR_ATARI_SDX_BLOCK_ERROR, fileContentLength, offset);
|
* Gets end offset for UPDATE_RELOC_HEADER and UPDATE_SYMBOLS_HEADER.
|
||||||
|
*
|
||||||
|
* @param offset The start offset, a non-negative integer.
|
||||||
|
* @return The end offset, a non-negative integer.
|
||||||
|
*/
|
||||||
|
private long getBlockEnd(long offset) {
|
||||||
|
int fileContentLength = fileContent.getLength();
|
||||||
|
long i = offset;
|
||||||
|
long blockEnd = -1;
|
||||||
|
while (blockEnd < 0 && i < fileContentLength) {
|
||||||
|
int location = fileContent.getByte(i);
|
||||||
|
switch (location) {
|
||||||
|
case 0xfc:
|
||||||
|
blockEnd = i;
|
||||||
|
break;
|
||||||
|
case 0xfd:
|
||||||
|
i += 3;
|
||||||
|
break;
|
||||||
|
case 0xfe:
|
||||||
|
i += 3;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
i++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return blockEnd;
|
||||||
}
|
}
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
private String getSymbolName(long offset) {
|
||||||
* Gets end offset for UPDATE_RELOC_HEADER and UPDATE_SYMBOLS_HEADER.
|
StringBuffer buffer = new StringBuffer(8);
|
||||||
*
|
for (int i = 0; i < 8; i++) {
|
||||||
* @param offset
|
buffer.append((char) fileContent.getByte(offset + i));
|
||||||
* The start offset, a non-negative integer.
|
}
|
||||||
* @return The end offset, a non-negative integer.
|
return buffer.toString();
|
||||||
*/
|
|
||||||
private long getBlockEnd(long offset) {
|
|
||||||
int fileContentLength = fileContent.getLength();
|
|
||||||
long i = offset;
|
|
||||||
long blockEnd = -1;
|
|
||||||
while (blockEnd < 0 && i < fileContentLength) {
|
|
||||||
int location = fileContent.getByte(i);
|
|
||||||
switch (location) {
|
|
||||||
case 0xfc:
|
|
||||||
blockEnd = i;
|
|
||||||
break;
|
|
||||||
case 0xfd:
|
|
||||||
i += 3;
|
|
||||||
break;
|
|
||||||
case 0xfe:
|
|
||||||
i += 3;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
i++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return blockEnd;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getSymbolName(long offset) {
|
|
||||||
StringBuffer buffer = new StringBuffer(8);
|
|
||||||
for (int i = 0; i < 8; i++) {
|
|
||||||
buffer.append((char) fileContent.getByte(offset + i));
|
|
||||||
}
|
|
||||||
return buffer.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,14 +26,14 @@ import com.wudsn.ide.hex.HexEditorParser;
|
||||||
|
|
||||||
public class BinaryParser extends HexEditorParser {
|
public class BinaryParser extends HexEditorParser {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean parse(StyledString contentBuilder) {
|
public boolean parse(StyledString contentBuilder) {
|
||||||
if (contentBuilder == null) {
|
if (contentBuilder == null) {
|
||||||
throw new IllegalArgumentException("Parameter 'contentBuilder' must not be null.");
|
throw new IllegalArgumentException("Parameter 'contentBuilder' must not be null.");
|
||||||
|
}
|
||||||
|
HexEditorContentOutlineTreeObject treeObject = new HexEditorContentOutlineTreeObject(contentBuilder);
|
||||||
|
printBytes(treeObject, contentBuilder, 0, fileContent.getLength() - 1, false, 0);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
HexEditorContentOutlineTreeObject treeObject = new HexEditorContentOutlineTreeObject(contentBuilder);
|
|
||||||
printBytes(treeObject, contentBuilder, 0, fileContent.getLength() - 1, false, 0);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,37 +27,37 @@ import com.wudsn.ide.hex.HexEditorParser;
|
||||||
|
|
||||||
public class C64PRGParser extends HexEditorParser {
|
public class C64PRGParser extends HexEditorParser {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean parse(StyledString contentBuilder) {
|
public boolean parse(StyledString contentBuilder) {
|
||||||
if (contentBuilder == null) {
|
if (contentBuilder == null) {
|
||||||
throw new IllegalArgumentException("Parameter 'contentBuilder' must not be null.");
|
throw new IllegalArgumentException("Parameter 'contentBuilder' must not be null.");
|
||||||
|
}
|
||||||
|
boolean error;
|
||||||
|
int startAddress;
|
||||||
|
int endAddress;
|
||||||
|
|
||||||
|
int length = fileContent.getLength();
|
||||||
|
long offset = 0;
|
||||||
|
|
||||||
|
error = (length < 2);
|
||||||
|
if (!error) {
|
||||||
|
startAddress = fileContent.getByte(offset + 0) + 256 * fileContent.getByte(offset + 1);
|
||||||
|
endAddress = startAddress + length - 3;
|
||||||
|
|
||||||
|
HexEditorContentOutlineTreeObject treeObject;
|
||||||
|
treeObject = printBlockHeader(contentBuilder, Texts.HEX_EDITOR_C64_PRG_HEADER, -1,
|
||||||
|
Texts.HEX_EDITOR_C64_PRG_HEADER_PARAMETERS, offset, startAddress, endAddress);
|
||||||
|
offset = printBytes(treeObject, contentBuilder, offset, offset + 1, true, 0);
|
||||||
|
|
||||||
|
error = endAddress > 0xffff;
|
||||||
|
if (!error) {
|
||||||
|
printBytes(treeObject, contentBuilder, offset, length - 1, true, startAddress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (error) {
|
||||||
|
printBlockWithError(contentBuilder, Texts.HEX_EDITOR_C64_PRG_ERROR, length, offset);
|
||||||
|
}
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
boolean error;
|
|
||||||
int startAddress;
|
|
||||||
int endAddress;
|
|
||||||
|
|
||||||
int length = fileContent.getLength();
|
|
||||||
long offset = 0;
|
|
||||||
|
|
||||||
error = (length < 2);
|
|
||||||
if (!error) {
|
|
||||||
startAddress = fileContent.getByte(offset + 0) + 256 * fileContent.getByte(offset + 1);
|
|
||||||
endAddress = startAddress + length - 3;
|
|
||||||
|
|
||||||
HexEditorContentOutlineTreeObject treeObject;
|
|
||||||
treeObject = printBlockHeader(contentBuilder, Texts.HEX_EDITOR_C64_PRG_HEADER, -1,
|
|
||||||
Texts.HEX_EDITOR_C64_PRG_HEADER_PARAMETERS, offset, startAddress, endAddress);
|
|
||||||
offset = printBytes(treeObject, contentBuilder, offset, offset + 1, true, 0);
|
|
||||||
|
|
||||||
error = endAddress > 0xffff;
|
|
||||||
if (!error) {
|
|
||||||
printBytes(treeObject, contentBuilder, offset, length - 1, true, startAddress);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (error) {
|
|
||||||
printBlockWithError(contentBuilder, Texts.HEX_EDITOR_C64_PRG_ERROR, length, offset);
|
|
||||||
}
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,92 +30,92 @@ import com.wudsn.ide.hex.Texts;
|
||||||
|
|
||||||
public final class IFFParser extends HexEditorParser {
|
public final class IFFParser extends HexEditorParser {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final boolean parse(StyledString contentBuilder) {
|
public final boolean parse(StyledString contentBuilder) {
|
||||||
if (contentBuilder == null) {
|
if (contentBuilder == null) {
|
||||||
throw new IllegalArgumentException("Parameter 'contentBuilder' must not be null.");
|
throw new IllegalArgumentException("Parameter 'contentBuilder' must not be null.");
|
||||||
}
|
|
||||||
boolean error;
|
|
||||||
long offset = 0;
|
|
||||||
long fileContentLength = fileContent.getLength();
|
|
||||||
error = parse(contentBuilder, offset, fileContentLength, null);
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean parse(StyledString contentBuilder, long offset, long fileContentLength,
|
|
||||||
HexEditorContentOutlineTreeObject treeObject) {
|
|
||||||
boolean error;
|
|
||||||
|
|
||||||
error = (fileContentLength - offset) < 8;
|
|
||||||
if (!error) {
|
|
||||||
while ((fileContentLength - offset) >= 8 && !error) {
|
|
||||||
long headerLength = 8;
|
|
||||||
String chunkName = getChunkName(offset);
|
|
||||||
long chunkLength = fileContent.getDoubleWordBigEndian(offset + 4);
|
|
||||||
String headerText;
|
|
||||||
String formTypeName = "";
|
|
||||||
boolean hasInnerChunks = false;
|
|
||||||
if (chunkName.equals("FORM")) {
|
|
||||||
if (chunkLength >= 4) {
|
|
||||||
formTypeName = getChunkName(offset + 8);
|
|
||||||
headerText = TextUtility.format(Texts.HEX_EDITOR_IFF_FORM_CHUNK, chunkName, formTypeName,
|
|
||||||
HexUtility.getLongValueHexString(chunkLength),
|
|
||||||
NumberUtility.getLongValueDecimalString(chunkLength));
|
|
||||||
headerLength += 4;
|
|
||||||
chunkLength -= 4;
|
|
||||||
// Ignore trailing parts in the file outside of the main
|
|
||||||
// chunk
|
|
||||||
fileContentLength = offset + chunkLength;
|
|
||||||
hasInnerChunks = true;
|
|
||||||
} else {
|
|
||||||
error = true;
|
|
||||||
headerText = null;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
headerText = TextUtility.format(Texts.HEX_EDITOR_IFF_CHUNK, chunkName,
|
|
||||||
HexUtility.getLongValueHexString(chunkLength),
|
|
||||||
NumberUtility.getLongValueDecimalString(chunkLength));
|
|
||||||
}
|
}
|
||||||
|
boolean error;
|
||||||
|
long offset = 0;
|
||||||
|
long fileContentLength = fileContent.getLength();
|
||||||
|
error = parse(contentBuilder, offset, fileContentLength, null);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean parse(StyledString contentBuilder, long offset, long fileContentLength,
|
||||||
|
HexEditorContentOutlineTreeObject treeObject) {
|
||||||
|
boolean error;
|
||||||
|
|
||||||
|
error = (fileContentLength - offset) < 8;
|
||||||
if (!error) {
|
if (!error) {
|
||||||
StyledString styledString = new StyledString(headerText, offsetStyler);
|
while ((fileContentLength - offset) >= 8 && !error) {
|
||||||
treeObject = printBlockHeader(contentBuilder, styledString, offset);
|
long headerLength = 8;
|
||||||
contentBuilder.append(styledString);
|
String chunkName = getChunkName(offset);
|
||||||
contentBuilder.append("\n");
|
long chunkLength = fileContent.getDoubleWordBigEndian(offset + 4);
|
||||||
offset = printBytes(treeObject, contentBuilder, offset, offset + headerLength - 1, false, 0);
|
String headerText;
|
||||||
|
String formTypeName = "";
|
||||||
|
boolean hasInnerChunks = false;
|
||||||
|
if (chunkName.equals("FORM")) {
|
||||||
|
if (chunkLength >= 4) {
|
||||||
|
formTypeName = getChunkName(offset + 8);
|
||||||
|
headerText = TextUtility.format(Texts.HEX_EDITOR_IFF_FORM_CHUNK, chunkName, formTypeName,
|
||||||
|
HexUtility.getLongValueHexString(chunkLength),
|
||||||
|
NumberUtility.getLongValueDecimalString(chunkLength));
|
||||||
|
headerLength += 4;
|
||||||
|
chunkLength -= 4;
|
||||||
|
// Ignore trailing parts in the file outside of the main
|
||||||
|
// chunk
|
||||||
|
fileContentLength = offset + chunkLength;
|
||||||
|
hasInnerChunks = true;
|
||||||
|
} else {
|
||||||
|
error = true;
|
||||||
|
headerText = null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
headerText = TextUtility.format(Texts.HEX_EDITOR_IFF_CHUNK, chunkName,
|
||||||
|
HexUtility.getLongValueHexString(chunkLength),
|
||||||
|
NumberUtility.getLongValueDecimalString(chunkLength));
|
||||||
|
}
|
||||||
|
|
||||||
if (hasInnerChunks) {
|
if (!error) {
|
||||||
contentBuilder.append("\n");
|
StyledString styledString = new StyledString(headerText, offsetStyler);
|
||||||
|
treeObject = printBlockHeader(contentBuilder, styledString, offset);
|
||||||
|
contentBuilder.append(styledString);
|
||||||
|
contentBuilder.append("\n");
|
||||||
|
offset = printBytes(treeObject, contentBuilder, offset, offset + headerLength - 1, false, 0);
|
||||||
|
|
||||||
parse(contentBuilder, offset, fileContentLength, treeObject);
|
if (hasInnerChunks) {
|
||||||
offset += chunkLength;
|
contentBuilder.append("\n");
|
||||||
} else {
|
|
||||||
offset = printBytes(treeObject, contentBuilder, offset, offset + chunkLength - 1, false, 0);
|
|
||||||
}
|
|
||||||
contentBuilder.append("\n");
|
|
||||||
|
|
||||||
// Skip padding byte
|
parse(contentBuilder, offset, fileContentLength, treeObject);
|
||||||
if ((offset & 0x1) == 1) {
|
offset += chunkLength;
|
||||||
offset++;
|
} else {
|
||||||
}
|
offset = printBytes(treeObject, contentBuilder, offset, offset + chunkLength - 1, false, 0);
|
||||||
|
}
|
||||||
|
contentBuilder.append("\n");
|
||||||
|
|
||||||
|
// Skip padding byte
|
||||||
|
if ((offset & 0x1) == 1) {
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
if (error) {
|
||||||
|
printBlockWithError(contentBuilder, Texts.HEX_EDITOR_IFF_FILE_ERROR, fileContentLength, offset);
|
||||||
|
}
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
if (error) {
|
|
||||||
printBlockWithError(contentBuilder, Texts.HEX_EDITOR_IFF_FILE_ERROR, fileContentLength, offset);
|
|
||||||
}
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getChunkName(long offset) {
|
private String getChunkName(long offset) {
|
||||||
char[] id = new char[4];
|
char[] id = new char[4];
|
||||||
id[0] = (char) fileContent.getByte(offset);
|
id[0] = (char) fileContent.getByte(offset);
|
||||||
id[1] = (char) fileContent.getByte(offset + 1);
|
id[1] = (char) fileContent.getByte(offset + 1);
|
||||||
id[2] = (char) fileContent.getByte(offset + 2);
|
id[2] = (char) fileContent.getByte(offset + 2);
|
||||||
id[3] = (char) fileContent.getByte(offset + 3);
|
id[3] = (char) fileContent.getByte(offset + 3);
|
||||||
return String.copyValueOf(id);
|
return String.copyValueOf(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user