mirror of
https://github.com/xlmnxp/extractify.zip.git
synced 2024-11-23 17:13:12 +03:00
add binary view
This commit is contained in:
parent
c8209c5799
commit
5a739b543d
9
app.vue
9
app.vue
@ -5,6 +5,7 @@ import { useDisplay } from 'vuetify/lib/framework.mjs';
|
|||||||
import { HistoryManager } from './composables/history-manager';
|
import { HistoryManager } from './composables/history-manager';
|
||||||
import { FilesManager } from './composables/files-manager';
|
import { FilesManager } from './composables/files-manager';
|
||||||
import type { iFile } from "composables/worker/7zip-manager"
|
import type { iFile } from "composables/worker/7zip-manager"
|
||||||
|
import { videoExtensions, binaryExtensions } from '#imports';
|
||||||
|
|
||||||
let display = useDisplay();
|
let display = useDisplay();
|
||||||
let drawer = ref(!display.mdAndDown.value);
|
let drawer = ref(!display.mdAndDown.value);
|
||||||
@ -57,6 +58,8 @@ watchEffect(async () => {
|
|||||||
const file = filesManager.getFile(selectedPath.value);
|
const file = filesManager.getFile(selectedPath.value);
|
||||||
filesGridList.value = file?.content;
|
filesGridList.value = file?.content;
|
||||||
|
|
||||||
|
console.log("Selected file", file);
|
||||||
|
|
||||||
selectedList.value = [];
|
selectedList.value = [];
|
||||||
for (const selectedElement of document.querySelectorAll(".selectable.selected")) {
|
for (const selectedElement of document.querySelectorAll(".selectable.selected")) {
|
||||||
selectedElement.classList.remove("selected");
|
selectedElement.classList.remove("selected");
|
||||||
@ -193,9 +196,13 @@ function stepUp(path: string) {
|
|||||||
<MediaVideoPlayer :src="mediaBlobUrl"></MediaVideoPlayer>
|
<MediaVideoPlayer :src="mediaBlobUrl"></MediaVideoPlayer>
|
||||||
</template>
|
</template>
|
||||||
<template
|
<template
|
||||||
v-if="!filesManager.getFile(selectedPath)?.isFolder && files.length && !videoExtensions.includes(filesManager.getFile(selectedPath)?.extension)">
|
v-if="!filesManager.getFile(selectedPath)?.isFolder && files.length && !videoExtensions.includes(filesManager.getFile(selectedPath)?.extension) && !binaryExtensions.includes(filesManager.getFile(selectedPath)?.extension)">
|
||||||
<TextEditor :file="filesManager.getFile(selectedPath)" :filesManager="filesManager"></TextEditor>
|
<TextEditor :file="filesManager.getFile(selectedPath)" :filesManager="filesManager"></TextEditor>
|
||||||
</template>
|
</template>
|
||||||
|
<template
|
||||||
|
v-if="!filesManager.getFile(selectedPath)?.isFolder && files.length && binaryExtensions.includes(filesManager.getFile(selectedPath)?.extension)">
|
||||||
|
<BinaryViewer :file="filesManager.getFile(selectedPath)" :filesManager="filesManager"></BinaryViewer>
|
||||||
|
</template>
|
||||||
<template v-if="!files.length">
|
<template v-if="!files.length">
|
||||||
<!-- tutorial drag and drop zipped file here and review it securely -->
|
<!-- tutorial drag and drop zipped file here and review it securely -->
|
||||||
<v-row align="center" justify="center">
|
<v-row align="center" justify="center">
|
||||||
|
144
components/binary-viewer.vue
Normal file
144
components/binary-viewer.vue
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, onMounted, computed } from 'vue'
|
||||||
|
import { FilesManager } from '~/composables/files-manager';
|
||||||
|
import { iFile } from '~/composables/worker/7zip-manager';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
file: iFile,
|
||||||
|
filesManager: FilesManager
|
||||||
|
}
|
||||||
|
|
||||||
|
const { file, filesManager } = defineProps<Props>()
|
||||||
|
const buffer = ref<Uint8Array>()
|
||||||
|
const containerRef = ref<HTMLElement>()
|
||||||
|
const isLoading = ref(true)
|
||||||
|
const rowHeight = 24 // pixels per row
|
||||||
|
const visibleRows = ref(0)
|
||||||
|
const scrollTop = ref(0)
|
||||||
|
|
||||||
|
// Calculate total rows and visible window
|
||||||
|
const totalRows = computed(() => buffer.value ? Math.ceil(buffer.value.length / 16) : 0)
|
||||||
|
const startRow = computed(() => Math.floor(scrollTop.value / rowHeight))
|
||||||
|
const endRow = computed(() => Math.min(startRow.value + visibleRows.value + 5, totalRows.value))
|
||||||
|
|
||||||
|
// Get only the visible rows data
|
||||||
|
const visibleData = computed(() => {
|
||||||
|
if (!buffer.value) return []
|
||||||
|
|
||||||
|
const rows = []
|
||||||
|
for (let i = startRow.value; i < endRow.value; i++) {
|
||||||
|
const offset = i * 16
|
||||||
|
const chunk = buffer.value.slice(offset, offset + 16)
|
||||||
|
const hex = Array.from(chunk).map(b => b.toString(16).padStart(2, '0')).join(' ')
|
||||||
|
const ascii = Array.from(chunk).map(b => b >= 32 && b <= 126 ? String.fromCharCode(b) : '.').join('')
|
||||||
|
|
||||||
|
rows.push({
|
||||||
|
address: offset.toString(16).padStart(8, '0'),
|
||||||
|
hex: hex.padEnd(48, ' '),
|
||||||
|
ascii
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return rows
|
||||||
|
})
|
||||||
|
|
||||||
|
// Handle scroll events
|
||||||
|
function onScroll(event: Event) {
|
||||||
|
const container = event.target as HTMLElement
|
||||||
|
scrollTop.value = container.scrollTop
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate visible rows based on container height
|
||||||
|
function updateVisibleRows() {
|
||||||
|
if (containerRef.value) {
|
||||||
|
visibleRows.value = Math.ceil(containerRef.value.clientHeight / rowHeight)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
try {
|
||||||
|
buffer.value = await filesManager.getFileContent(file.path, "binary") as Uint8Array
|
||||||
|
updateVisibleRows()
|
||||||
|
window.addEventListener('resize', updateVisibleRows)
|
||||||
|
} finally {
|
||||||
|
isLoading.value = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="binary-viewer">
|
||||||
|
<div v-if="isLoading" class="loading">
|
||||||
|
Loading...
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-else
|
||||||
|
ref="containerRef"
|
||||||
|
class="hex-container"
|
||||||
|
@scroll="onScroll"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="scroll-content"
|
||||||
|
:style="{
|
||||||
|
height: `${totalRows * rowHeight}px`,
|
||||||
|
paddingTop: `${startRow * rowHeight}px`
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-for="row in visibleData"
|
||||||
|
:key="row.address"
|
||||||
|
class="hex-line"
|
||||||
|
>
|
||||||
|
<span class="address">{{ row.address }}</span>
|
||||||
|
<span class="hex">{{ row.hex }}</span>
|
||||||
|
<span class="ascii">{{ row.ascii }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.binary-viewer {
|
||||||
|
font-family: monospace;
|
||||||
|
white-space: pre;
|
||||||
|
padding: 1rem;
|
||||||
|
background-color: var(--v-theme-surface);
|
||||||
|
height: calc(100vh - 150px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hex-container {
|
||||||
|
height: 100%;
|
||||||
|
overflow-y: auto;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scroll-content {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hex-line {
|
||||||
|
line-height: 1.5;
|
||||||
|
height: v-bind(rowHeight + 'px');
|
||||||
|
}
|
||||||
|
|
||||||
|
.address {
|
||||||
|
color: #666;
|
||||||
|
margin-right: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hex {
|
||||||
|
margin-right: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ascii {
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
@ -10,7 +10,8 @@ import mime from 'mime';
|
|||||||
export const videoExtensions = ['mp4', 'avi', 'mov', 'mkv'];
|
export const videoExtensions = ['mp4', 'avi', 'mov', 'mkv'];
|
||||||
export const imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
|
export const imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
|
||||||
export const audioExtensions = ['mp3', 'wav', 'ogg', 'flac'];
|
export const audioExtensions = ['mp3', 'wav', 'ogg', 'flac'];
|
||||||
export const textExtensions = ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'md', 'js', 'ts', 'php', 'c', 'cpp', 'py', 'html', 'css', 'scss', 'sass', 'less', 'json', 'xml', 'sql', 'java', 'go', 'rb', 'sh', 'bat', 'ps1', 'cmd', 'yml', 'yaml', 'ini', 'toml', 'csv', 'tsv', 'gitignore', 'lock', 'htaccess', 'htpasswd', 'env', 'dockerfile', 'gitattributes', 'gitmodules', 'editorconfig', 'babelrc', 'eslintrc', 'eslintignore', 'prettierrc', 'prettierignore', 'stylelintrc', 'stylelintignore', 'postcssrc', 'postcss.config', 'jsx', 'tsx', 'license']
|
export const textExtensions = ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'md', 'js', 'ts', 'php', 'c', 'cpp', 'py', 'html', 'css', 'scss', 'sass', 'less', 'json', 'xml', 'sql', 'java', 'go', 'rb', 'sh', 'bat', 'ps1', 'cmd', 'yml', 'yaml', 'ini', 'toml', 'csv', 'tsv', 'gitignore', 'lock', 'htaccess', 'htpasswd', 'env', 'dockerfile', 'gitattributes', 'gitmodules', 'editorconfig', 'babelrc', 'eslintrc', 'eslintignore', 'prettierrc', 'prettierignore', 'stylelintrc', 'stylelintignore', 'postcssrc', 'postcss.config', 'jsx', 'tsx', 'license'];
|
||||||
|
export const binaryExtensions = ['exe', 'dll', 'so', 'dylib', 'bin', 'dat', 'db', 'sqlite', 'o', 'class', 'pyc'];
|
||||||
|
|
||||||
export class FilesManager {
|
export class FilesManager {
|
||||||
consoleOutputBuffer: string[] = [];
|
consoleOutputBuffer: string[] = [];
|
||||||
|
6
package-lock.json
generated
6
package-lock.json
generated
@ -2662,9 +2662,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/caniuse-lite": {
|
"node_modules/caniuse-lite": {
|
||||||
"version": "1.0.30001487",
|
"version": "1.0.30001677",
|
||||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001487.tgz",
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001677.tgz",
|
||||||
"integrity": "sha512-83564Z3yWGqXsh2vaH/mhXfEM0wX+NlBCm1jYHOb97TrTWJEmPTccZgeLTPBUUb0PNVo+oomb7wkimZBIERClA==",
|
"integrity": "sha512-fmfjsOlJUpMWu+mAAtZZZHz7UEwsUxIIvu1TJfO1HqFQvB/B+ii0xr9B5HpbZY/mC4XZ8SvjHJqtAY6pDPQEog==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user