package eu.starsong.ghidra.endpoints; import com.google.gson.JsonObject; import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpServer; import eu.starsong.ghidra.api.ResponseBuilder; import ghidra.framework.plugintool.PluginTool; import ghidra.program.model.listing.Program; import ghidra.program.model.mem.MemoryBlock; import ghidra.util.Msg; import java.io.IOException; import java.util.*; public class SegmentEndpoints extends AbstractEndpoint { private PluginTool tool; // Updated constructor to accept port public SegmentEndpoints(Program program, int port) { super(program, port); // Call super constructor } public SegmentEndpoints(Program program, int port, PluginTool tool) { super(program, port); this.tool = tool; } @Override protected PluginTool getTool() { return tool; } @Override public void registerEndpoints(HttpServer server) { server.createContext("/segments", this::handleSegments); } public void handleSegments(HttpExchange exchange) throws IOException { try { if ("GET".equals(exchange.getRequestMethod())) { Map qparams = parseQueryParams(exchange); int offset = parseIntOrDefault(qparams.get("offset"), 0); int limit = parseIntOrDefault(qparams.get("limit"), 100); String nameFilter = qparams.get("name"); Program program = getCurrentProgram(); if (program == null) { sendErrorResponse(exchange, 400, "No program loaded", "NO_PROGRAM_LOADED"); return; } List> segments = new ArrayList<>(); for (MemoryBlock block : program.getMemory().getBlocks()) { // Apply name filter if present if (nameFilter != null && !block.getName().contains(nameFilter)) { continue; } Map segment = new HashMap<>(); segment.put("name", block.getName()); segment.put("start", block.getStart().toString()); segment.put("end", block.getEnd().toString()); segment.put("size", block.getSize()); // Add permissions segment.put("readable", block.isRead()); segment.put("writable", block.isWrite()); segment.put("executable", block.isExecute()); segment.put("initialized", block.isInitialized()); // Add HATEOAS links for this segment Map links = new HashMap<>(); Map selfLink = new HashMap<>(); selfLink.put("href", "/segments/" + block.getName()); links.put("self", selfLink); Map memoryLink = new HashMap<>(); memoryLink.put("href", "/memory/" + block.getStart()); links.put("memory", memoryLink); segment.put("_links", links); segments.add(segment); } // Build response with HATEOAS links ResponseBuilder builder = new ResponseBuilder(exchange, port) .success(true); // Handle optional name filter String queryParams = nameFilter != null ? "name=" + nameFilter : null; // Apply pagination and get paginated items List> paginatedSegments = applyPagination( segments, offset, limit, builder, "/segments", queryParams); // Set the paginated result builder.result(paginatedSegments); // Add program link builder.addLink("program", "/program"); sendJsonResponse(exchange, builder.build(), 200); } else { sendErrorResponse(exchange, 405, "Method Not Allowed", "METHOD_NOT_ALLOWED"); } } catch (Exception e) { Msg.error(this, "Error in /segments endpoint", e); sendErrorResponse(exchange, 500, "Internal server error: " + e.getMessage(), "INTERNAL_ERROR"); } } // parseIntOrDefault is inherited from AbstractEndpoint }