mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-10 14:11:59 +00:00
parent
3ffbf09e52
commit
8216440278
@ -13,56 +13,51 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
// List function names and entry point addresses to a file
|
||||
// List function names and entry point addresses to a file in JSON format
|
||||
//@category Functions
|
||||
|
||||
import ghidra.app.plugin.core.script.Ingredient;
|
||||
import ghidra.app.plugin.core.script.IngredientDescription;
|
||||
import ghidra.app.script.GatherParamPanel;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
|
||||
import com.google.gson.*;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.*;
|
||||
|
||||
import java.io.*;
|
||||
public class ExportFunctionInfoScript extends GhidraScript {
|
||||
|
||||
public class ExportFunctionInfoScript extends GhidraScript implements Ingredient {
|
||||
private static final String NAME = "name";
|
||||
private static final String ENTRY = "entry";
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
IngredientDescription[] ingredients = getIngredientDescriptions();
|
||||
for (int i = 0; i < ingredients.length; i++) {
|
||||
state.addParameter(ingredients[i].getID(), ingredients[i].getLabel(),
|
||||
ingredients[i].getType(), ingredients[i].getDefaultValue());
|
||||
}
|
||||
if (!state.displayParameterGatherer("Script Options")) {
|
||||
return;
|
||||
}
|
||||
File outputNameFile = (File) state.getEnvironmentVar("FunctionNameOutputFile");
|
||||
PrintWriter pWriter = new PrintWriter(new FileOutputStream(outputNameFile));
|
||||
|
||||
Gson gson = new GsonBuilder().setPrettyPrinting().create();
|
||||
|
||||
File outputFile = askFile("Please Select Output File", "Choose");
|
||||
JsonWriter jsonWriter = new JsonWriter(new FileWriter(outputFile));
|
||||
jsonWriter.beginArray();
|
||||
|
||||
Listing listing = currentProgram.getListing();
|
||||
FunctionIterator iter = listing.getFunctions(true);
|
||||
while (iter.hasNext() && !monitor.isCancelled()) {
|
||||
Function f = iter.next();
|
||||
String fName = f.getName();
|
||||
|
||||
String name = f.getName();
|
||||
Address entry = f.getEntryPoint();
|
||||
if (entry == null) {
|
||||
pWriter.println("/* FUNCTION_NAME_ " + fName + " FUNCTION_ADDR_ " +
|
||||
"NO_ENTRY_POINT" + " */");
|
||||
println("WARNING: no entry point for " + fName);
|
||||
}
|
||||
else {
|
||||
pWriter.println("/* FUNCTION_NAME_ " + fName + " FUNCTION_ADDR_ " + entry + " */");
|
||||
}
|
||||
|
||||
JsonObject json = new JsonObject();
|
||||
json.addProperty(NAME, name);
|
||||
json.addProperty(ENTRY, entry.toString());
|
||||
|
||||
gson.toJson(json, jsonWriter);
|
||||
}
|
||||
pWriter.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IngredientDescription[] getIngredientDescriptions() {
|
||||
IngredientDescription[] retVal =
|
||||
new IngredientDescription[] { new IngredientDescription("FunctionNameOutputFile",
|
||||
"Output Function Name File", GatherParamPanel.FILE, "") };
|
||||
return retVal;
|
||||
}
|
||||
jsonWriter.endArray();
|
||||
jsonWriter.close();
|
||||
|
||||
println("Wrote functions to " + outputFile);
|
||||
}
|
||||
}
|
||||
|
@ -1,153 +0,0 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//searches for pre-defined patterns and free space in code images
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import ghidra.app.cmd.label.AddLabelCmd;
|
||||
import ghidra.app.plugin.core.script.Ingredient;
|
||||
import ghidra.app.plugin.core.script.IngredientDescription;
|
||||
import ghidra.app.plugin.core.searchmem.RegExSearchData;
|
||||
import ghidra.app.script.GatherParamPanel;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.listing.CodeUnit;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
import ghidra.util.datastruct.ListAccumulator;
|
||||
import ghidra.util.search.memory.*;
|
||||
|
||||
public class FindEmptySpaceScript extends GhidraScript implements Ingredient {
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
IngredientDescription[] ingredients = getIngredientDescriptions();
|
||||
for (IngredientDescription ingredient : ingredients) {
|
||||
state.addParameter(ingredient.getID(), ingredient.getLabel(), ingredient.getType(),
|
||||
ingredient.getDefaultValue());
|
||||
}
|
||||
if (!state.displayParameterGatherer("Empty Area Finder Options")) {
|
||||
return;
|
||||
}
|
||||
|
||||
String emptyArea = (String) state.getEnvironmentVar("EmptyAreaData");
|
||||
Integer threshold = (Integer) state.getEnvironmentVar("Threshold");
|
||||
Integer align = (Integer) state.getEnvironmentVar("Alignment");
|
||||
String stem = (String) state.getEnvironmentVar("NameStem");
|
||||
|
||||
findEmptyAreas(emptyArea, threshold, align, stem);
|
||||
}
|
||||
|
||||
protected void findEmptyAreas(String emptyArea, Integer threshold, Integer align, String stem)
|
||||
throws Exception {
|
||||
String emptyAreaPlusThreshold = emptyArea + "{" + threshold + ",}";
|
||||
if (align < currentProgram.getLanguage().getInstructionAlignment()) {
|
||||
align = currentProgram.getLanguage().getInstructionAlignment();
|
||||
println(
|
||||
" Adjusting alignment to minimum instruction alignment for this processor; new alignment is " +
|
||||
align + " bytes");
|
||||
}
|
||||
else if ((align % currentProgram.getLanguage().getInstructionAlignment()) != 0) {
|
||||
align = align + (align % currentProgram.getLanguage().getInstructionAlignment());
|
||||
println(
|
||||
" Adjusting alignment to match processor instruction alignment; new alignment is " +
|
||||
align + " bytes");
|
||||
}
|
||||
|
||||
println(" Searching initialized memory for " + emptyAreaPlusThreshold +
|
||||
"; minimum size = " + threshold + " bytes ; alignment = " + align +
|
||||
" bytes; search limited to first 1000 matches");
|
||||
|
||||
AddressSetView addrs = currentProgram.getMemory().getLoadedAndInitializedAddressSet();
|
||||
|
||||
SearchInfo searchInfo = new SearchInfo(new RegExSearchData(emptyAreaPlusThreshold), 1000,
|
||||
false, true, align, true, null);
|
||||
RegExMemSearcherAlgorithm searcher =
|
||||
new RegExMemSearcherAlgorithm(searchInfo, addrs, currentProgram, true);
|
||||
|
||||
ListAccumulator<MemSearchResult> accumulator = new ListAccumulator<>();
|
||||
searcher.search(accumulator, monitor);
|
||||
List<MemSearchResult> results = accumulator.asList();
|
||||
List<Address> addresses =
|
||||
results.stream().map(r -> r.getAddress()).collect(Collectors.toList());
|
||||
|
||||
int numMatches = 0;
|
||||
long maxLen = 0;
|
||||
if (results.isEmpty()) {
|
||||
println(" FAILURE: Could not find any empty areas with regexp = " +
|
||||
emptyAreaPlusThreshold + "and alignment = " + align + " bytes");
|
||||
return;
|
||||
}
|
||||
|
||||
//put matches into an address set, thereby coalescing ranges
|
||||
AddressSet addrSet = new AddressSet();
|
||||
for (MemSearchResult result : results) {
|
||||
Address match = result.getAddress();
|
||||
int len = result.getLength();
|
||||
addrSet.addRange(match, match.addNoWrap(len));
|
||||
}
|
||||
|
||||
//iterate over the set items that matched
|
||||
for (AddressRange range : addrSet) {
|
||||
long len = range.getLength();
|
||||
addLabelAndExportSym(range.getMinAddress(), len, stem, "emptyArea", "size = " + len +
|
||||
" bytes (alignment = " + align + " bytes; min size = " + threshold + " bytes)");
|
||||
numMatches++;
|
||||
if (len > maxLen) {
|
||||
maxLen = len;
|
||||
}
|
||||
}
|
||||
|
||||
println(" Found " + numMatches +
|
||||
" empty areas meeting size and alignment requirements; maximum length found = " +
|
||||
maxLen + " bytes");
|
||||
|
||||
}
|
||||
|
||||
protected void addLabelAndExportSym(Address matchAddr, long len, String stem, String tag,
|
||||
String optComment) {
|
||||
String label = stem + "_" + matchAddr + "_" + len;
|
||||
label = label.replaceAll(":", "_");
|
||||
String comment = "{@exportsym " + tag + " " + optComment + "}";
|
||||
CodeUnit cd = currentProgram.getListing().getCodeUnitAt(matchAddr);
|
||||
if (cd == null) {
|
||||
return;
|
||||
}
|
||||
AddLabelCmd lcmd = new AddLabelCmd(matchAddr, label, false, SourceType.USER_DEFINED);
|
||||
lcmd.applyTo(currentProgram);
|
||||
String commentThere = cd.getComment(CodeUnit.EOL_COMMENT);
|
||||
if (commentThere != null) {
|
||||
comment = commentThere + "\n" + comment;
|
||||
}
|
||||
cd.setComment(CodeUnit.EOL_COMMENT, comment);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IngredientDescription[] getIngredientDescriptions() {
|
||||
|
||||
IngredientDescription[] retVal = new IngredientDescription[] {
|
||||
new IngredientDescription("EmptyAreaData", "Regular Expression Data Pattern",
|
||||
GatherParamPanel.STRING, "\\xff"),
|
||||
new IngredientDescription("Threshold", "Minimum Size (decimal bytes)",
|
||||
GatherParamPanel.INTEGER, ""),
|
||||
new IngredientDescription("Alignment", "Alignment (decimal bytes)",
|
||||
GatherParamPanel.INTEGER, ""),
|
||||
new IngredientDescription("NameStem", "Optional Label Stem", GatherParamPanel.STRING,
|
||||
"EMPTY") };
|
||||
return retVal;
|
||||
}
|
||||
|
||||
}
|
@ -1,97 +0,0 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//Places header structure on overlay segments
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import ghidra.app.plugin.core.script.Ingredient;
|
||||
import ghidra.app.plugin.core.script.IngredientDescription;
|
||||
import ghidra.app.script.GatherParamPanel;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.FileDataTypeManager;
|
||||
import ghidra.program.model.util.CodeUnitInsertionException;
|
||||
|
||||
public class OverlayHeadersScript extends GhidraScript implements Ingredient {
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
// Get our configuration info and save for other scripts to use
|
||||
IngredientDescription[] ingredients = getIngredientDescriptions();
|
||||
for (IngredientDescription ingredient : ingredients) {
|
||||
state.addParameter(ingredient.getID(), ingredient.getLabel(), ingredient.getType(),
|
||||
ingredient.getDefaultValue());
|
||||
}
|
||||
if (!state.displayParameterGatherer("Script Options")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get our parameters for use here
|
||||
String overlayName = (String) state.getEnvironmentVar("OverlayName");
|
||||
File dataTypeArchive = (File) state.getEnvironmentVar("OverlayHeaderArchive");
|
||||
String dataTypeName = (String) state.getEnvironmentVar("OverlayHeaderName"); // must include datatype category
|
||||
|
||||
// Create our history logger
|
||||
Address histAddr = currentProgram.getMemory().getMinAddress();
|
||||
String tmpString = "\nScript: OverlayHeaders()\n";
|
||||
tmpString = tmpString + " Add " + dataTypeName + " structure\n from " +
|
||||
dataTypeArchive.toString();
|
||||
|
||||
// Get the datatype that we want to place on the overlays
|
||||
FileDataTypeManager dataTypeFileManager = openDataTypeArchive(dataTypeArchive, true);
|
||||
DataType dataType = dataTypeFileManager.getDataType(dataTypeName);
|
||||
dataTypeFileManager.close();
|
||||
if (dataType == null) {
|
||||
println("Can't find data type " + dataTypeName + " in " + dataTypeArchive.toString());
|
||||
throw new Exception(
|
||||
"Can't find data type " + dataTypeName + "\n in " + dataTypeArchive.toString());
|
||||
}
|
||||
|
||||
// Now iterate over overlays the lay down structure
|
||||
AddressSetView searchSet = currentProgram.getMemory();
|
||||
AddressRangeIterator addressRanges = searchSet.getAddressRanges(true);
|
||||
monitor.initialize(searchSet.getNumAddresses());
|
||||
int progressCount = 0;
|
||||
while (addressRanges.hasNext() && !monitor.isCancelled()) {
|
||||
AddressRange range = addressRanges.next();
|
||||
Address startAddr = range.getMinAddress();
|
||||
String rangeName = startAddr.toString();
|
||||
if (rangeName.startsWith(overlayName)) {
|
||||
try {
|
||||
createData(startAddr, dataType);
|
||||
}
|
||||
catch (CodeUnitInsertionException ex) {
|
||||
println("Error creating data type: " + ex);
|
||||
}
|
||||
}
|
||||
progressCount += range.getLength();
|
||||
monitor.setProgress(progressCount);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IngredientDescription[] getIngredientDescriptions() {
|
||||
IngredientDescription[] retVal = new IngredientDescription[] {
|
||||
new IngredientDescription("OverlayName", "Overlay Name", GatherParamPanel.STRING, "ov"),
|
||||
new IngredientDescription("OverlayHeaderArchive", "Overlay Header Archive",
|
||||
GatherParamPanel.FILE, ""),
|
||||
new IngredientDescription("OverlayHeaderName", "Overlay Header Name",
|
||||
GatherParamPanel.STRING, "/overlay_header") };
|
||||
return retVal;
|
||||
}
|
||||
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.plugin.core.script;
|
||||
|
||||
public interface Ingredient {
|
||||
IngredientDescription [] getIngredientDescriptions();
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.plugin.core.script;
|
||||
|
||||
public class IngredientDescription {
|
||||
private boolean visited;
|
||||
private String id;
|
||||
private String label;
|
||||
private int type;
|
||||
private Object defaultValue;
|
||||
|
||||
public IngredientDescription(String id, String label, int type, Object defaultValue) {
|
||||
this.id = id;
|
||||
this.label = label;
|
||||
this.type = type;
|
||||
this.defaultValue = defaultValue;
|
||||
visited = false;
|
||||
}
|
||||
|
||||
public boolean wasVisited() {
|
||||
return visited;
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
public String getID() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public Object getDefaultValue() {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,156 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.plugin.core.script;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
|
||||
import docking.widgets.filechooser.GhidraFileChooser;
|
||||
import generic.json.Json;
|
||||
import ghidra.framework.Application;
|
||||
import ghidra.program.model.listing.Function;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.test.*;
|
||||
|
||||
/**
|
||||
* Tests the {@code ExportFunctionInfoScript}, which writes Ghidra function object info in JSON
|
||||
* form for the entire program
|
||||
*/
|
||||
public class ExportFunctionInfoScriptTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
|
||||
private TestEnv env;
|
||||
private File script;
|
||||
|
||||
private Program program;
|
||||
private Function f1;
|
||||
private Function f2;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
||||
program = buildProgram();
|
||||
|
||||
env = new TestEnv();
|
||||
env.launchDefaultTool(program);
|
||||
|
||||
String scriptPath = "ghidra_scripts/ExportFunctionInfoScript.java";
|
||||
script = Application.getModuleFile("Base", scriptPath).getFile(true);
|
||||
}
|
||||
|
||||
private Program buildProgram() throws Exception {
|
||||
ToyProgramBuilder builder = new ToyProgramBuilder("Test", true, this);
|
||||
builder.createMemory(".text", "0x1001000", 0x40);
|
||||
|
||||
f1 = builder.createFunction("0x1001000");
|
||||
f2 = builder.createFunction("0x1001020");
|
||||
|
||||
return builder.getProgram();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testScript() throws Exception {
|
||||
|
||||
File outputFile = createTempFileForTest();
|
||||
|
||||
ScriptTaskListener listener = env.runScript(script);
|
||||
|
||||
chooseFile(outputFile);
|
||||
|
||||
waitForScriptCompletion(listener, 20000);
|
||||
|
||||
assertFunctionsInFile(outputFile, f1, f2);
|
||||
}
|
||||
|
||||
private void assertFunctionsInFile(File file, Function... functions)
|
||||
throws Exception {
|
||||
|
||||
List<Function> testFunctions = new ArrayList<>(List.of(f1, f2));
|
||||
|
||||
List<TestJsonFunction> jsons = readFromJson(file);
|
||||
|
||||
jsons.forEach(jsonFunction -> assertFunction(jsonFunction, testFunctions));
|
||||
assertThat("Not all program functions written to json file",
|
||||
testFunctions, is(empty()));
|
||||
}
|
||||
|
||||
private List<TestJsonFunction> readFromJson(File file) throws Exception {
|
||||
|
||||
List<TestJsonFunction> results = new ArrayList<>();
|
||||
Gson gson = new Gson();
|
||||
BufferedReader br = new BufferedReader(new FileReader(file));
|
||||
JsonReader reader = new JsonReader(br);
|
||||
|
||||
// the file is an array of objects
|
||||
reader.beginArray();
|
||||
while (reader.hasNext()) {
|
||||
TestJsonFunction function = gson.fromJson(reader, TestJsonFunction.class);
|
||||
results.add(function);
|
||||
}
|
||||
reader.endArray();
|
||||
reader.close();
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
private void assertFunction(TestJsonFunction function, List<Function> testFunctions) {
|
||||
Function match = null;
|
||||
for (Function expected : testFunctions) {
|
||||
if (function.matches(expected)) {
|
||||
match = expected;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assertNotNull("Unexpected function written to file", match);
|
||||
testFunctions.remove(match);
|
||||
}
|
||||
|
||||
private void chooseFile(File file) throws Exception {
|
||||
|
||||
GhidraFileChooser chooser = waitForDialogComponent(GhidraFileChooser.class);
|
||||
runSwing(() -> chooser.setSelectedFile(file));
|
||||
waitForUpdateOnChooser(chooser);
|
||||
pressButtonByText(chooser.getComponent(), "Choose");
|
||||
waitForSwing();
|
||||
}
|
||||
|
||||
private class TestJsonFunction {
|
||||
private String name;
|
||||
private String entry;
|
||||
|
||||
boolean matches(Function expected) {
|
||||
return name.equals(expected.getName()) &&
|
||||
entry.equals(expected.getEntryPoint().toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
// this is only for debug; not required
|
||||
return Json.toString(this);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//Decompile an entire program
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.app.plugin.core.script.Ingredient;
|
||||
import ghidra.app.plugin.core.script.IngredientDescription;
|
||||
import ghidra.app.script.GatherParamPanel;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.app.util.Option;
|
||||
import ghidra.app.util.exporter.CppExporter;
|
||||
|
||||
public class Decompile extends GhidraScript implements Ingredient {
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
IngredientDescription[] ingredients = getIngredientDescriptions();
|
||||
for (IngredientDescription ingredient : ingredients) {
|
||||
state.addParameter(ingredient.getID(), ingredient.getLabel(), ingredient.getType(),
|
||||
ingredient.getDefaultValue());
|
||||
}
|
||||
if (!state.displayParameterGatherer("Script Options")) {
|
||||
return;
|
||||
}
|
||||
File outputFile = (File) state.getEnvironmentVar("COutputFile");
|
||||
CppExporter cppExporter = new CppExporter();
|
||||
List<Option> options = new ArrayList<Option>();
|
||||
options.add(new Option(CppExporter.CREATE_HEADER_FILE, new Boolean(false)));
|
||||
cppExporter.setOptions(options);
|
||||
cppExporter.setExporterServiceProvider(state.getTool());
|
||||
cppExporter.export(outputFile, currentProgram, null, monitor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IngredientDescription[] getIngredientDescriptions() {
|
||||
IngredientDescription[] retVal = new IngredientDescription[] {
|
||||
new IngredientDescription("COutputFile", "Output C File", GatherParamPanel.FILE, "") };
|
||||
return retVal;
|
||||
}
|
||||
|
||||
}
|
@ -18,8 +18,8 @@ dependencies {
|
||||
compile "org.apache.commons:commons-collections4:4.1"
|
||||
compile "org.apache.commons:commons-lang3:3.9"
|
||||
compile "org.apache.commons:commons-text:1.6"
|
||||
|
||||
compile "commons-io:commons-io:2.6"
|
||||
compile "commons-io:commons-io:2.6"
|
||||
compile "com.google.code.gson:gson:2.8.6"
|
||||
|
||||
compileOnly "junit:junit:4.12"
|
||||
}
|
||||
|
@ -67,7 +67,6 @@ public class ExtensionUtils {
|
||||
public static String PROPERTIES_FILE_NAME = "extension.properties";
|
||||
public static String PROPERTIES_FILE_NAME_UNINSTALLED = "extension.properties.uninstalled";
|
||||
|
||||
|
||||
/**
|
||||
* Returns a set of all extensions known to Ghidra, represented by
|
||||
* {@link ExtensionDetails} objects. This will include all installed
|
||||
@ -76,7 +75,7 @@ public class ExtensionUtils {
|
||||
* Note that this method will only look in the known extension folder locations:
|
||||
* <ul>
|
||||
* <li>{@link ApplicationLayout#getExtensionArchiveDir}</li>
|
||||
* <li>{@link ApplicationLayout#getExtensionInstallationDir}</li>
|
||||
* <li>{@link ApplicationLayout#getExtensionInstallationDirs}</li>
|
||||
* </ul>
|
||||
* If users install extensions from other locations, the installed version of
|
||||
* the extension will be known, but the source archive location will not be retained.
|
||||
@ -123,13 +122,14 @@ public class ExtensionUtils {
|
||||
|
||||
/**
|
||||
* Returns all installed extensions. These are all the extensions found in
|
||||
* {@link ApplicationLayout#getExtensionInstallationDir}.
|
||||
* {@link ApplicationLayout#getExtensionInstallationDirs}.
|
||||
*
|
||||
* @param includeUninstalled if true, include extensions that have been marked for removal
|
||||
* @return set of installed extensions
|
||||
* @throws ExtensionException if the extension details cannot be retrieved
|
||||
*/
|
||||
public static Set<ExtensionDetails> getInstalledExtensions(boolean includeUninstalled) throws ExtensionException {
|
||||
public static Set<ExtensionDetails> getInstalledExtensions(boolean includeUninstalled)
|
||||
throws ExtensionException {
|
||||
|
||||
ApplicationLayout layout = Application.getApplicationLayout();
|
||||
|
||||
@ -165,7 +165,7 @@ public class ExtensionUtils {
|
||||
|
||||
return extensions;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns all archived extensions. These are all the extensions found in
|
||||
* {@link ApplicationLayout#getExtensionArchiveDir}.
|
||||
@ -215,7 +215,6 @@ public class ExtensionUtils {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return extensions;
|
||||
}
|
||||
@ -262,7 +261,7 @@ public class ExtensionUtils {
|
||||
e);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
return runInstallTask(rFile.getFile(false));
|
||||
}
|
||||
|
||||
@ -306,7 +305,7 @@ public class ExtensionUtils {
|
||||
}
|
||||
|
||||
ResourceFile file = new ResourceFile(extension.getArchivePath());
|
||||
|
||||
|
||||
// We need to handle a special case: If the user selects an extension to uninstall using
|
||||
// the GUI then tries to reinstall it without restarting Ghidra, the extension hasn't actually
|
||||
// been removed yet; just the manifest file has been renamed. In this case we don't need to go through
|
||||
@ -315,7 +314,7 @@ public class ExtensionUtils {
|
||||
if (installDir.exists()) {
|
||||
return restoreStateFiles(installDir);
|
||||
}
|
||||
|
||||
|
||||
if (install(file)) {
|
||||
extension.setInstallPath(installDir + File.separator + extension.getName());
|
||||
return true;
|
||||
@ -421,7 +420,7 @@ public class ExtensionUtils {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if the given file is a valid .zip archive.
|
||||
*
|
||||
@ -453,7 +452,7 @@ public class ExtensionUtils {
|
||||
throw new ExtensionException(e.getMessage(), ExtensionExceptionType.ZIP_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a list of files representing all the <code>extension.properties</code> files found
|
||||
* under a given directory. This will ONLY search the given directory and its immediate children.
|
||||
@ -517,8 +516,10 @@ public class ExtensionUtils {
|
||||
List<ResourceFile> tempFiles = Arrays.asList(rfiles);
|
||||
|
||||
Optional<ResourceFile> file =
|
||||
tempFiles.stream().filter(f -> f.getName().equals(PROPERTIES_FILE_NAME) ||
|
||||
f.getName().equals(PROPERTIES_FILE_NAME_UNINSTALLED)).findFirst();
|
||||
tempFiles.stream()
|
||||
.filter(f -> f.getName().equals(PROPERTIES_FILE_NAME) ||
|
||||
f.getName().equals(PROPERTIES_FILE_NAME_UNINSTALLED))
|
||||
.findFirst();
|
||||
if (file.isPresent()) {
|
||||
return file.get();
|
||||
}
|
||||
@ -547,14 +548,14 @@ public class ExtensionUtils {
|
||||
}
|
||||
else {
|
||||
copyToInstallationFolder(file, monitor);
|
||||
}
|
||||
}
|
||||
installed.set(true);
|
||||
}
|
||||
catch (ExtensionException e) {
|
||||
// If there's a problem copying files, check to see if there's already an extension
|
||||
// with this name in the install location that was slated for removal. If so, just
|
||||
// restore the extension properties and manifest files.
|
||||
if (e.getExceptionType() == ExtensionExceptionType.COPY_ERROR ||
|
||||
if (e.getExceptionType() == ExtensionExceptionType.COPY_ERROR ||
|
||||
e.getExceptionType() == ExtensionExceptionType.DUPLICATE_FILE_ERROR) {
|
||||
|
||||
File errorFile = e.getErrorFile();
|
||||
@ -563,14 +564,15 @@ public class ExtensionUtils {
|
||||
ResourceFile installDir = Application.getApplicationLayout()
|
||||
.getExtensionInstallationDirs()
|
||||
.get(0);
|
||||
|
||||
|
||||
// Get the root directory of the extension (strip off the install folder location and
|
||||
// grab the first part of the remaining path).
|
||||
//
|
||||
// eg: If errorFile is "/Users/johnG/Ghidra/Extensions/MyExtensionName/subdir1/problemFile"
|
||||
// And installDir is "/Users/johnG/Ghidra/Extensions"
|
||||
// We need to get "MyExtensionName"
|
||||
String extPath = errorFile.getAbsolutePath().substring(installDir.getAbsolutePath().length()+1);
|
||||
String extPath = errorFile.getAbsolutePath()
|
||||
.substring(installDir.getAbsolutePath().length() + 1);
|
||||
int slashIndex = extPath.indexOf(File.separator);
|
||||
String extName;
|
||||
if (slashIndex == -1) {
|
||||
@ -580,12 +582,13 @@ public class ExtensionUtils {
|
||||
extName = extPath.substring(0, extPath.indexOf(File.separator));
|
||||
}
|
||||
|
||||
boolean success = restoreStateFiles(new File(installDir.getAbsolutePath() + File.separator + extName));
|
||||
|
||||
boolean success = restoreStateFiles(
|
||||
new File(installDir.getAbsolutePath() + File.separator + extName));
|
||||
|
||||
installed.set(success);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (installed.get() == false) {
|
||||
Msg.showError(null, null, "Installation Error", "Error installing extension [" +
|
||||
file.getName() + "]." + " " + e.getExceptionType());
|
||||
@ -601,7 +604,7 @@ public class ExtensionUtils {
|
||||
|
||||
return installed.get();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Recursively searches a given directory for any module manifest and extension
|
||||
* properties files that are in an installed state and converts them to an uninstalled
|
||||
@ -617,7 +620,7 @@ public class ExtensionUtils {
|
||||
* @return false if any renames fail
|
||||
*/
|
||||
public static boolean removeStateFiles(ExtensionDetails extension) {
|
||||
|
||||
|
||||
// Sanity check
|
||||
if (extension == null || extension.getInstallPath() == null ||
|
||||
extension.getInstallPath().isEmpty()) {
|
||||
@ -625,23 +628,29 @@ public class ExtensionUtils {
|
||||
}
|
||||
|
||||
boolean success = true;
|
||||
|
||||
|
||||
List<File> manifestFiles = new ArrayList<>();
|
||||
ExtensionUtils.findFilesWithName(new File(extension.getInstallPath()), ModuleUtilities.MANIFEST_FILE_NAME, manifestFiles);
|
||||
ExtensionUtils.findFilesWithName(new File(extension.getInstallPath()),
|
||||
ModuleUtilities.MANIFEST_FILE_NAME, manifestFiles);
|
||||
for (File f : manifestFiles) {
|
||||
if (f.exists()) {
|
||||
File newFile = new File(f.getAbsolutePath().replace(ModuleUtilities.MANIFEST_FILE_NAME, ModuleUtilities.MANIFEST_FILE_NAME_UNINSTALLED) );
|
||||
File newFile = new File(f.getAbsolutePath()
|
||||
.replace(ModuleUtilities.MANIFEST_FILE_NAME,
|
||||
ModuleUtilities.MANIFEST_FILE_NAME_UNINSTALLED));
|
||||
if (!f.renameTo(newFile)) {
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
List<File> propFiles = new ArrayList<>();
|
||||
ExtensionUtils.findFilesWithName(new File(extension.getInstallPath()), ExtensionUtils.PROPERTIES_FILE_NAME, propFiles);
|
||||
ExtensionUtils.findFilesWithName(new File(extension.getInstallPath()),
|
||||
ExtensionUtils.PROPERTIES_FILE_NAME, propFiles);
|
||||
for (File f : propFiles) {
|
||||
if (f.exists()) {
|
||||
File newFile = new File(f.getAbsolutePath().replace(ExtensionUtils.PROPERTIES_FILE_NAME, ExtensionUtils.PROPERTIES_FILE_NAME_UNINSTALLED) );
|
||||
File newFile = new File(f.getAbsolutePath()
|
||||
.replace(ExtensionUtils.PROPERTIES_FILE_NAME,
|
||||
ExtensionUtils.PROPERTIES_FILE_NAME_UNINSTALLED));
|
||||
if (!f.renameTo(newFile)) {
|
||||
success = false;
|
||||
}
|
||||
@ -665,34 +674,37 @@ public class ExtensionUtils {
|
||||
* @return false if any renames fail
|
||||
*/
|
||||
public static boolean restoreStateFiles(File rootDir) {
|
||||
|
||||
|
||||
boolean success = true;
|
||||
|
||||
|
||||
List<File> manifestFiles = new ArrayList<>();
|
||||
findFilesWithName(rootDir, ModuleUtilities.MANIFEST_FILE_NAME_UNINSTALLED, manifestFiles);
|
||||
for (File f : manifestFiles) {
|
||||
if (f.exists()) {
|
||||
File newFile = new File(f.getAbsolutePath().replace(ModuleUtilities.MANIFEST_FILE_NAME_UNINSTALLED, ModuleUtilities.MANIFEST_FILE_NAME) );
|
||||
File newFile = new File(f.getAbsolutePath()
|
||||
.replace(ModuleUtilities.MANIFEST_FILE_NAME_UNINSTALLED,
|
||||
ModuleUtilities.MANIFEST_FILE_NAME));
|
||||
if (!f.renameTo(newFile)) {
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
List<File> propFiles = new ArrayList<>();
|
||||
findFilesWithName(rootDir, PROPERTIES_FILE_NAME_UNINSTALLED, propFiles);
|
||||
for (File f : propFiles) {
|
||||
if (f.exists()) {
|
||||
File newFile = new File(f.getAbsolutePath().replace(PROPERTIES_FILE_NAME_UNINSTALLED, PROPERTIES_FILE_NAME) );
|
||||
File newFile = new File(f.getAbsolutePath()
|
||||
.replace(PROPERTIES_FILE_NAME_UNINSTALLED, PROPERTIES_FILE_NAME));
|
||||
if (!f.renameTo(newFile)) {
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param root the starting directory to search recursively
|
||||
@ -700,22 +712,22 @@ public class ExtensionUtils {
|
||||
* @param foundFiles list of all matching files
|
||||
*/
|
||||
public static void findFilesWithName(File root, String fileName, List<File> foundFiles) {
|
||||
|
||||
|
||||
if (root == null || foundFiles == null) {
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
if (root.isDirectory()) {
|
||||
File[] files = root.listFiles();
|
||||
if (files != null) {
|
||||
for (File file : files) {
|
||||
findFilesWithName(file, fileName, foundFiles);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (root.isFile() && root.getName().equals(fileName)) {
|
||||
foundFiles.add(root);
|
||||
}
|
||||
|
||||
if (root.isDirectory()) {
|
||||
File[] files = root.listFiles();
|
||||
if (files != null) {
|
||||
for (File file : files) {
|
||||
findFilesWithName(file, fileName, foundFiles);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (root.isFile() && root.getName().equals(fileName)) {
|
||||
foundFiles.add(root);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -761,7 +773,7 @@ public class ExtensionUtils {
|
||||
throws ExtensionException, CancelledException {
|
||||
|
||||
File newDir = null;
|
||||
try {
|
||||
try {
|
||||
newDir =
|
||||
new File(Application.getApplicationLayout().getExtensionInstallationDirs().get(0) +
|
||||
File.separator + extension.getName());
|
||||
@ -774,11 +786,11 @@ public class ExtensionUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpacks a given zip file to {@link ApplicationLayout#getExtensionInstallationDir}. The
|
||||
* Unpacks a given zip file to {@link ApplicationLayout#getExtensionInstallationDirs}. The
|
||||
* file permissions in the original zip will be retained.
|
||||
* <p>
|
||||
* Note: This method uses the Apache zip files since they keep track of permissions info;
|
||||
* the built-in java objects (ZipEntry et al.) do not.
|
||||
* the built-in java objects (e.g., ZipEntry) do not.
|
||||
*
|
||||
* @param zipFile the zip file to unpack
|
||||
* @param monitor the task monitor
|
||||
@ -993,7 +1005,7 @@ public class ExtensionUtils {
|
||||
String author = props.getProperty("author");
|
||||
String date = props.getProperty("createdOn");
|
||||
String version = props.getProperty("version");
|
||||
|
||||
|
||||
return new ExtensionDetails(name, desc, author, date, version);
|
||||
}
|
||||
|
||||
|
@ -4,9 +4,7 @@ eclipse.project.name = '_JsonDoclet'
|
||||
apply plugin: 'java'
|
||||
|
||||
dependencies {
|
||||
compile('com.googlecode.json-simple:json-simple:1.1.1') {
|
||||
exclude group: 'junit', module: 'junit'
|
||||
}
|
||||
compile "com.google.code.gson:gson:2.8.6"
|
||||
}
|
||||
|
||||
rootProject.createJsondocs.dependsOn jar
|
||||
|
@ -24,9 +24,7 @@ import javax.lang.model.type.TypeMirror;
|
||||
import javax.lang.model.util.ElementFilter;
|
||||
import javax.tools.Diagnostic.Kind;
|
||||
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import com.google.gson.*;
|
||||
import com.sun.source.doctree.*;
|
||||
import com.sun.source.util.DocTrees;
|
||||
|
||||
@ -35,8 +33,9 @@ import jdk.javadoc.doclet.*;
|
||||
/**
|
||||
* Doclet that outputs javadoc in JSON format (instead of HTML). Things like Python can then
|
||||
* read in the JSON and easily access all of the javadoc elements.
|
||||
*
|
||||
* To run: gradle zipJavadocs
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public class JsonDoclet implements Doclet {
|
||||
|
||||
private Reporter log;
|
||||
@ -45,6 +44,11 @@ public class JsonDoclet implements Doclet {
|
||||
private DocletEnvironment docEnv;
|
||||
private DocTrees docTrees;
|
||||
|
||||
private Gson gson = new GsonBuilder()
|
||||
.setPrettyPrinting()
|
||||
.serializeNulls()
|
||||
.create();
|
||||
|
||||
@Override
|
||||
public void init(Locale locale, Reporter reporter) {
|
||||
this.log = reporter;
|
||||
@ -128,13 +132,13 @@ public class JsonDoclet implements Doclet {
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a class {@link TypeElement} to a {@link JSONObject}.
|
||||
* Converts a class {@link TypeElement} to a {@link JsonObject}.
|
||||
*
|
||||
* @param classElement the class {@link TypeElement} to convert
|
||||
* @return A json object that represents the class.
|
||||
*/
|
||||
private JSONObject classToJson(TypeElement classElement) {
|
||||
JSONObject classObj = new JSONObject();
|
||||
private JsonObject classToJson(TypeElement classElement) {
|
||||
JsonObject classObj = new JsonObject();
|
||||
processClassAttributes(classElement, classObj);
|
||||
processFieldAndMethodAttributes(classElement, classObj);
|
||||
return classObj;
|
||||
@ -146,11 +150,11 @@ public class JsonDoclet implements Doclet {
|
||||
* @param classElement the class element to parse
|
||||
* @param classObj the json object to populate
|
||||
*/
|
||||
private void processClassAttributes(TypeElement classElement, JSONObject classObj) {
|
||||
classObj.put("name", classElement.getSimpleName().toString());
|
||||
classObj.put("comment", getComment(docTrees.getDocCommentTree(classElement)));
|
||||
classObj.put("javadoc", getJavadoc(docTrees.getDocCommentTree(classElement)));
|
||||
classObj.put("static", classElement.getModifiers().contains(Modifier.STATIC));
|
||||
private void processClassAttributes(TypeElement classElement, JsonObject classObj) {
|
||||
classObj.addProperty("name", classElement.getSimpleName().toString());
|
||||
classObj.addProperty("comment", getComment(docTrees.getDocCommentTree(classElement)));
|
||||
classObj.addProperty("javadoc", getJavadoc(docTrees.getDocCommentTree(classElement)));
|
||||
classObj.addProperty("static", classElement.getModifiers().contains(Modifier.STATIC));
|
||||
addInterfaces(classElement, classObj);
|
||||
addSuperClass(classElement, classObj);
|
||||
}
|
||||
@ -162,8 +166,8 @@ public class JsonDoclet implements Doclet {
|
||||
* @param typeElement the {@link TypeElement} to parse
|
||||
* @param obj the json object to populate
|
||||
*/
|
||||
private void addInterfaces(TypeElement typeElement, JSONObject obj) {
|
||||
JSONArray interfaceArray = new JSONArray();
|
||||
private void addInterfaces(TypeElement typeElement, JsonObject obj) {
|
||||
JsonArray interfaceArray = new JsonArray();
|
||||
|
||||
//@formatter:off
|
||||
typeElement.getInterfaces()
|
||||
@ -176,7 +180,7 @@ public class JsonDoclet implements Doclet {
|
||||
.forEach(ifaceTypeElement -> interfaceArray.add(ifaceTypeElement.getQualifiedName().toString()));
|
||||
//@formatter:on
|
||||
|
||||
obj.put("implements", interfaceArray);
|
||||
obj.add("implements", interfaceArray);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -186,12 +190,12 @@ public class JsonDoclet implements Doclet {
|
||||
* @param typeElement the {@link TypeElement} to parse
|
||||
* @param obj the json object to populate
|
||||
*/
|
||||
private void addSuperClass(TypeElement typeElement, JSONObject obj) {
|
||||
private void addSuperClass(TypeElement typeElement, JsonObject obj) {
|
||||
if (typeElement.getSuperclass() instanceof DeclaredType) {
|
||||
DeclaredType declaredType = (DeclaredType) typeElement.getSuperclass();
|
||||
if (declaredType.asElement() instanceof TypeElement) {
|
||||
TypeElement typeEl = (TypeElement) declaredType.asElement();
|
||||
obj.put("extends", typeEl.getQualifiedName().toString());
|
||||
obj.addProperty("extends", typeEl.getQualifiedName().toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -202,29 +206,29 @@ public class JsonDoclet implements Doclet {
|
||||
* @param classElement the class to parse
|
||||
* @param classObj the json object to populate
|
||||
*/
|
||||
private void processFieldAndMethodAttributes(TypeElement classElement, JSONObject classObj) {
|
||||
private void processFieldAndMethodAttributes(TypeElement classElement, JsonObject classObj) {
|
||||
|
||||
JSONArray fieldArray = new JSONArray();
|
||||
JSONArray methodArray = new JSONArray();
|
||||
JsonArray fieldArray = new JsonArray();
|
||||
JsonArray methodArray = new JsonArray();
|
||||
|
||||
for (Element el : classElement.getEnclosedElements()) {
|
||||
|
||||
JSONObject obj = new JSONObject();
|
||||
obj.put("name", el.getSimpleName().toString());
|
||||
obj.put("comment", getComment(docTrees.getDocCommentTree(el)));
|
||||
obj.put("javadoc", getJavadoc(docTrees.getDocCommentTree(el)));
|
||||
obj.put("static", el.getModifiers().contains(Modifier.STATIC));
|
||||
JsonObject obj = new JsonObject();
|
||||
obj.addProperty("name", el.getSimpleName().toString());
|
||||
obj.addProperty("comment", getComment(docTrees.getDocCommentTree(el)));
|
||||
obj.addProperty("javadoc", getJavadoc(docTrees.getDocCommentTree(el)));
|
||||
obj.addProperty("static", el.getModifiers().contains(Modifier.STATIC));
|
||||
|
||||
switch (el.getKind()) {
|
||||
case FIELD:
|
||||
VariableElement varElement = (VariableElement) el;
|
||||
obj.put("type_long", getTypeLong(el.asType()));
|
||||
obj.put("type_short", getTypeShort(el.asType()));
|
||||
obj.addProperty("type_long", getTypeLong(el.asType()));
|
||||
obj.addProperty("type_short", getTypeShort(el.asType()));
|
||||
Object constantValue = varElement.getConstantValue();
|
||||
if (constantValue instanceof String) {
|
||||
constantValue = "\"" + constantValue + "\"";
|
||||
}
|
||||
obj.put("constant_value", Objects.toString(constantValue, null)); // only applies to 'final'
|
||||
obj.addProperty("constant_value", Objects.toString(constantValue, null)); // only applies to 'final'
|
||||
fieldArray.add(obj);
|
||||
break;
|
||||
case CONSTRUCTOR:
|
||||
@ -255,8 +259,8 @@ public class JsonDoclet implements Doclet {
|
||||
}
|
||||
}
|
||||
|
||||
classObj.put("fields", fieldArray);
|
||||
classObj.put("methods", methodArray);
|
||||
classObj.add("fields", fieldArray);
|
||||
classObj.add("methods", methodArray);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -266,14 +270,14 @@ public class JsonDoclet implements Doclet {
|
||||
* @param execElement the element to parse
|
||||
* @param obj the json object
|
||||
*/
|
||||
private void addParams(ExecutableElement execElement, JSONObject obj) {
|
||||
private void addParams(ExecutableElement execElement, JsonObject obj) {
|
||||
|
||||
JSONArray paramsArray = new JSONArray();
|
||||
JsonArray paramsArray = new JsonArray();
|
||||
for (VariableElement varElement : execElement.getParameters()) {
|
||||
JSONObject paramObj = new JSONObject();
|
||||
paramObj.put("name", varElement.getSimpleName().toString());
|
||||
paramObj.put("type_long", getTypeLong(varElement.asType()));
|
||||
paramObj.put("type_short", getTypeShort(varElement.asType()));
|
||||
JsonObject paramObj = new JsonObject();
|
||||
paramObj.addProperty("name", varElement.getSimpleName().toString());
|
||||
paramObj.addProperty("type_long", getTypeLong(varElement.asType()));
|
||||
paramObj.addProperty("type_short", getTypeShort(varElement.asType()));
|
||||
String comment = "";
|
||||
DocCommentTree commentTree = docTrees.getDocCommentTree(execElement);
|
||||
if (commentTree != null) {
|
||||
@ -287,10 +291,10 @@ public class JsonDoclet implements Doclet {
|
||||
}
|
||||
}
|
||||
}
|
||||
paramObj.put("comment", comment);
|
||||
paramObj.addProperty("comment", comment);
|
||||
paramsArray.add(paramObj);
|
||||
}
|
||||
obj.put("params", paramsArray);
|
||||
obj.add("params", paramsArray);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -300,11 +304,11 @@ public class JsonDoclet implements Doclet {
|
||||
* @param execElement the element to parse
|
||||
* @param obj the json object
|
||||
*/
|
||||
private void addReturn(ExecutableElement execElement, JSONObject obj) {
|
||||
private void addReturn(ExecutableElement execElement, JsonObject obj) {
|
||||
TypeMirror returnType = execElement.getReturnType();
|
||||
JSONObject returnObj = new JSONObject();
|
||||
returnObj.put("type_long", getTypeLong(returnType));
|
||||
returnObj.put("type_short", getTypeShort(returnType));
|
||||
JsonObject returnObj = new JsonObject();
|
||||
returnObj.addProperty("type_long", getTypeLong(returnType));
|
||||
returnObj.addProperty("type_short", getTypeShort(returnType));
|
||||
String comment = "";
|
||||
DocCommentTree commentTree = docTrees.getDocCommentTree(execElement);
|
||||
if (commentTree != null) {
|
||||
@ -314,8 +318,8 @@ public class JsonDoclet implements Doclet {
|
||||
}
|
||||
}
|
||||
}
|
||||
returnObj.put("comment", comment);
|
||||
obj.put("return", returnObj);
|
||||
returnObj.addProperty("comment", comment);
|
||||
obj.add("return", returnObj);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -325,14 +329,14 @@ public class JsonDoclet implements Doclet {
|
||||
* @param execElement the element to parse
|
||||
* @param obj the json object
|
||||
*/
|
||||
private void addExceptions(ExecutableElement execElement, JSONObject obj) {
|
||||
JSONArray throwsArray = new JSONArray();
|
||||
private void addExceptions(ExecutableElement execElement, JsonObject obj) {
|
||||
JsonArray throwsArray = new JsonArray();
|
||||
for (TypeMirror thrownType : execElement.getThrownTypes()) {
|
||||
JSONObject throwObj = new JSONObject();
|
||||
JsonObject throwObj = new JsonObject();
|
||||
String typeLong = getTypeLong(thrownType);
|
||||
String typeShort = getTypeShort(thrownType);
|
||||
throwObj.put("type_long", typeLong);
|
||||
throwObj.put("type_short", typeShort);
|
||||
throwObj.addProperty("type_long", typeLong);
|
||||
throwObj.addProperty("type_short", typeShort);
|
||||
String comment = "";
|
||||
DocCommentTree commentTree = docTrees.getDocCommentTree(execElement);
|
||||
if (commentTree != null) {
|
||||
@ -346,10 +350,10 @@ public class JsonDoclet implements Doclet {
|
||||
}
|
||||
}
|
||||
}
|
||||
throwObj.put("comment", comment);
|
||||
throwObj.addProperty("comment", comment);
|
||||
throwsArray.add(throwObj);
|
||||
}
|
||||
obj.put("throws", throwsArray);
|
||||
obj.add("throws", throwsArray);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -446,11 +450,12 @@ public class JsonDoclet implements Doclet {
|
||||
* @param qualifiedName The qualified class name. This name will get converted into a directory
|
||||
* structure.
|
||||
*/
|
||||
private void writeJsonToFile(JSONObject json, Name qualifiedName) {
|
||||
private void writeJsonToFile(JsonObject json, Name qualifiedName) {
|
||||
|
||||
File jsonFile = new File(destDir, qualifiedName.toString().replace('.', '/') + ".json");
|
||||
jsonFile.getParentFile().mkdirs();
|
||||
try (PrintWriter writer = new PrintWriter(new FileWriter(jsonFile))) {
|
||||
writer.println(json.toJSONString());
|
||||
writer.println(gson.toJson(json));
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
|
Loading…
Reference in New Issue
Block a user