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 ghidra.util.Msg;
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 renaming an existing structure in the data type manager.
* This allows updating structure names during reverse engineering analysis.
*/
public final class RenameStruct extends Handler {
/**
* Constructs a new RenameStruct handler.
*
* @param tool the PluginTool instance to use for program operations
*/
public RenameStruct(PluginTool tool) {
super(tool, "/rename_struct");
}
/**
* Handles HTTP requests to rename a structure.
* Expects POST parameters: struct_name (required), new_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");
String newName = params.get("new_name");
if (structName == null || newName == null) {
sendResponse(exchange, "struct_name and new_name are required");
return;
}
if (structName.trim().isEmpty() || newName.trim().isEmpty()) {
sendResponse(exchange, "struct_name and new_name cannot be empty");
return;
}
sendResponse(exchange, renameStruct(structName, newName));
}
/**
* Renames a structure in the data type manager.
*
* @param structName the current name of the structure
* @param newName the new name for the structure
* @return a message indicating the result of the operation
*/
private String renameStruct(String structName, String newName) {
Program program = getCurrentProgram(tool);
if (program == null)
return "No program loaded";
final AtomicReference<String> result = new AtomicReference<>();
try {
SwingUtilities.invokeAndWait(() -> {
int txId = program.startTransaction("Rename 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;
}
// Check if a struct with the new name already exists
DataType existingDt = dtm.getDataType(path, newName);
if (existingDt != null) {
result.set("Error: Struct " + newName + " already exists");
return;
}
// Rename the structure
try {
dt.setName(newName);
result.set("Struct " + structName + " successfully renamed to " + newName);
success = true;
} catch (Exception e) {
result.set("Error: Failed to rename struct " + structName + " - " + e.getMessage());
Msg.error(this, "Rename struct error", e);
}
} catch (Exception e) {
result.set("Error: Failed to rename struct: " + e.getMessage());
Msg.error(this, "Rename struct error", e);
} finally {
program.endTransaction(txId, success);
}
});
} catch (InterruptedException | InvocationTargetException e) {
return "Error: Failed to execute rename struct on Swing thread: " + e.getMessage();
}
return result.get();
}
}