|
12 | 12 |
|
13 | 13 | import { AccessInstance, type GenericInformation, MemoryRegionManager, type OutputJSON } from './lib/types'; |
14 | 14 |
|
15 | | - import { Drawer, drawerStore } from '@skeletonlabs/skeleton'; |
| 15 | + import { Drawer, drawerStore, FileDropzone } from '@skeletonlabs/skeleton'; |
16 | 16 | import { dummyData } from './lib/loadDummyData'; |
17 | 17 | import InspectDrawer from './components/InspectDrawer.svelte'; |
18 | 18 | import VisualizeMemoryRegion from './components/VisualizeMemoryRegion.svelte'; |
19 | 19 | import { pageState } from './lib/stores'; |
20 | 20 | import { currentMemoryRegion } from './lib/stores'; |
21 | 21 |
|
22 | | - // Load the general data |
23 | | - // We actually do a JSON.parse here, as it is faster using the JSON parser than for the browser to evaluate an existing JSON object in JavaScript |
24 | | - // This is because the parser for the DOM needs to do more complex work. |
25 | | - // Additionally this leaves us an easy entry point which will not get simplified away (which normally a comment might be) |
| 22 | + // Function to load a valid JSON file into the application as memory structure |
| 23 | + const loadJSON = (json: OutputJSON) => { |
| 24 | + const info = json.GlobalSettings; |
26 | 25 |
|
27 | | - // But actually for development mode load in a file |
28 | | - const MemoryData: OutputJSON = JSON.parse(import.meta.env.DEV ? dummyData : `// JS_TEMPLATE`); |
| 26 | + // Generate AccessInstances from the pure data |
| 27 | + const data: AccessInstance[] = json.MemoryAccessLogs.map( |
| 28 | + ([address, blockID, threadID, isRead]) => new AccessInstance(address, blockID, threadID, isRead, info) |
| 29 | + ); |
29 | 30 |
|
30 | | - const info = MemoryData.GlobalSettings; |
| 31 | + // Generate MemoryRegionManagers |
| 32 | + const memoryRegions: MemoryRegionManager[] = json.MemoryRegions.map((region) => new MemoryRegionManager(region)); |
31 | 33 |
|
32 | | - // Generate AccessInstances from the pure data |
33 | | - const data: AccessInstance[] = MemoryData.MemoryAccessLogs.map( |
34 | | - ([address, blockID, threadID, isRead]) => new AccessInstance(address, blockID, threadID, isRead, info) |
35 | | - ); |
36 | | -
|
37 | | - // Generate MemoryRegionManagers |
38 | | - const memoryRegions: MemoryRegionManager[] = MemoryData.MemoryRegions.map( |
39 | | - (region) => new MemoryRegionManager(region) |
40 | | - ); |
| 34 | + // Store all our memory accesses in the memoryRegions |
| 35 | + // This is relatively slow as we need to iterate over all memory accesses and then again over all memory regions, maybe this can be optimized, but the number of memory Regions should be low, so this should not be a problem |
| 36 | + data.forEach((access) => { |
| 37 | + memoryRegions.forEach((region) => { |
| 38 | + region.addMemoryAccessIfInRegion(access); |
| 39 | + }); |
| 40 | + }); |
41 | 41 |
|
42 | | - // Store all our memory accesses in the memoryRegions |
43 | | - // This is relatively slow as we need to iterate over all memory accesses and then again over all memory regions, maybe this can be optimized, but the number of memory Regions should be low, so this should not be a problem |
44 | | - data.forEach((access) => { |
| 42 | + // For each memory region, bake all data which gets processed after the data is loaded |
45 | 43 | memoryRegions.forEach((region) => { |
46 | | - region.addMemoryAccessIfInRegion(access); |
| 44 | + region.bake(); |
47 | 45 | }); |
48 | | - }); |
49 | 46 |
|
50 | | - // For each memory region, bake all data which gets processed after the data is loaded |
51 | | - memoryRegions.forEach((region) => { |
52 | | - region.bake(); |
53 | | - }); |
| 47 | + // Add the loaded memory regions to the store so it can be selected |
| 48 | + $pageState.availableMemoryRegions = [...$pageState.availableMemoryRegions, ...memoryRegions]; |
| 49 | + }; |
| 50 | +
|
| 51 | + // To support errors and loading new files into the template without an export, create all necessary variables |
| 52 | + // Template which will be replaced |
| 53 | + const loadData = '// JS_TEMPLATE'; |
| 54 | + let validTemplate = true; |
| 55 | + // Holds dragged in files |
| 56 | + let files: FileList; |
| 57 | +
|
| 58 | + // Check if we are not in development mode, but still no data was loaded |
| 59 | + if (loadData.startsWith('// JS_TEMPLAT') && !import.meta.env.DEV) { |
| 60 | + // Neither data, nor dev mode are enabled, so show error. |
| 61 | + validTemplate = false; |
| 62 | + } else { |
| 63 | + // Otherwise we might be in dev mode, or have data |
| 64 | + try { |
| 65 | + // For development mode load in a file |
| 66 | + // For production mode parse the existing data |
| 67 | + // Parsing JSON in a string is always faster than the JavaScript parser |
| 68 | + const MemoryData: OutputJSON = JSON.parse(import.meta.env.DEV ? dummyData : loadData); |
| 69 | + loadJSON(MemoryData); |
| 70 | + } catch (e) { |
| 71 | + // If we have an error, we are not in dev mode, but the data is invalid |
| 72 | + console.error(e); |
| 73 | + validTemplate = false; |
| 74 | + } |
| 75 | + } |
| 76 | +
|
| 77 | + // This is a reactive statement if files changes, this only changes, if files were dropped |
| 78 | + $: if (files) { |
| 79 | + // Log the files we got |
| 80 | + console.log(files); |
| 81 | +
|
| 82 | + // Now try to load the data instead of the static data included in the file |
| 83 | + for (const file of files) { |
| 84 | + // Check if it is a JSON file |
| 85 | + if (file.type === 'application/json') { |
| 86 | + // Read the file |
| 87 | + const reader = new FileReader(); |
| 88 | + // Define the callback for when the file is read |
| 89 | + reader.onload = (e) => { |
| 90 | + // Parse the JSON |
| 91 | + const data: OutputJSON = JSON.parse(e.target.result as string) as OutputJSON; |
| 92 | + // Check if the data is valid |
| 93 | + if (data && data.GlobalSettings && data.MemoryRegions.length > 0 && data.MemoryAccessLogs.length > 0) { |
| 94 | + // Load the data |
| 95 | + loadJSON(data); |
| 96 | +
|
| 97 | + // To not cause an event loading the same data twice, clear the files |
| 98 | + files = null; |
54 | 99 |
|
55 | | - $pageState.availableMemoryRegions = memoryRegions; |
| 100 | + // Set the valid template to true |
| 101 | + validTemplate = true; |
| 102 | + } |
| 103 | + }; |
| 104 | + // Start reading the file |
| 105 | + reader.readAsText(file); |
| 106 | + } |
| 107 | + } |
| 108 | + } |
56 | 109 | </script> |
57 | 110 |
|
58 | 111 | <Layout> |
59 | 112 | <div class="h-full mx-auto flex flex-row"> |
60 | | - {#if $currentMemoryRegion != null} |
61 | | - <VisualizeMemoryRegion MemoryRegion={$currentMemoryRegion} /> |
| 113 | + {#if validTemplate} |
| 114 | + {#if $currentMemoryRegion != null && !('isPlaceHolder' in $currentMemoryRegion)} |
| 115 | + <VisualizeMemoryRegion MemoryRegion={$currentMemoryRegion} /> |
| 116 | + {:else} |
| 117 | + <div class="flex flex-col justify-center items-center w-full h-full"> |
| 118 | + <h1 class="text-3xl font-bold opacity-30 ">Please select a memory region</h1> |
| 119 | + <div class="px-12 my-12 w-full"> |
| 120 | + <FileDropzone bind:files title="You can upload additional .json files here." /> |
| 121 | + </div> |
| 122 | + </div> |
| 123 | + {/if} |
62 | 124 | {:else} |
63 | | - <div class="flex flex-col justify-center items-center w-full h-full"> |
64 | | - <h1 class="text-3xl font-bold opacity-30 ">Please select a memory region</h1> |
| 125 | + <div class="flex flex-col justify-center items-center w-full h-full text-center"> |
| 126 | + <h1 class="text-3xl font-bold opacity-30 "> |
| 127 | + Please load in valid data for this template.<br /> Without data this HTML file can't do anything. |
| 128 | + </h1> |
| 129 | + <div class="px-12 my-12 w-full"> |
| 130 | + <FileDropzone bind:files title="You can alternatively drag in a valid .json as template here." /> |
| 131 | + </div> |
65 | 132 | </div> |
66 | 133 | {/if} |
67 | 134 | </div> |
|
0 commit comments