📄 rcmainframe.java
字号:
package net.softgems.resourceparser;
import java.io.*;
import java.util.ArrayList;
import net.softgems.resourceparser.main.*;
import net.softgems.resourceparser.preprocessor.*;
import net.softgems.resourceparser.xml.ResourceStatement;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.*;
import org.eclipse.swt.events.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.widgets.Text;
import org.jdom.*;
import org.jdom.output.*;
import antlr.TokenStreamRecognitionException;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.graphics.Font;
import antlr.collections.AST;
/**
* This code was generated using CloudGarden's Jigloo
* SWT/Swing GUI Builder, which is free for non-commercial
* use. If Jigloo is being used commercially (ie, by a
* for-profit company or business) then you should purchase
* a license - please visit www.cloudgarden.com for details.
*/
public class RCMainFrame extends org.eclipse.swt.widgets.Composite {
private Button browseOutputFolderButton;
private Text outputPathEdit;
private Label button1;
private Button browseIniFileButton;
private Text txtFileNameEdit;
private Button multipleFilesRadioButton;
private Button browseRCFileButton;
private Text rcFileNameEdit;
private Button singleFileRadioButton;
private Composite composite7;
private Button addIncludePathButton;
private Button addSymbolButton;
private String[] commandLine;
private Composite composite1;
private Composite composite2;
private Composite composite3;
private Composite composite4;
private Composite composite5;
private Composite composite6;
private ArrayList defines = new ArrayList();
private Group group1;
private List includePathList;
private ArrayList includes = new ArrayList();
private Label label2;
private Label label3;
private Label label4;
private Label label5;
private Label label6;
private Label label7;
private Button parseButton;
private Button removeIncludePathButton;
private Button removeSymbolButton;
private Shell shell;
private TabFolder tabFolder1;
private TabItem tabItem1;
private TabItem tabItem2;
private TabItem tabItem3;
private TableColumn tableColumn1;
private TableColumn tableColumn2;
protected TableCursor cursor;
protected int errorCount;
protected boolean isEditing;
protected List log;
protected Label parseLineLabel;
protected Tree parseTree;
protected int preProcessedLines;
protected Label preprocessLineLabel;
protected List processedIncludesList;
protected int processedLines;
protected Table symbolsTable;
protected int tokenCount;
/** Mapper to convert a parse event into a textual representation. */
protected String[] eventStrings = new String[] {
"(PANIC) ", "(Error) ", "(Warning) ", "(Information) "
};
public RCMainFrame(Composite parent, int style, String[] args) {
super(parent, style);
this.shell = (Shell) parent;
commandLine = args;
initGUI();
}
//------------------------------------------------------------------------------------------------
/**
* Converts the given file, which must be an rc file to XML.
*
* @param file The file to convert.
* @param writeIntermediate If <b>true</b> then the intermediate text that comes out from the
* preprocessing step is written in a separate file with extension *.rcX. Since this
* intermediate content is the base for the parser all error line numbers correspond to
* this file, not the original input.
* @param createVisualAST If <b>true</b> then the abstract syntax tree is loaded into a treeviewer
* for examination. This step is not needed for the conversion process.
* @param targetPath The path where to write the resulting XML file to. If this path is <b>null</b>
* then the XML file is written to the folder where the source file is located.
* @return <b>true</b> if no error/warning was reported, otherwise <b>false</b>.
* @throws Exception Thrown for various reasons (IO error, recognition error etc.).
*/
private boolean convertFile(String filename, boolean writeIntermediate, boolean createVisualAST,
String targetPath) throws Exception
{
boolean result = true;
File file = new File(filename);
logMessage("Parsing file: " + file.getCanonicalPath());
// Set the current user directory to be the folder that contains the current rc file.
// This is necessary to make inclusion of file with relative path possible.
String folder = file.getParent();
System.setProperty("user.dir", folder);
logMessage("Set working folder to " + folder);
// The translation of a resource file is done very similar to the phases described in MSDN:
// "C/C++ Preprocessor Reference" -> "Phases of Translation".
// Note: None of the steps described below is done on its own. It is rather a big chain
// driven by the parser, which reads tokens from the lexer, which reads characters from
// the preprocessor, which reads lines from the input converter, which reads raw bytes.
PreprocessorInputState inputState = new PreprocessorInputState();
// 1) Convert the input data into our internal representation (Unicode).
// Convert trigraph sequences and do line splicing in this process too.
// For conversion it is necessary to know in which character set the input is encoded.
// Standard C files are all ANSI (ISO-8859-1, Latin-1) encoded, but resource files may have
// any other encoding including Unicode, so it is important to specify the right encoding.
// However usually also resource files are ANSI encoded, hence this charset can be used as
// a good first guess. Resource files may contain a #pragma code_page directive to switch
// the current codepage.
InputConverter converter = new InputConverter(inputState, new FileInputStream(filename),
Preprocessor.DEFAULT_CHARSET);
// 2) Handle preprocessor directives.
// The preprocessor takes a list of include pathes and a list of predefined symbols.
// Output will be cleaned source code without any preprocessor stuff and without comments.
// Include files will directly be imported by the preprocessor.
Preprocessor preprocessor = new Preprocessor(converter, null, inputState, false);
for (int i = 0; i < includePathList.getItemCount(); i++)
preprocessor.addIncludePath(includePathList.getItem(i));
for (int i = 0; i < symbolsTable.getItemCount(); i++)
{
TableItem item = symbolsTable.getItem(i);
preprocessor.addMacro(item.getText(0) + ' ' + item.getText(1));
}
preprocessor.addPreprocessorEventListener(
new IParseEventListener()
{
public void handleEvent(int event, String message)
{
switch (event)
{
case IParseEventListener.NEW_LINE:
{
preProcessedLines++;
if (preProcessedLines % 5000 == 0)
{
preprocessLineLabel.setText(Integer.toString(preProcessedLines));
preprocessLineLabel.update();
}
break;
}
case IParseEventListener.INCLUDE_FILE:
processedIncludesList.add(message);
processedIncludesList.update();
break;
default:
log.add("[Preprocessor] " + eventStrings[event] + message);
log.update();
};
};
}
);
// 3) Tokenize the input and feed the parser.
inputState.pushState(preprocessor, file.getName(), file.getParent());
// Once the initial state is set we can add extra files we need to be parsed in advance.
// Using Winresrc.h as standard include will make sure everything else, which is usually
// included by the resource compiler is also included here.
preprocessor.includeFile("Winresrc.h");
RCLexer lexer = new RCLexer(inputState);
lexer.addLexerEventListener(
new IParseEventListener()
{
public void handleEvent(int event, String message)
{
switch (event)
{
case IParseEventListener.NEW_LINE:
{
processedLines++;
parseLineLabel.setText("" + processedLines);
parseLineLabel.update();
break;
}
default:
{
log.add("[Lexer] " + eventStrings[event] + message);
log.update();
}
};
};
}
);
// 4) Here comes the actual parsing. This step converts the rc source code into an
// abstract syntax tree (AST).
RCParserSharedInputState parserInputState = new RCParserSharedInputState();
parserInputState.setInput(lexer);
RCParser parser = new RCParser(parserInputState);
parser.setFilename(filename);
parser.addParserEventListener(
new IParseEventListener()
{
public void handleEvent(int event, String message)
{
log.add("[Parser] " + eventStrings[event] + message);
log.update();
};
}
);
// This call will actually start the parsing process.
parser.resource_definition();
if (preprocessor.hadErrors() || lexer.hadErrors() || parser.hadErrors())
result = false;
logMessage("Parsing finished.");
if (createVisualAST)
{
logMessage("Filling abstract syntax tree.");
fillParseTree(parser);
}
// Finally write out the XML data.
exportXML(parser, file, preprocessor.getMacroTable(), targetPath);
// Free unused objects in case there is a large bunch of files to convert.
System.gc();
return result;
}
//------------------------------------------------------------------------------------------------
/**
* Exports all parsed content to an XML file named like the input file but with xml extension.
*
* @param parser The parser containing the parsed data.
* @param sourceFile The input file (only need to create the target file name from).
* @param macroTable The macro class that allows to resolve expressions.
* @param targetPath The path where to write the resulting XML file to. If this path is <b>null</b>
* then the XML file is written to the folder where the source file is located.
*/
private void exportXML(RCParser parser, File sourceFile, MacroTable macroTable, String targetPath)
{
String filename;
try
{
filename = sourceFile.getName();
int index = filename.lastIndexOf('.');
if (index == -1)
filename += ".xml";
else
filename = filename.substring(0, index) + ".xml";
File targetFile;
if (targetPath == null)
{
targetPath = sourceFile.getParent();
}
if (!targetPath.endsWith("\\") && !targetPath.endsWith("/"))
targetPath += "/";
targetFile = new File(targetPath + filename);
if (targetFile.exists())
targetFile.delete();
if (targetFile.createNewFile())
{
logMessage("Exporting result to " + filename);
Document document = new Document();
Element rootElement = new Element("dialog-definition");
document.setRootElement(rootElement);
AST node = parser.getAST();
while (node != null)
{
ResourceStatement statement = new ResourceStatement(this, node);
statement.setMacroTable(macroTable);
statement.convert(rootElement);
node = node.getNextSibling();
}
// Let JDOM format the output and write the result to disc.
Format format = Format.getPrettyFormat();
XMLOutputter outputter = new XMLOutputter(format);
OutputStream stream = new FileOutputStream(targetFile);
outputter.output(document, stream);
stream.close();
}
else
{
logMessage("Could not create target file " + filename);
}
}
catch (IOException e)
{
logMessage("Error while creating output file " + sourceFile.getAbsolutePath());
}
}
//------------------------------------------------------------------------------------------------
private void fillParseTree(RCParser parser)
{
parseTree.removeAll();
AST root = parser.getAST();
while (root != null)
{
TreeItem item = new TreeItem(parseTree, SWT.NULL);
item.setText(root.getText() + " (" + parser.getTokenName(root.getType()) + ")");
fillParseTreeNode(parser, root, item);
root = root.getNextSibling();
}
}
//------------------------------------------------------------------------------------------------
private void fillParseTreeNode(RCParser parser, AST astNode, TreeItem treeNode)
{
AST run = astNode.getFirstChild();
while (run != null)
{
TreeItem item = new TreeItem(treeNode, SWT.NULL);
item.setText(run.getText() + " (" + parser.getTokenName(run.getType()) + ")");
fillParseTreeNode(parser, run, item);
run = run.getNextSibling();
}
}
//------------------------------------------------------------------------------------------------
/**
* Checks the java command line for include path and symbol specifications. We accept two entry
* types. One is
* -include=path
* and the other is
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -