package com.lauriewired.handlers.set;
import com.lauriewired.handlers.Handler;
import com.sun.net.httpserver.HttpExchange;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.data.Structure;
import ghidra.program.model.listing.Program;
import javax.swing.SwingUtilities;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import static com.lauriewired.util.ParseUtils.*;
import ghidra.program.model.data.CategoryPath;
import static ghidra.program.util.GhidraProgramUtilities.getCurrentProgram;
/**
* Handler for removing an entire structure from the data type manager in Ghidra.
* This handler processes requests to completely remove a specified structure by name and
* category, which is more commonly needed than just clearing struct contents.
*/
public final class RemoveStruct extends Handler {
/**
* Constructs a new RemoveStruct handler.
*
* @param tool the PluginTool instance to use for program operations
*/
public RemoveStruct(PluginTool tool) {
super(tool, "/remove_struct");
}
/**
* Handles HTTP requests to remove a structure.
* Expects POST parameters: struct_name (required).
*
* @param exchange the HttpExchange object containing the request
* @throws IOException if an I/O error occurs
*/
@Override
public void handle(HttpExchange exchange) throws IOException {
Map<String, String> params = parsePostParams(exchange);
String structName = params.get("struct_name");
if (structName == null) {
sendResponse(exchange, "struct_name is required");
return;
}
sendResponse(exchange, removeStruct(structName));
}
/**
* Removes an entire structure from the data type manager.
*
* @param structName the name of the structure to remove
* @return a message indicating the result of the operation
*/
private String removeStruct(String structName) {
Program program = getCurrentProgram(tool);
if (program == null)
return "No program loaded";
final AtomicReference<String> result = new AtomicReference<>();
try {
SwingUtilities.invokeAndWait(() -> {
int txId = program.startTransaction("Remove Struct");
boolean success = false;
try {
DataTypeManager dtm = program.getDataTypeManager();
CategoryPath path = new CategoryPath("/");
DataType dt = dtm.getDataType(path, structName);
if (dt == null || !(dt instanceof Structure)) {
result.set("Error: Struct " + structName + " not found");
return;
}
// Remove the entire structure from the data type manager
boolean removed = dtm.remove(dt, null);
if (removed) {
result.set("Struct " + structName + " successfully removed");
success = true;
} else {
result.set("Error: Failed to remove struct " + structName + " - it may be in use by other data types");
}
} catch (Exception e) {
result.set("Error: Failed to remove struct: " + e.getMessage());
} finally {
program.endTransaction(txId, success);
}
});
} catch (InterruptedException | InvocationTargetException e) {
return "Error: Failed to execute remove struct on Swing thread: " + e.getMessage();
}
return result.get();
}
}