Reformat source

This commit is contained in:
peterdell 2021-09-18 01:09:46 +02:00
parent 25a4d82719
commit 62030ab828
34 changed files with 3498 additions and 3577 deletions

View File

@ -45,174 +45,172 @@ import com.wudsn.ide.asm.compiler.syntax.CompilerSyntax;
*/
public final class CompilerRegistry {
/**
* The id of the extension point which provides the compilers.
*/
private static final String COMPILERS = "com.wudsn.ide.asm.compilers";
/**
* The id of the extension point which provides the compilers.
*/
private static final String COMPILERS = "com.wudsn.ide.asm.compilers";
/**
* The registered compiler definition.
*/
private List<CompilerDefinition> compilerDefinitionList;
/**
* The registered compiler definition.
*/
private List<CompilerDefinition> compilerDefinitionList;
/**
* The cached map of compiler instances.
*/
private Map<String, Compiler> compilerMap;
/**
* The cached map of compiler instances.
*/
private Map<String, Compiler> compilerMap;
/**
* Creation is public.
*/
public CompilerRegistry() {
compilerDefinitionList = Collections.emptyList();
compilerMap = Collections.emptyMap();
/**
* Creation is public.
*/
public CompilerRegistry() {
compilerDefinitionList = Collections.emptyList();
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) {
IConfigurationElement[] configurationElements = extension.getConfigurationElements();
for (IConfigurationElement configurationElement : configurationElements) {
compilerDefinitionList = new ArrayList<CompilerDefinition>();
compilerMap = new TreeMap<String, Compiler>();
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);
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();
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);
compilerDefinitionList = Collections.unmodifiableList(compilerDefinitionList);
compilerMap = Collections.unmodifiableMap(compilerMap);
}
/**
* 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;
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;
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);
/**
* 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;
}
// 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);
/**
* 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) {
CompilerSyntax syntax;
syntax = new CompilerSyntax(id);
result = compilerMap.get(compilerId);
}
if (result == null) {
syntax.loadXMLData(compilerClasses);
throw new IllegalArgumentException("Unknown compiler id '" + compilerId + "'.");
}
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() + "'.");
return result;
}
}
/**
* 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;
}
}

View File

@ -29,79 +29,77 @@ import com.wudsn.ide.asm.Texts;
*/
public final class CompilerSyntaxUtility {
/**
* Creation private.
*/
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() + ".");
}
/**
* Creation private.
*/
private CompilerSyntaxUtility() {
}
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;
/**
* 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) {
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() + ".");
}
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.
*
* @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;
}
}

View File

@ -47,297 +47,297 @@ import com.wudsn.ide.base.common.StringUtility;
*/
public final class AppleFileWriter extends CompilerFileWriter {
private final static String HELLO_ENTRY_NAME = "HELLO";
private final static String OUTPUT_IMAGE_ENTRY_NAME = "WORLD";
private final static String HELLO_ENTRY_NAME = "HELLO";
private final static String OUTPUT_IMAGE_ENTRY_NAME = "WORLD";
private final class AppleSoftTokens {
public final static byte PRINT = (byte) 0xba;
public final static byte CHRS = (byte) 0xe7;
public final static byte CALL = (byte) 0x8c;
private final class AppleSoftTokens {
public final static byte PRINT = (byte) 0xba;
public final static byte CHRS = (byte) 0xe7;
public final static byte CALL = (byte) 0x8c;
// public String[] tokenNames = { "END", "FOR ", "NEXT ", "DATA ",
// "INPUT ", "DEL", "DIM ", "READ ", "GR", "TEXT", "PR#", "IN#",
// "CALL ", "PLOT", "HLIN ", "VLIN ", "HGR2", "HGR", "HCOLOR=",
// "HPLOT ", "DRAW ", "XDRAW ", "HTAB ", "HOME", "ROT=", "SCALE=",
// "SHLOAD", "TRACE", "NOTRACE", "NORMAL", "INVERSE", "FLASH",
// "COLOR=", "POP", "VTAB ", "HIMEM:", "LOMEM:", "ONERR ",
// "RESUME", "RECALL", "STORE", "SPEED=", "LET ", "GOTO ", "RUN",
// "IF ", "RESTORE", "& ", "GOSUB ", "RETURN", "REM ", "STOP",
// "ON ", "WAIT", "LOAD", "SAVE", "DEF", "POKE ", "PRINT ",
// "CONT", "LIST", "CLEAR", "GET ", "NEW", "TAB(", "TO ", "FN",
// "SPC(", "THEN ", "AT ", "NOT ", "STEP ", "+ ", "- ", "* ",
// "/ ", "^ ", "AND ", "OR ", "> ", "= ", "< ", "SGN", "INT",
// "ABS", "USR", "FRE", "SCRN(", "PDL", "POS ", "SQR", "RND",
// "LOG", "EXP", "COS", "SIN", "TAN", "ATN", "PEEK", "LEN",
// "STR$", "VAL", "ASC", "CHR$", "LEFT$", "RIGHT$", "MID$" };
// public String[] tokenNames = { "END", "FOR ", "NEXT ", "DATA ",
// "INPUT ", "DEL", "DIM ", "READ ", "GR", "TEXT", "PR#", "IN#",
// "CALL ", "PLOT", "HLIN ", "VLIN ", "HGR2", "HGR", "HCOLOR=",
// "HPLOT ", "DRAW ", "XDRAW ", "HTAB ", "HOME", "ROT=", "SCALE=",
// "SHLOAD", "TRACE", "NOTRACE", "NORMAL", "INVERSE", "FLASH",
// "COLOR=", "POP", "VTAB ", "HIMEM:", "LOMEM:", "ONERR ",
// "RESUME", "RECALL", "STORE", "SPEED=", "LET ", "GOTO ", "RUN",
// "IF ", "RESTORE", "& ", "GOSUB ", "RETURN", "REM ", "STOP",
// "ON ", "WAIT", "LOAD", "SAVE", "DEF", "POKE ", "PRINT ",
// "CONT", "LIST", "CLEAR", "GET ", "NEW", "TAB(", "TO ", "FN",
// "SPC(", "THEN ", "AT ", "NOT ", "STEP ", "+ ", "- ", "* ",
// "/ ", "^ ", "AND ", "OR ", "> ", "= ", "< ", "SGN", "INT",
// "ABS", "USR", "FRE", "SCRN(", "PDL", "POS ", "SQR", "RND",
// "LOG", "EXP", "COS", "SIN", "TAN", "ATN", "PEEK", "LEN",
// "STR$", "VAL", "ASC", "CHR$", "LEFT$", "RIGHT$", "MID$" };
// public int[] tokenAddresses = { 0xD870, 0xD766, 0xDCF9, 0xD995,
// 0xDBB2,
// 0xF331, 0xDFD9, 0xDBE2, 0xF390, 0xF399, 0xF1E5, 0xF1DE, 0xF1D5,
// 0xF225, 0xF232, 0xF241, 0xF3D8, 0xF3E2, 0xF6E9, 0xF6FE, 0xF769,
// 0xF76F, 0xF7E7, 0xFC58, 0xF721, 0xF727, 0xF775, 0xF26D, 0xF26F,
// 0xF273, 0xF277, 0xF280, 0xF24F, 0xD96B, 0xF256, 0xF286, 0xF2A6,
// 0xF2CB, 0xF318, 0xF3BC, 0xF39F, 0xF262, 0xDA46, 0xD93E, 0xD912,
// 0xD9C9, 0xD849, 0x03F5, 0xD921, 0xD96B, 0xD9DC, 0xD86E, 0xD9EC,
// 0xE784, 0xD8C9, 0xD8B0, 0xE313, 0xE77B, 0xFDAD5, 0xD896,
// 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,
// 0xD412, 0xDFCD, 0xE2FF, 0xEE8D, 0xEFAE, 0xE941, 0xEF09, 0xEFEA,
// 0xEFF1, 0xF03A, 0xF09E, 0xE764, 0xE6D6, 0xE3C5, 0xE707, 0xE6E5,
// 0xE646, 0xE65A, 0xE686, 0xE691 };
}
// public int[] tokenAddresses = { 0xD870, 0xD766, 0xDCF9, 0xD995,
// 0xDBB2,
// 0xF331, 0xDFD9, 0xDBE2, 0xF390, 0xF399, 0xF1E5, 0xF1DE, 0xF1D5,
// 0xF225, 0xF232, 0xF241, 0xF3D8, 0xF3E2, 0xF6E9, 0xF6FE, 0xF769,
// 0xF76F, 0xF7E7, 0xFC58, 0xF721, 0xF727, 0xF775, 0xF26D, 0xF26F,
// 0xF273, 0xF277, 0xF280, 0xF24F, 0xD96B, 0xF256, 0xF286, 0xF2A6,
// 0xF2CB, 0xF318, 0xF3BC, 0xF39F, 0xF262, 0xDA46, 0xD93E, 0xD912,
// 0xD9C9, 0xD849, 0x03F5, 0xD921, 0xD96B, 0xD9DC, 0xD86E, 0xD9EC,
// 0xE784, 0xD8C9, 0xD8B0, 0xE313, 0xE77B, 0xFDAD5, 0xD896,
// 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,
// 0xD412, 0xDFCD, 0xE2FF, 0xEE8D, 0xEFAE, 0xE941, 0xEF09, 0xEFEA,
// 0xEFF1, 0xF03A, 0xF09E, 0xE764, 0xE6D6, 0xE3C5, 0xE707, 0xE6E5,
// 0xE646, 0xE65A, 0xE686, 0xE691 };
}
@Override
public boolean createOrUpdateDiskImage(CompilerFiles files) {
String imageFilePath = files.outputFilePathWithoutExtension + ".dsk";
String outputImageEntryName = OUTPUT_IMAGE_ENTRY_NAME;
String outputImageEntryTitle = "Loading " + files.outputFileNameWithoutExtension;
boolean autoCreate = true;
@Override
public boolean createOrUpdateDiskImage(CompilerFiles files) {
String imageFilePath = files.outputFilePathWithoutExtension + ".dsk";
String outputImageEntryName = OUTPUT_IMAGE_ENTRY_NAME;
String outputImageEntryTitle = "Loading " + files.outputFileNameWithoutExtension;
boolean autoCreate = true;
if (StringUtility.isSpecified(imageFilePath)) {
File imageFile = new File(imageFilePath);
if (!imageFile.exists()) {
if (StringUtility.isSpecified(imageFilePath)) {
File imageFile = new File(imageFilePath);
if (!imageFile.exists()) {
// When auto creation is active, we copy a template file.
// This is the only way to get a disk image which is not only
// formatted but also has a boot loader which runs "HELLO".
if (autoCreate) {
String resource = "/lib/AppleDos.dsk";
InputStream inputStream = Disk.class.getClassLoader().getResourceAsStream(resource);
if (inputStream == null) {
throw new RuntimeException("Cannot get input stream for '" + resource + "'");
}
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] buffer = new byte[8192];
int count;
do {
try {
count = inputStream.read(buffer);
} catch (IOException ex) {
throw new RuntimeException("Cannot read input stream for '" + resource + "'", ex);
// When auto creation is active, we copy a template file.
// This is the only way to get a disk image which is not only
// formatted but also has a boot loader which runs "HELLO".
if (autoCreate) {
String resource = "/lib/AppleDos.dsk";
InputStream inputStream = Disk.class.getClassLoader().getResourceAsStream(resource);
if (inputStream == null) {
throw new RuntimeException("Cannot get input stream for '" + resource + "'");
}
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] buffer = new byte[8192];
int count;
do {
try {
count = inputStream.read(buffer);
} catch (IOException 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 (count > 0) {
bos.write(buffer, 0, count);
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;
}
} 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());
}
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;
}
} 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();
if (formattedDisks == null || formattedDisks.length == 0) {
// ERROR: Disk image file '{0}' does not contain a valid file
// system. Make sure the disk image is properly formatted, so
// the output file '{1}' can be stored.
MarkerUtility.createMarker(files.mainSourceFile.iFile, 0, IMarker.SEVERITY_ERROR, Texts.MESSAGE_E135,
imageFilePath, outputImageEntryName);
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;
FormattedDisk[] formattedDisks = disk.getFormattedDisks();
if (formattedDisks == null || formattedDisks.length == 0) {
// ERROR: Disk image file '{0}' does not contain a valid file
// system. Make sure the disk image is properly formatted, so
// the output file '{1}' can be stored.
MarkerUtility.createMarker(files.mainSourceFile.iFile, 0, IMarker.SEVERITY_ERROR, Texts.MESSAGE_E135,
imageFilePath, outputImageEntryName);
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) {
// 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;
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 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 {
formattedDisk.save();
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;
} 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
// error: {1}
MarkerUtility.createMarker(files.mainSourceFile.iFile, 0, IMarker.SEVERITY_ERROR, Texts.MESSAGE_E137,
imageFilePath, ex.getMessage());
return false;
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
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.");
}
}
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);
return (0xff & bytes[index]) + 256 * (0xff & bytes[index + 1]);
}
// Byte is the line length in bytes
entry.setFileData(program);
return entry;
}
private static int getWord(byte[] bytes, int index) {
if (bytes == null) {
throw new IllegalArgumentException("Parameter 'bytes' must not be null.");
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;
}
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;
}
}

View File

@ -75,485 +75,478 @@ import com.wudsn.ide.base.common.Profiler;
*/
public abstract class AssemblerEditor extends TextEditor {
private AssemblerPlugin plugin;
private AssemblerEditorFilesLogic filesLogic;
private AssemblerPlugin plugin;
private AssemblerEditorFilesLogic filesLogic;
private Compiler compiler;
private Compiler compiler;
private AssemblerContentOutlinePage contentOutlinePage;
private ProjectionAnnotationModel annotationModel;
private AssemblerContentOutlinePage contentOutlinePage;
private ProjectionAnnotationModel annotationModel;
private Hardware hardware;
private Hardware hardware;
/**
* Creates a new instance. Constructor parameters are not useful, because
* the super constructor inverts the flow of control, so
* {@link #initializeEditor} is called before the code in this constructor
* is executed.
*/
protected AssemblerEditor() {
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;
/**
* Creates a new instance. Constructor parameters are not useful, because the
* super constructor inverts the flow of control, so {@link #initializeEditor}
* is called before the code in this constructor is executed.
*/
protected AssemblerEditor() {
filesLogic = AssemblerEditorFilesLogic.createInstance(this);
}
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
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.");
/**
* Gets the files logic associated with this editor.
*
* @return The files logic, not <code>null</code>.
*/
public AssemblerEditorFilesLogic getFilesLogic() {
return filesLogic;
}
return plugin;
}
/**
* Gets the compiler preferences.
*
* @return The compiler preferences, not <code>null</code>.
*/
public final CompilerPreferences getCompilerPreferences() {
return plugin.getPreferences().getCompilerPreferences(getCompilerId(), getHardware());
}
/**
* 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;
/**
* 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.
*
* @return The compiler id for this editor, not empty and not <code>null</code>.
*/
protected abstract String getCompilerId();
@Override
protected final void createActions() {
super.createActions();
@Override
protected final void initializeEditor() {
super.initializeEditor();
ResourceBundle bundle = ResourceBundle.getBundle("com.wudsn.ide.asm.Actions", Locale.getDefault(),
AssemblerEditor.class.getClassLoader());
plugin = AssemblerPlugin.getInstance();
compiler = plugin.getCompilerRegistry().getCompiler(getCompilerId());
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);
setSourceViewerConfiguration(new AssemblerSourceViewerConfiguration(this, getPreferenceStore()));
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");
// refreshSourceViewer();
profiler.end("refreshSourceViewer");
}
/**
* 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.");
/**
* 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;
}
// Create a working copy.
foldingPositions = new ArrayList<Position>(foldingPositions);
List<ProjectionAnnotation> deletions = new ArrayList<ProjectionAnnotation>();
Object annotationObject = null;
ProjectionAnnotation annotation = null;
Position position = null;
/**
* Gets the compiler preferences.
*
* @return The compiler preferences, not <code>null</code>.
*/
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.
for (@SuppressWarnings("rawtypes")
Iterator iter = annotationModel.getAnnotationIterator(); iter.hasNext();) {
annotationObject = iter.next();
/**
* 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;
}
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 {
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
// with their corresponding folding positions.
HashMap<ProjectionAnnotation, Position> newAnnotations = new HashMap<ProjectionAnnotation, Position>();
// Ensure decoration support has been created and configured.
getSourceViewerDecorationSupport(viewer);
for (int i = 0; i < foldingPositions.size(); i++) {
annotation = new ProjectionAnnotation();
newAnnotations.put(annotation, foldingPositions.get(i));
// 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;
}
// Do not update anything if there is actual change to preserve the
// current cursor positioning.
if (removeAnnotations.length == 0 && newAnnotations.isEmpty()) {
return;
/**
* 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");
// 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.");
}
/**
* Gets the directory of the current file.
*
* @return The directory of the current file or <code>null</code>.
*/
public final File getCurrentDirectory() {
File result;
result = getCurrentFile();
if (result != null) {
result = result.getParentFile();
}
return result;
}
// Create a working copy.
foldingPositions = new ArrayList<Position>(foldingPositions);
List<ProjectionAnnotation> deletions = new ArrayList<ProjectionAnnotation>();
Object annotationObject = null;
ProjectionAnnotation annotation = null;
Position position = null;
/**
* 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;
}
// Access to the annotationModel is intentionally not synchronized, as
// otherwise deadlock would be the result.
for (@SuppressWarnings("rawtypes")
Iterator iter = annotationModel.getAnnotationIterator(); iter.hasNext();) {
annotationObject = iter.next();
/**
* 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();
if (annotationObject instanceof ProjectionAnnotation) {
annotation = (ProjectionAnnotation) annotationObject;
} else {
result = null;
}
return result;
}
position = annotationModel.getPosition(annotation);
/**
* 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 + ".");
if (foldingPositions.contains(position)) {
foldingPositions.remove(position);
} else {
deletions.add(annotation);
}
}
}
Annotation[] removeAnnotations = deletions.toArray(new Annotation[deletions.size()]);
// 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;
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;
/**
* Gets the directory of the current file.
*
* @return The directory of the current file or <code>null</code>.
*/
public final File getCurrentDirectory() {
File result;
result = getCurrentFile();
if (result != null) {
result = result.getParentFile();
}
return result;
}
/**
* 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;
}
}

View File

@ -39,55 +39,50 @@ import com.wudsn.ide.asm.compiler.CompilerFiles;
*/
public abstract class AssemblerEditorFilesCommandHandler extends AbstractHandler {
public AssemblerEditorFilesCommandHandler() {
super();
}
@Override
public Object execute(ExecutionEvent event) throws ExecutionException {
IEditorPart editor;
editor = HandlerUtil.getActiveEditorChecked(event);
if (!(editor instanceof AssemblerEditor)) {
return null;
public AssemblerEditorFilesCommandHandler() {
super();
}
AssemblerEditor assemblerEditor;
assemblerEditor = (AssemblerEditor) editor;
@Override
public Object execute(ExecutionEvent event) throws ExecutionException {
IEditorPart editor;
editor = HandlerUtil.getActiveEditorChecked(event);
if (!(editor instanceof AssemblerEditor)) {
return null;
}
CompilerFiles files;
files = AssemblerEditorFilesLogic.createInstance(assemblerEditor).createCompilerFiles();
AssemblerEditor assemblerEditor;
assemblerEditor = (AssemblerEditor) editor;
if (files != null) {
execute(event, assemblerEditor, files);
} else {
try {
AssemblerPlugin.getInstance().showError(
assemblerEditor.getSite().getShell(),
"Operation '" + event.getCommand().getName()
+ "' is not possible because the file in the editor is not located in the workspace.",
new Exception());
} catch (NotDefinedException ignore) {
// Ignore
}
CompilerFiles files;
files = AssemblerEditorFilesLogic.createInstance(assemblerEditor).createCompilerFiles();
if (files != null) {
execute(event, assemblerEditor, files);
} else {
try {
AssemblerPlugin.getInstance().showError(assemblerEditor.getSite().getShell(),
"Operation '" + event.getCommand().getName()
+ "' is not possible because the file in the editor is not located in the workspace.",
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.
*
* @param event
* The event, not <code>null</code>.
* @param assemblerEditor
* The assembler editor, not <code>null</code> and with current
* files which are not <code>null</code>.
* @param files
* The current compiler files of the editor, not
* <code>null</code> .
* @throws ExecutionException
* if an exception occurred during execution.
*/
protected abstract void execute(ExecutionEvent event, AssemblerEditor assemblerEditor, CompilerFiles files)
throws ExecutionException;
/**
* Perform the action on the current editor and file.
*
* @param event The event, not <code>null</code>.
* @param assemblerEditor The assembler editor, not <code>null</code> and with
* current files which are not <code>null</code>.
* @param files The current compiler files of the editor, not
* <code>null</code> .
* @throws ExecutionException if an exception occurred during execution.
*/
protected abstract void execute(ExecutionEvent event, AssemblerEditor assemblerEditor, CompilerFiles files)
throws ExecutionException;
}

View File

@ -55,318 +55,310 @@ import com.wudsn.ide.base.common.StringUtility;
*/
public final class AssemblerEditorFilesLogic {
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();
}
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.");
}
}
result = new CompilerFiles(mainSourceIFile, mainSourceFileProperties, sourceIFile, sourceFileProperties,
assemblerEditor.getCompilerPreferences());
} else {
result = null;
}
return result;
}
public boolean removeMarkers(CompilerFiles files) {
if (files == null) {
throw new IllegalArgumentException("Parameter 'files' must not be null.");
AssemblerEditorFilesLogic result = new AssemblerEditorFilesLogic();
result.assemblerEditor = assemblerEditor;
return result;
}
// Remove markers from the current file.
try {
files.sourceFile.iFile.deleteMarkers(IMarker.PROBLEM, true, IResource.DEPTH_INFINITE);
} catch (CoreException ex) {
assemblerEditor.getPlugin().logError("Cannot remove markers", null, ex);
}
/**
* 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) {
// 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;
IDocument document = assemblerEditor.getDocumentProvider().getDocument(assemblerEditor.getEditorInput());
AssemblerProperties sourceFileProperties = CompilerSourceParser.getDocumentProperties(document);
// 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;
}
IFile mainSourceIFile;
AssemblerProperties mainSourceFileProperties;
// Remove markers from the other relevant files.
// TODO Use (only) include files parsed from main source file
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;
}
mainSourceIFile = sourceIFile;
mainSourceFileProperties = sourceFileProperties;
/**
* Determine the hardware defined by the property
* {@link AssemblerProperties#HARDWARE}.
*
* @param iFile
* The iFIle to which error message will be associated, not
* <code>null</code>.
* @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()) {
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());
if (value != Hardware.GENERIC) {
if (allowedValuesBuilder.length() > 0) {
allowedValuesBuilder.append(",");
}
allowedValues.put(value.name(), value);
allowedValuesBuilder.append(value.name());
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();
}
}
}
result = new CompilerFiles(mainSourceIFile, mainSourceFileProperties, sourceIFile, sourceFileProperties,
assemblerEditor.getCompilerPreferences());
} else {
result = null;
}
}
return result;
}
String hardwarePropertyValue = hardwareProperty.value.toUpperCase();
if (StringUtility.isEmpty(hardwarePropertyValue)) {
public boolean removeMarkers(CompilerFiles files) {
if (files == null) {
throw new IllegalArgumentException("Parameter 'files' must not be null.");
}
// Remove markers from the current file.
try {
iFile.deleteMarkers(IMarker.PROBLEM, true, IResource.DEPTH_ZERO);
files.sourceFile.iFile.deleteMarkers(IMarker.PROBLEM, true, IResource.DEPTH_INFINITE);
} 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 {
iFile.deleteMarkers(IMarker.PROBLEM, true, IResource.DEPTH_ZERO);
files.mainSourceFile.iFile.getParent().deleteMarkers(IMarker.PROBLEM, true, IResource.DEPTH_INFINITE);
} 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
// 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;
return true;
}
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;
}
/**
* Determine the hardware defined by the property
* {@link AssemblerProperties#HARDWARE}.
*
* @param iFile The iFIle to which error message will be associated, not
* <code>null</code>.
* @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()) {
/**
* 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);
if (value != Hardware.GENERIC) {
if (allowedValuesBuilder.length() > 0) {
allowedValuesBuilder.append(",");
}
allowedValues.put(value.name(), value);
allowedValuesBuilder.append(value.name());
}
}
return false;
}
if (!files.outputFileExtension.startsWith(".")) {
// ERROR: Output file extension {0} must start with ".".
createMainSourceFileMessage(files, files.outputFileExtensionProperty, IMarker.SEVERITY_ERROR,
Texts.MESSAGE_E139, files.outputFileExtension);
return false;
String hardwarePropertyValue = hardwareProperty.value.toUpperCase();
if (StringUtility.isEmpty(hardwarePropertyValue)) {
try {
iFile.deleteMarkers(IMarker.PROBLEM, true, IResource.DEPTH_ZERO);
} catch (CoreException ex) {
AssemblerPlugin.getInstance().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) {
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
// compiler '{0}' or via the annotation '{1}'.
createMainSourceFileMessage(files, files.outputFolderModeProperty, IMarker.SEVERITY_ERROR,
Texts.MESSAGE_E140, compilerDefinition.getName(), AssemblerProperties.OUTPUT_FOLDER_MODE);
return false;
}
if (!CompilerOutputFolderMode.isDefined(files.outputFolderMode)) {
// ERROR: Unknown output folder mode {0}. Specify one of the
// following valid values '{1}'.
createMainSourceFileMessage(files, files.outputFolderModeProperty, IMarker.SEVERITY_ERROR,
Texts.MESSAGE_E141, files.outputFolderMode, CompilerOutputFolderMode.getAllowedValues());
return false;
/**
* 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}
// 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);
/**
* 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.");
return false;
}
if (!files.outputFileExtension.startsWith(".")) {
// ERROR: Output file extension {0} must start with ".".
createMainSourceFileMessage(files, files.outputFileExtensionProperty, IMarker.SEVERITY_ERROR,
Texts.MESSAGE_E139, files.outputFileExtension);
return false;
}
if (StringUtility.isEmpty(files.outputFolderMode)) {
// ERROR: Output folder mode be set in the preferences of
// compiler '{0}' or via the annotation '{1}'.
createMainSourceFileMessage(files, files.outputFolderModeProperty, IMarker.SEVERITY_ERROR,
Texts.MESSAGE_E140, compilerDefinition.getName(), AssemblerProperties.OUTPUT_FOLDER_MODE);
return false;
}
if (!CompilerOutputFolderMode.isDefined(files.outputFolderMode)) {
// ERROR: Unknown output folder mode {0}. Specify one of the
// following valid values '{1}'.
createMainSourceFileMessage(files, files.outputFolderModeProperty, IMarker.SEVERITY_ERROR,
Texts.MESSAGE_E141, files.outputFolderMode, CompilerOutputFolderMode.getAllowedValues());
return false;
}
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);
}
}

View File

@ -33,214 +33,208 @@ import com.wudsn.ide.base.common.StringUtility;
*/
public final class CompilerPreferences {
private AssemblerPreferences assemblerPreferences;
private Hardware hardware;
private String compilerId;
private AssemblerPreferences assemblerPreferences;
private Hardware hardware;
private String compilerId;
CompilerPreferences(AssemblerPreferences assemblerPreferences, String compilerId, Hardware hardware) {
if (assemblerPreferences == null) {
throw new IllegalArgumentException("Parameter 'assemblerPreferences' must not be null.");
CompilerPreferences(AssemblerPreferences assemblerPreferences, String compilerId, Hardware hardware) {
if (assemblerPreferences == 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.
*
* @return The compiler id of the compiler, not empty and not
* <code>null</code>.
*/
public String getCompilerId() {
return compilerId;
}
/**
* 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);
/**
* Determines if illegal opcodes shall be highlighted and proposed.
*
* @return <code>true</code> if yet, <code>false</code> otherwise.
*/
@Deprecated
public boolean isIllegalOpcodesVisible() {
return getCPU() == CPU.MOS6502_ILLEGAL;
}
return result;
}
/**
* Determines if illegal opcodes shall be highlighted and proposed.
*
* @return <code>true</code> if yet, <code>false</code> otherwise.
*/
@Deprecated
public boolean isIllegalOpcodesVisible() {
return getCPU() == CPU.MOS6502_ILLEGAL;
}
/**
* 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;
/**
* 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;
}
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.");
/**
* 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));
}
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 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() {
/**
* 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.");
return assemblerPreferences
.getString(AssemblerPreferencesConstants.getCompilerOutputFolderModeName(compilerId, hardware));
}
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));
}
}

View File

@ -1,8 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry combineaccessrules="false" kind="src" path="/com.wudsn.ide.base"/>
<classpathentry kind="output" path="bin"/>
<classpathentry kind="con"
path="org.eclipse.pde.core.requiredPlugins" />
<classpathentry kind="src" path="src" />
<classpathentry kind="con"
path="org.eclipse.jdt.launching.JRE_CONTAINER" />
<classpathentry combineaccessrules="false" kind="src"
path="/com.wudsn.ide.base" />
<classpathentry kind="output" path="bin" />
</classpath>

View File

@ -2,46 +2,42 @@ package com.wudsn.ide.hex;
public interface FileContent {
/**
* Gets the length of the file content.
*
* @return The length of the file content, a non-negative integer.
*/
public int getLength();
/**
* Gets the length of the file content.
*
* @return The length of the file content, a non-negative integer.
*/
public int getLength();
/**
* Gets a byte (8 bit) from the file content.
*
* @param offset
* The offset, a non-negative integer.
* @return The byte from the file content.
*/
public int getByte(long offset);
/**
* Gets a byte (8 bit) from the file content.
*
* @param offset The offset, a non-negative integer.
* @return The byte from the file content.
*/
public int getByte(long offset);
/**
* Gets a word (16 bit) in little endian format from the file content.
*
* @param offset
* The offset, a non-negative integer.
* @return The word from the file content.
*/
public int getWord(long offset);
/**
* Gets a word (16 bit) in little endian format from the file content.
*
* @param offset The offset, a non-negative integer.
* @return The word from the file content.
*/
public int getWord(long offset);
/**
* Gets a word (16 bit) in big endian format from the file content.
*
* @param offset
* The offset, a non-negative integer.
* @return The word from the file content.
*/
public int getWordBigEndian(long offset);
/**
* Gets a word (16 bit) in big endian format from the file content.
*
* @param offset The offset, a non-negative integer.
* @return The word from the file content.
*/
public int getWordBigEndian(long offset);
/**
* Gets a double word (32 bit) in big endian format from the file content.
*
* @param offset
* The offset, a non-negative integer.
* @return The word from the file content.
*/
public long getDoubleWordBigEndian(long offset);
/**
* Gets a double word (32 bit) in big endian format from the file content.
*
* @param offset The offset, a non-negative integer.
* @return The word from the file content.
*/
public long getDoubleWordBigEndian(long offset);
}

View File

@ -1,78 +1,74 @@
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) {
if (fileContent == null) {
throw new IllegalArgumentException("Parameter 'fileContent' must not be null.");
public FileContentImpl(byte[] fileContent) {
if (fileContent == null) {
throw new IllegalArgumentException("Parameter 'fileContent' must not be null.");
}
this.fileContent = fileContent;
}
this.fileContent = fileContent;
}
/**
* Gets the length of the file content.
*
* @return The length of the file content, a non-negative integer.
*/
@Override
public int getLength() {
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");
/**
* Gets the length of the file content.
*
* @return The length of the file content, a non-negative integer.
*/
@Override
public int getLength() {
return fileContent.length;
}
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.
*
* @param offset
* The offset, a non-negative integer.
* @return The word from the file content.
*/
@Override
public int getWord(long offset) {
return getByte(offset) + 0x100 * getByte(offset + 1);
}
/**
* Gets a word (16 bit) in little endian format from the file content.
*
* @param offset The offset, a non-negative integer.
* @return The word from the file content.
*/
@Override
public int getWord(long offset) {
return getByte(offset) + 0x100 * getByte(offset + 1);
}
/**
* Gets a word (16 bit) in big endian format from the file content.
*
* @param offset
* The offset, a non-negative integer.
* @return The word from the file content.
*/
@Override
public int getWordBigEndian(long offset) {
return getByte(offset + 1) + 0x100 * getByte(offset);
}
/**
* Gets a word (16 bit) in big endian format from the file content.
*
* @param offset The offset, a non-negative integer.
* @return The word from the file content.
*/
@Override
public int getWordBigEndian(long offset) {
return getByte(offset + 1) + 0x100 * getByte(offset);
}
/**
* Gets a double word (32 bit) in big endian format from the file content.
*
* @param offset
* The offset, a non-negative integer.
* @return The word from the file content.
*/
@Override
public long getDoubleWordBigEndian(long offset) {
return getWordBigEndian(offset + 2) + 0x10000 * getWordBigEndian(offset);
}
/**
* Gets a double word (32 bit) in big endian format from the file content.
*
* @param offset The offset, a non-negative integer.
* @return The word from the file content.
*/
@Override
public long getDoubleWordBigEndian(long offset) {
return getWordBigEndian(offset + 2) + 0x10000 * getWordBigEndian(offset);
}
}

View File

@ -37,147 +37,147 @@ import com.wudsn.ide.base.common.NumberUtility;
*/
public final class HexEditorClipboardCommandHandler extends HexEditorSelectionCommandHandler {
public static final class CommandIds {
public static final class 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(',');
}
}
private CommandIds() {
}
} 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(' ');
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)) {
// 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 + "'.");
}
}
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(',');
}
}
data = new Object[] { builder.toString(), hexEditorSelection };
transfers = new Transfer[] { TextTransfer.getInstance(), HexEditorSelectionTransfer.getInstance() };
copyToClipboard(bytes, data, transfers);
} else if (commandId.equals(CommandIds.PASTE)) {
pasteFromClipboard();
}
} 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 {
throw new IllegalArgumentException("Unknown command '" + commandId + "'.");
}
data = new Object[] { builder.toString(), hexEditorSelection };
transfers = new Transfer[] { TextTransfer.getInstance(), HexEditorSelectionTransfer.getInstance() };
copyToClipboard(bytes, data, transfers);
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 {
} else if (commandId.equals(CommandIds.PASTE)) {
pasteFromClipboard();
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();
}
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();
}
}
}

View File

@ -31,50 +31,50 @@ import org.eclipse.swt.graphics.Image;
*/
final class HexEditorContentOutlineLabelProvider extends DelegatingStyledCellLabelProvider {
/** Outline segment image */
private final Image segmentImage;
/** Outline segment image */
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
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();
public Image getImage(Object element) {
Image result;
result = segmentImage;
return result;
}
}
/**
* 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;
}
}

View File

@ -34,52 +34,52 @@ import org.eclipse.ui.views.contentoutline.ContentOutlinePage;
*/
final class HexEditorContentOutlinePage extends ContentOutlinePage {
private HexEditor editor;
private Object input;
private HexEditor editor;
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
public void createControl(Composite parent) {
super.createControl(parent);
TreeViewer viewer = getTreeViewer();
viewer.getControl().setFont(JFaceResources.getTextFont());
viewer.setContentProvider(new HexEditorContentOutlineTreeContentProvider());
viewer.setLabelProvider(new HexEditorContentOutlineLabelProvider());
viewer.addSelectionChangedListener(this);
viewer.setAutoExpandLevel(AbstractTreeViewer.ALL_LEVELS);
TreeViewer viewer = getTreeViewer();
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.");
updateTreeView();
}
this.input = input;
updateTreeView();
}
private void updateTreeView() {
TreeViewer viewer = getTreeViewer();
if (viewer != null) {
viewer.setInput(input);
@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() {
TreeViewer viewer = getTreeViewer();
if (viewer != null) {
viewer.setInput(input);
}
}
}
}

View File

@ -31,63 +31,63 @@ import org.eclipse.jface.viewers.Viewer;
*/
final class HexEditorContentOutlineTreeContentProvider implements ITreeContentProvider {
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;
HexEditorContentOutlineTreeContentProvider() {
}
return result;
}
/**
* {@inheritDoc}
*/
@Override
public Object[] getChildren(Object parentElement) {
return null;
}
/**
* {@inheritDoc}
*/
@Override
public void dispose() {
/**
* {@inheritDoc}
*/
@Override
public Object getParent(Object element) {
}
return null;
}
/**
* {@inheritDoc}
*/
@Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
/**
* {@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 void dispose() {
}
/**
* {@inheritDoc}
*/
@Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
}

View File

@ -28,122 +28,117 @@ import org.eclipse.jface.viewers.StyledString;
*/
public final class HexEditorContentOutlineTreeObject {
private final StyledString styledString;
private long fileStartOffset;
private long textStartOffset;
private long fileEndOffset;
private long textEndOffset;
private final StyledString styledString;
private long fileStartOffset;
private long textStartOffset;
private long fileEndOffset;
private long textEndOffset;
/**
* Create a new instance.
*
* @param styledString
* The styled string of the instance, may be empty not
* <code>null</code>.
*/
public HexEditorContentOutlineTreeObject(StyledString styledString) {
if (styledString == null) {
throw new IllegalArgumentException("Parameter 'styledString' must not be null.");
/**
* Create a new instance.
*
* @param styledString The styled string of the instance, may be empty not
* <code>null</code>.
*/
public HexEditorContentOutlineTreeObject(StyledString styledString) {
if (styledString == 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.
*
* @return The styled string, not <code>null</code>.
*/
public StyledString getStyledString() {
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 + ".");
/**
* Gets the styled string of the object.
*
* @return The styled string, not <code>null</code>.
*/
public StyledString getStyledString() {
return styledString;
}
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 + ".");
/**
* 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.
*
* @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;
}
}

View File

@ -28,10 +28,10 @@ import com.wudsn.ide.base.editor.CommonOpenEditorCommandHandler;
*/
public final class HexEditorOpenCommandHandler extends CommonOpenEditorCommandHandler {
/**
* Creation is public. Called by extension "org.eclipse.ui.popupMenus".
*/
public HexEditorOpenCommandHandler() {
super(HexEditor.ID);
}
/**
* Creation is public. Called by extension "org.eclipse.ui.popupMenus".
*/
public HexEditorOpenCommandHandler() {
super(HexEditor.ID);
}
}

View File

@ -28,169 +28,150 @@ import com.wudsn.ide.base.common.TextUtility;
public abstract class HexEditorParser {
private HexEditorParserComponent owner;
protected Styler offsetStyler;
protected Styler addressStyler;
protected FileContent fileContent;
private HexEditorParserComponent owner;
protected Styler offsetStyler;
protected Styler addressStyler;
protected FileContent fileContent;
/**
* Creation is protected.
*/
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);
/**
* Creation is protected.
*/
protected HexEditorParser() {
}
if (StringUtility.isSpecified(blockHeaderParameterText)) {
styledString.append(" : ");
styledString.append(hexText, addressStyler);
styledString.append(" : ");
styledString.append(decimalText);
/**
* 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();
}
contentBuilder.append(blockHeaderText, offsetStyler);
if (blockHeaderNumber >= 0) {
contentBuilder.append(" ");
contentBuilder.append(blockHeaderNumberText, offsetStyler);
/**
* 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);
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.
*
* @param contentBuilder
* The content builder, not <code>null</code>.
* @param headerStyledString
* The style string for the block header in the outline, not
* <code>null</code>.
* @param offset
* The start offset, a non-negative integer.
*
* @return The tree object representing the block.
*/
protected final HexEditorContentOutlineTreeObject printBlockHeader(StyledString contentBuilder,
StyledString headerStyledString, long offset) {
return owner.printBlockHeader(contentBuilder, headerStyledString, offset);
}
/**
* Adds a block to the outline.
*
* @param contentBuilder The content builder, not <code>null</code>.
* @param headerStyledString The style string for the block header in the
* outline, not <code>null</code>.
* @param offset The start offset, a non-negative integer.
*
* @return The tree object representing the block.
*/
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
* of bytes.
*
* @param contentBuilder
* The content builder, not <code>null</code>.
* @param errorText
* The error text, not empty and not <code>null</code>.
* @param length
* The length of the last block, a non-negative integer.
* @param 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);
}
/**
* Prints the last block in case if contains an error like the wrong number of
* bytes.
*
* @param contentBuilder The content builder, not <code>null</code>.
* @param errorText The error text, not empty and not <code>null</code>.
* @param length The length of the last block, a non-negative integer.
* @param 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) {
owner.skipByteTextIndex(offset);
protected final void skipByteTextIndex(long offset) {
owner.skipByteTextIndex(offset);
}
}
protected final long printBytes(HexEditorContentOutlineTreeObject treeObject, StyledString contentBuilder,
long offset, long maxOffset, boolean withStartAddress, int startAddress) {
return owner.printBytes(treeObject, contentBuilder, offset, maxOffset, withStartAddress, startAddress);
protected final long printBytes(HexEditorContentOutlineTreeObject treeObject, StyledString contentBuilder,
long offset, long maxOffset, boolean withStartAddress, int startAddress) {
return owner.printBytes(treeObject, contentBuilder, offset, maxOffset, withStartAddress, startAddress);
}
}
}

View File

@ -36,43 +36,43 @@ import com.wudsn.ide.base.common.TextUtility;
public final class HexEditorSaveSelectionAsCommandHandler extends HexEditorSelectionCommandHandler {
public static final class CommandIds {
public static final class 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());
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());
}
}
}
}
}

View File

@ -29,78 +29,75 @@ import org.eclipse.jface.viewers.ISelection;
*/
final class HexEditorSelection implements ISelection {
private long startOffset;
private long endOffset;
private byte[] bytes;
private long startOffset;
private long endOffset;
private byte[] bytes;
/**
* Creates a new selection.
*
* @param startOffset
* The start offset in the original array, a non-negative number.
* @param endOffset
* The end offset in the original array, a non-negative number
* greater or equal to the start offset.
* @param bytes
* The content of the selection, may be empty, not
* <code>null</code>.
*/
public HexEditorSelection(long startOffset, long endOffset, byte[] bytes) {
/**
* Creates a new selection.
*
* @param startOffset The start offset in the original array, a non-negative
* number.
* @param endOffset The end offset in the original array, a non-negative
* number greater or equal to the start offset.
* @param bytes The content of the selection, may be empty, not
* <code>null</code>.
*/
public HexEditorSelection(long startOffset, long endOffset, byte[] bytes) {
if (startOffset < 0) {
throw new IllegalArgumentException("Parameter 'startOffset' must not be negative, specified value is "
+ startOffset + ".");
if (startOffset < 0) {
throw new IllegalArgumentException(
"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 "
+ startOffset + ", specified value is " + endOffset + ".");
@Override
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() {
return bytes.length == 0;
}
/**
* Gets the end offset in the original array.
*
* @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.
*
* @return The start offset in the original array, a non-negative number.
*
*/
public long getStartOffset() {
return startOffset;
}
/**
* Gets the content of the selection.
*
* @return The content of the selection, may be empty, not <code>null</code> .
*/
public byte[] getBytes() {
return bytes;
}
/**
* Gets the end offset in the original array.
*
* @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";
}
@Override
public String toString() {
return "HexEditorSelection from " + startOffset + " to " + endOffset + ": " + bytes.length + " bytes";
}
}

View File

@ -35,43 +35,43 @@ import com.wudsn.ide.base.gui.MessageManager;
*/
public abstract class HexEditorSelectionCommandHandler extends AbstractHandler {
protected ExecutionEvent event;
protected String commandId;
protected HexEditorSelection hexEditorSelection;
protected HexEditor hexEditor;
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();
protected ExecutionEvent event;
protected String commandId;
protected HexEditorSelection hexEditorSelection;
protected HexEditor hexEditor;
protected MessageManager messageManager;
/**
* 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;
}

View File

@ -11,86 +11,86 @@ import org.eclipse.swt.dnd.TransferData;
public final class HexEditorSelectionTransfer extends ByteArrayTransfer {
private static final String HEX_EDITOR_SELECTION_NAME = "HexEditorSelection";
private static final int HEX_EDITOR_SELECTION_ID = registerType(HEX_EDITOR_SELECTION_NAME);
private static HexEditorSelectionTransfer instance = new HexEditorSelectionTransfer();
private static final String HEX_EDITOR_SELECTION_NAME = "HexEditorSelection";
private static final int HEX_EDITOR_SELECTION_ID = registerType(HEX_EDITOR_SELECTION_NAME);
private static HexEditorSelectionTransfer instance = new 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) {
}
private HexEditorSelectionTransfer() {
}
}
@Override
public Object nativeToJava(TransferData transferData) {
public static HexEditorSelectionTransfer getInstance() {
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 (buffer == null) {
return null;
}
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);
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);
byte[] buffer = out.toByteArray();
writeOut.close();
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
protected String[] getTypeNames() {
return new String[] { HEX_EDITOR_SELECTION_NAME };
}
if (isSupportedType(transferData)) {
@Override
protected int[] getTypeIds() {
return new int[] { HEX_EDITOR_SELECTION_ID };
}
byte[] buffer = (byte[]) super.nativeToJava(transferData);
if (buffer == null) {
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 };
}
}

View File

@ -9,54 +9,54 @@ import com.wudsn.ide.base.common.AbstractIDEPlugin;
*/
public class HexPlugin extends AbstractIDEPlugin {
// The plug-in ID
public static final String ID = "com.wudsn.ide.hex"; //$NON-NLS-1$
// The plug-in ID
public static final String ID = "com.wudsn.ide.hex"; //$NON-NLS-1$
// The shared instance
private static HexPlugin plugin;
// The shared instance
private static HexPlugin plugin;
/**
* The constructor
*/
public HexPlugin() {
}
/**
* {@inheritDoc}
*/
@Override
protected String getPluginId() {
return ID;
}
/**
* {@inheritDoc}
*/
@Override
public void start(BundleContext context) throws Exception {
super.start(context);
plugin = this;
}
/**
* {@inheritDoc}
*/
@Override
public void stop(BundleContext context) throws Exception {
plugin = null;
super.stop(context);
}
/**
* Gets the shared plugin instance
*
* @return The plug-in, not <code>null</code>.
*/
public static HexPlugin getInstance() {
if (plugin == null) {
throw new IllegalStateException("Plugin not initialized or already stopped");
/**
* The constructor
*/
public HexPlugin() {
}
/**
* {@inheritDoc}
*/
@Override
protected String getPluginId() {
return ID;
}
/**
* {@inheritDoc}
*/
@Override
public void start(BundleContext context) throws Exception {
super.start(context);
plugin = this;
}
/**
* {@inheritDoc}
*/
@Override
public void stop(BundleContext context) throws Exception {
plugin = null;
super.stop(context);
}
/**
* Gets the shared plugin instance
*
* @return The plug-in, not <code>null</code>.
*/
public static HexPlugin getInstance() {
if (plugin == null) {
throw new IllegalStateException("Plugin not initialized or already stopped");
}
return plugin;
}
return plugin;
}
}

View File

@ -28,65 +28,65 @@ import org.eclipse.osgi.util.NLS;
*/
public final class Texts extends NLS {
/**
* Hex editor
*/
public static String HEX_EDITOR_FILE_SIZE;
/**
* Hex editor
*/
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_PARAMETERS;
public static String HEX_EDITOR_ATARI_COM_BLOCK_ERROR;
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_ERROR;
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_PARAMETERS;
public static String HEX_EDITOR_ATARI_SECTOR_ERROR;
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_PARAMETERS;
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_UPDATE_RELOC_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_SYMBOL_HEADER;
public static String HEX_EDITOR_ATARI_MADS_BLOCK_ERROR;
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_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_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_PARAMETERS;
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_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_NON_RELOC_BLOCK_HEADER;
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_UPDATE_RELOC_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_BLOCK_ERROR;
public static String HEX_EDITOR_C64_PRG_HEADER;
public static String HEX_EDITOR_C64_PRG_HEADER_PARAMETERS;
public static String HEX_EDITOR_C64_PRG_ERROR;
public static String HEX_EDITOR_C64_PRG_HEADER;
public static String HEX_EDITOR_C64_PRG_HEADER_PARAMETERS;
public static String HEX_EDITOR_C64_PRG_ERROR;
public static String HEX_EDITOR_IFF_CHUNK;
public static String HEX_EDITOR_IFF_FORM_CHUNK;
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_IFF_CHUNK;
public static String HEX_EDITOR_IFF_FORM_CHUNK;
public static String HEX_EDITOR_IFF_FILE_ERROR;
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;
/**
* 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;
public static String HEX_EDITOR_SAVE_SELECTION_AS_DIALOG_TITLE;
/**
* Initializes the constants.
*/
static {
NLS.initializeMessages(Texts.class.getName(), Texts.class);
}
/**
* 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.
*/
static {
NLS.initializeMessages(Texts.class.getName(), Texts.class);
}
}

View File

@ -23,14 +23,14 @@ import org.eclipse.jface.viewers.StyledString;
public final class AtariCOMParser extends AtariParser {
@Override
public boolean parse(StyledString contentBuilder) {
if (contentBuilder == null) {
throw new IllegalArgumentException("Parameter 'contentBuilder' must not be null.");
@Override
public boolean parse(StyledString contentBuilder) {
if (contentBuilder == 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);
}
}

View File

@ -22,27 +22,27 @@ package com.wudsn.ide.hex.parser;
import org.eclipse.jface.viewers.StyledString;
public final class AtariDiskImageKFileParser extends AtariDiskImageParser {
// 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;
// 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;
@Override
public boolean parse(StyledString contentBuilder) {
@Override
public boolean parse(StyledString contentBuilder) {
if (contentBuilder == null) {
throw new IllegalArgumentException("Parameter 'contentBuilder' must not be null.");
if (contentBuilder == 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;
}
}

View File

@ -26,65 +26,65 @@ import com.wudsn.ide.hex.HexEditorContentOutlineTreeObject;
public class AtariDiskImageParser extends AtariParser {
@Override
public boolean parse(StyledString contentBuilder) {
@Override
public boolean parse(StyledString contentBuilder) {
if (contentBuilder == null) {
throw new IllegalArgumentException("Parameter 'contentBuilder' must not be null.");
}
if (contentBuilder == null) {
throw new IllegalArgumentException("Parameter 'contentBuilder' must not be null.");
}
boolean error = false;
int length = fileContent.getLength();
long offset = 0;
boolean error = false;
int length = fileContent.getLength();
long offset = 0;
HexEditorContentOutlineTreeObject treeObject;
treeObject = printBlockHeader(contentBuilder, Texts.HEX_EDITOR_ATARI_DISK_IMAGE_HEADER, -1, "", offset, offset,
offset + 15);
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);
HexEditorContentOutlineTreeObject treeObject;
treeObject = printBlockHeader(contentBuilder, Texts.HEX_EDITOR_ATARI_DISK_IMAGE_HEADER, -1, "", offset, offset,
offset + 15);
offset = printBytes(treeObject, contentBuilder, offset, offset + 15, true, 0);
contentBuilder.append("\n");
if (offset >= length) {
blockMode = false;
} else if (length - offset < sectorSize) {
error = true;
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;
}
sectorCount++;
if (sectorCount > 3) {
sectorSize = mainSectorSize;
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");
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());
}
}
} catch (RuntimeException ex) {
contentBuilder.append(ex.toString());
if (error) {
printBlockWithError(contentBuilder, Texts.HEX_EDITOR_ATARI_SECTOR_ERROR, length, offset);
}
return error;
}
if (error) {
printBlockWithError(contentBuilder, Texts.HEX_EDITOR_ATARI_SECTOR_ERROR, length, offset);
}
return error;
}
}

View File

@ -35,188 +35,188 @@ import com.wudsn.ide.hex.HexEditorParser;
*/
public class AtariMADSParser extends HexEditorParser {
public static final int COM_HEADER = 0xffff;
public static final int RELOC_HEADER = 0x524d;
public static final int UPDATE_RELOC_HEADER = 0xffef;
public static final int UPDATE_SYMBOLS_HEADER = 0xffee;
public static final int DEFINE_SYMBOLS_HEADER = 0xffed;
public static final int COM_HEADER = 0xffff;
public static final int RELOC_HEADER = 0x524d;
public static final int UPDATE_RELOC_HEADER = 0xffef;
public static final int UPDATE_SYMBOLS_HEADER = 0xffee;
public static final int DEFINE_SYMBOLS_HEADER = 0xffed;
@Override
public boolean parse(StyledString contentBuilder) {
if (contentBuilder == 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");
@Override
public boolean parse(StyledString contentBuilder) {
if (contentBuilder == null) {
throw new IllegalArgumentException("Parameter 'contentBuilder' must not be null.");
}
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,
HexUtility.getLongValueHexString(startAddress, 4),
HexUtility.getLongValueHexString(endAddress, 4),
HexUtility.getByteValueHexString(config));
boolean error;
long offset = 0;
treeObject = printHeader(contentBuilder, offset, headerText);
offset = printBytes(treeObject, contentBuilder, offset, offset + 15, true, 0);
// Skip offset bytes in lookup array.
skipByteTextIndex(offset);
long blockEnd = offset + endAddress - startAddress;
HexEditorContentOutlineTreeObject treeObject;
int fileContentLength = fileContent.getLength();
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;
}
error = (fileContentLength - offset) < 17;
boolean first = true;
boolean more = true;
try {
while (more && !error) {
if (!first) {
contentBuilder.append("\n");
}
break;
case 'A':
break;
case 'S':
break;
}
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);
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);
String headerText = TextUtility.format(Texts.HEX_EDITOR_ATARI_MADS_RELOC_BLOCK_HEADER,
HexUtility.getLongValueHexString(startAddress, 4),
HexUtility.getLongValueHexString(endAddress, 4),
HexUtility.getByteValueHexString(config));
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;
}
}
}
} else {
} catch (RuntimeException ex) {
contentBuilder.append(ex.toString());
error = true;
}
}
}
} catch (RuntimeException ex) {
contentBuilder.append(ex.toString());
error = true;
if (error) {
printBlockWithError(contentBuilder, Texts.HEX_EDITOR_ATARI_MADS_BLOCK_ERROR, fileContentLength, offset);
}
return error;
}
if (error) {
printBlockWithError(contentBuilder, Texts.HEX_EDITOR_ATARI_MADS_BLOCK_ERROR, fileContentLength, offset);
private HexEditorContentOutlineTreeObject printHeader(StyledString contentBuilder, long offset, String headerText) {
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) {
HexEditorContentOutlineTreeObject treeObject;
StyledString headerStyledString = new StyledString(headerText, offsetStyler);
contentBuilder.append(headerStyledString).append("\n");
treeObject = printBlockHeader(contentBuilder, headerStyledString, offset);
return treeObject;
}
private HexEditorContentOutlineTreeObject printTypedHeader(StyledString contentBuilder, long offset, String text,
int type, int dataLength) {
HexEditorContentOutlineTreeObject treeObject;
String headerText = TextUtility.format(text, String.valueOf((char) type),
HexUtility.getLongValueHexString(dataLength, 4));
treeObject = printHeader(contentBuilder, offset, headerText);
return treeObject;
}
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));
private HexEditorContentOutlineTreeObject printTypedHeader(StyledString contentBuilder, long offset, String text,
int type, int dataLength) {
HexEditorContentOutlineTreeObject treeObject;
String headerText = TextUtility.format(text, String.valueOf((char) type),
HexUtility.getLongValueHexString(dataLength, 4));
treeObject = printHeader(contentBuilder, offset, headerText);
return treeObject;
}
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();
}
return buffer.toString();
}
}

View File

@ -27,101 +27,101 @@ import com.wudsn.ide.hex.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) {
if (contentBuilder == 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;
}
}
protected final boolean parseAtariCOMFile(StyledString contentBuilder, long offset, int fileContentLength) {
if (contentBuilder == null) {
throw new IllegalArgumentException("Parameter 'contentBuilder' must not be null.");
}
} catch (RuntimeException ex) {
contentBuilder.append(ex.toString());
error = true;
}
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) {
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;
}
}

View File

@ -26,26 +26,26 @@ import com.wudsn.ide.hex.HexEditorContentOutlineTreeObject;
public final class AtariSAPParser extends AtariParser {
@Override
public boolean parse(StyledString contentBuilder) {
if (contentBuilder == null) {
throw new IllegalArgumentException("Parameter 'contentBuilder' must not be null.");
}
long offset = 0;
int fileContentLenght = fileContent.getLength();
int maxOffset = fileContentLenght - 2;
while (offset < maxOffset && fileContent.getByte(offset) != 0xff && fileContent.getByte(offset) != 0xff) {
offset++;
}
if (offset == maxOffset) {
return false;
}
HexEditorContentOutlineTreeObject treeObject = printBlockHeader(contentBuilder,
Texts.HEX_EDITOR_ATARI_SAP_FILE_HEADER, -1, "", 0, 0, 0);
printBytes(treeObject, contentBuilder, 0, offset - 1, false, 0);
contentBuilder.append("\n");
@Override
public boolean parse(StyledString contentBuilder) {
if (contentBuilder == null) {
throw new IllegalArgumentException("Parameter 'contentBuilder' must not be null.");
}
long offset = 0;
int fileContentLenght = fileContent.getLength();
int maxOffset = fileContentLenght - 2;
while (offset < maxOffset && fileContent.getByte(offset) != 0xff && fileContent.getByte(offset) != 0xff) {
offset++;
}
if (offset == maxOffset) {
return false;
}
HexEditorContentOutlineTreeObject treeObject = printBlockHeader(contentBuilder,
Texts.HEX_EDITOR_ATARI_SAP_FILE_HEADER, -1, "", 0, 0, 0);
printBytes(treeObject, contentBuilder, 0, offset - 1, false, 0);
contentBuilder.append("\n");
return parseAtariCOMFile(contentBuilder, offset, fileContentLenght);
}
return parseAtariCOMFile(contentBuilder, offset, fileContentLenght);
}
}

View File

@ -30,165 +30,164 @@ import com.wudsn.ide.hex.Texts;
public class AtariSDXParser extends HexEditorParser {
public static final int NON_RELOC_HEADER = 0xfffa;
public static final int RELOC_HEADER = 0xfffe;
public static final int UPDATE_RELOC_HEADER = 0xfffd;
public static final int UPDATE_SYMBOLS_HEADER = 0xfffb;
public static final int DEFINE_SYMBOLS_HEADER = 0xfffc;
public static final int NON_RELOC_HEADER = 0xfffa;
public static final int RELOC_HEADER = 0xfffe;
public static final int UPDATE_RELOC_HEADER = 0xfffd;
public static final int UPDATE_SYMBOLS_HEADER = 0xfffb;
public static final int DEFINE_SYMBOLS_HEADER = 0xfffc;
@Override
public boolean parse(StyledString contentBuilder) {
if (contentBuilder == 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");
@Override
public boolean parse(StyledString contentBuilder) {
if (contentBuilder == null) {
throw new IllegalArgumentException("Parameter 'contentBuilder' must not be null.");
}
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,
-1, Texts.HEX_EDITOR_ATARI_SDX_NON_RELOC_BLOCK_HEADER_PARAMETERS, offset, startAddress,
endAddress);
offset = printBytes(treeObject, contentBuilder, offset, offset + 5, true, 0);
boolean error;
long offset = 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) {
int blockNumber = fileContent.getByte(offset + 2);
int blockId = fileContent.getByte(offset + 3);
int blockOffset = fileContent.getWord(offset + 4);
int blockLength = fileContent.getWord(offset + 6);
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);
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);
treeObject = printBlockHeader(contentBuilder, Texts.HEX_EDITOR_ATARI_SDX_NON_RELOC_BLOCK_HEADER,
-1, Texts.HEX_EDITOR_ATARI_SDX_NON_RELOC_BLOCK_HEADER_PARAMETERS, offset, startAddress,
endAddress);
offset = printBytes(treeObject, contentBuilder, offset, offset + 5, true, 0);
long blockEnd = offset + blockLength - 1;
long blockEnd = offset + endAddress - startAddress;
// Print bytes only of the block is not marked as EMPTY
if ((blockId & 0x80) != 0x80) {
offset = printBytes(treeObject, contentBuilder, offset, blockEnd, true, blockOffset);
offset = printBytes(treeObject, contentBuilder, offset, blockEnd, true, startAddress);
} 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) {
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 {
} catch (RuntimeException ex) {
contentBuilder.append(ex.toString());
error = true;
}
}
}
} catch (RuntimeException ex) {
contentBuilder.append(ex.toString());
error = true;
if (error) {
printBlockWithError(contentBuilder, Texts.HEX_EDITOR_ATARI_SDX_BLOCK_ERROR, fileContentLength, offset);
}
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;
}
/**
* 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;
}
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();
}
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();
}
}

View File

@ -26,14 +26,14 @@ import com.wudsn.ide.hex.HexEditorParser;
public class BinaryParser extends HexEditorParser {
@Override
public boolean parse(StyledString contentBuilder) {
if (contentBuilder == null) {
throw new IllegalArgumentException("Parameter 'contentBuilder' must not be null.");
@Override
public boolean parse(StyledString contentBuilder) {
if (contentBuilder == 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;
}
}

View File

@ -27,37 +27,37 @@ import com.wudsn.ide.hex.HexEditorParser;
public class C64PRGParser extends HexEditorParser {
@Override
public boolean parse(StyledString contentBuilder) {
if (contentBuilder == null) {
throw new IllegalArgumentException("Parameter 'contentBuilder' must not be null.");
@Override
public boolean parse(StyledString contentBuilder) {
if (contentBuilder == 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;
}
}

View File

@ -30,92 +30,92 @@ import com.wudsn.ide.hex.Texts;
public final class IFFParser extends HexEditorParser {
@Override
public final boolean parse(StyledString contentBuilder) {
if (contentBuilder == 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));
@Override
public final boolean parse(StyledString contentBuilder) {
if (contentBuilder == 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) {
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);
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));
}
if (hasInnerChunks) {
contentBuilder.append("\n");
if (!error) {
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);
offset += chunkLength;
} else {
offset = printBytes(treeObject, contentBuilder, offset, offset + chunkLength - 1, false, 0);
}
contentBuilder.append("\n");
if (hasInnerChunks) {
contentBuilder.append("\n");
// Skip padding byte
if ((offset & 0x1) == 1) {
offset++;
}
parse(contentBuilder, offset, fileContentLength, treeObject);
offset += chunkLength;
} 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) {
char[] id = new char[4];
id[0] = (char) fileContent.getByte(offset);
id[1] = (char) fileContent.getByte(offset + 1);
id[2] = (char) fileContent.getByte(offset + 2);
id[3] = (char) fileContent.getByte(offset + 3);
return String.copyValueOf(id);
}
private String getChunkName(long offset) {
char[] id = new char[4];
id[0] = (char) fileContent.getByte(offset);
id[1] = (char) fileContent.getByte(offset + 1);
id[2] = (char) fileContent.getByte(offset + 2);
id[3] = (char) fileContent.getByte(offset + 3);
return String.copyValueOf(id);
}
}