diff --git a/frontend/backend/ofrak_server.py b/frontend/backend/ofrak_server.py index 2ed19c542..58b84714d 100644 --- a/frontend/backend/ofrak_server.py +++ b/frontend/backend/ofrak_server.py @@ -25,8 +25,15 @@ from ofrak_type.error import NotFoundError from ofrak_type.range import Range -from ofrak import OFRAKContext, OFRAK -from ofrak.core import File +from ofrak import ( + OFRAKContext, + OFRAK, + ResourceFilter, + ResourceAttributeRangeFilter, + ResourceAttributeValueFilter, + ResourceSort, +) +from ofrak.core import File, Addressable from ofrak.core import ( GenericBinary, AddCommentModifier, @@ -131,6 +138,7 @@ def __init__( web.post("/{resource_id}/find_and_replace", self.find_and_replace), web.post("/{resource_id}/add_comment", self.add_comment), web.post("/{resource_id}/delete_comment", self.delete_comment), + web.post("/{resource_id}/search_for_vaddr", self.search_for_vaddr), ] ) @@ -330,6 +338,28 @@ async def delete_comment(self, request: Request) -> Response: ) return web.json_response(await self._serialize_component_result(result)) + @exceptions_to_http(SerializedError) + async def search_for_vaddr(self, request: Request) -> Response: + resource = await self._get_resource_for_request(request) + vaddr_start, vaddr_end = self._serializer.from_pjson( + await request.json(), Tuple[int, Optional[int]] + ) + try: + if vaddr_end is not None: + vaddr_filter = ResourceAttributeRangeFilter( + Addressable.VirtualAddress, vaddr_start, vaddr_end + ) + else: + vaddr_filter = ResourceAttributeValueFilter(Addressable.VirtualAddress, vaddr_start) + matching_resources = await resource.get_descendants( + r_filter=ResourceFilter(attribute_filters=(vaddr_filter,)), + r_sort=ResourceSort(Addressable.VirtualAddress), + ) + return web.json_response(list(map(self._serialize_resource, matching_resources))) + + except NotFoundError: + return web.json_response([]) + async def _get_resource_by_id(self, resource_id: bytes, job_id: bytes) -> Resource: resource = await self._ofrak_context.resource_factory.create( job_id, diff --git a/frontend/src/ResourceTreeToolbar.svelte b/frontend/src/ResourceTreeToolbar.svelte index 7dfd0b567..812620a2a 100644 --- a/frontend/src/ResourceTreeToolbar.svelte +++ b/frontend/src/ResourceTreeToolbar.svelte @@ -5,6 +5,7 @@ import Toolbar from "./Toolbar.svelte"; import { selectedResource, selected } from "./stores.js"; + import SearchView from "./SearchView.svelte"; export let resourceNodeDataMap, modifierView; $: rootResource = $selectedResource; @@ -187,6 +188,14 @@ modifierView = CommentView; }, }, + + { + text: "Search", + iconUrl: "/icons/identify.svg", + onclick: async (e) => { + modifierView = SearchView; + }, + }, ]; } diff --git a/frontend/src/SearchView.svelte b/frontend/src/SearchView.svelte new file mode 100644 index 000000000..384636930 --- /dev/null +++ b/frontend/src/SearchView.svelte @@ -0,0 +1,215 @@ + + + + +
+ Searching for descendants of {searchTarget.get_caption()} ({searchTarget.get_id()}) + whose virtual address matches a specific address or lies in a range of + addresses. +
+ {#if rangeSearch} + + + {:else} + + {/if} ++ Error: + {errorMessage} +
+ {/if} +Found {results.length} results
+