broken stream data
This commit is contained in:
parent
dcd1bd6d3f
commit
f6fa5d7269
@ -8,7 +8,7 @@ use crate::pdf::object::Resolve;
|
||||
use lazy_static::lazy_static;
|
||||
use pdf::file::{File, FileOptions, NoLog, ObjectCache, StreamCache};
|
||||
use pdf::object::{Object, ObjectWrite, PlainRef, Stream, Trace};
|
||||
use pdf::primitive::Primitive;
|
||||
use pdf::primitive::{Dictionary, Primitive};
|
||||
use pdf::xref::XRef;
|
||||
use regex::Regex;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -223,7 +223,11 @@ fn get_contents(
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn get_stream_data(id: &str, path: &str, session: State<Mutex<Session>>) -> Result<String, String> {
|
||||
fn get_stream_data(
|
||||
id: &str,
|
||||
path: &str,
|
||||
session: State<Mutex<Session>>,
|
||||
) -> Result<Vec<u8>, String> {
|
||||
let session_guard = session
|
||||
.lock()
|
||||
.map_err(|_| "Failed to lock the session mutex.".to_string())?;
|
||||
@ -231,7 +235,7 @@ fn get_stream_data(id: &str, path: &str, session: State<Mutex<Session>>) -> Resu
|
||||
get_stream_data_by_path_with_file(path, &file.cos_file)
|
||||
}
|
||||
|
||||
fn get_stream_data_by_path_with_file(path: &str, file: &CosFile) -> Result<String, String> {
|
||||
fn get_stream_data_by_path_with_file(path: &str, file: &CosFile) -> Result<Vec<u8>, String> {
|
||||
let mut steps = Step::parse(path);
|
||||
if steps
|
||||
.pop_back()
|
||||
@ -247,7 +251,7 @@ fn get_stream_data_by_path_with_file(path: &str, file: &CosFile) -> Result<Strin
|
||||
};
|
||||
let resolver = file.resolver();
|
||||
let data = t!(t!(Stream::<Primitive>::from_stream(stream, &resolver)).data(&resolver));
|
||||
Ok(String::from_utf8_lossy(&data).into_owned())
|
||||
Ok(data.to_vec())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@ -563,7 +567,7 @@ impl PrimitiveModel {
|
||||
Primitive::Boolean(b) => b.to_string(),
|
||||
Primitive::String(s) => s.to_string_lossy(),
|
||||
Primitive::Stream(_) => "-".to_string(),
|
||||
Primitive::Dictionary(_) => "-".to_string(),
|
||||
Primitive::Dictionary(dict) => PrimitiveModel::format_dict_content(dict),
|
||||
Primitive::Array(arr) => PrimitiveModel::format_arr_content(arr),
|
||||
Primitive::Reference(pref) => {
|
||||
format!("Obj Nr: {} Gen Nr: {}", pref.id, pref.gen)
|
||||
@ -592,6 +596,26 @@ impl PrimitiveModel {
|
||||
}
|
||||
}
|
||||
|
||||
fn format_dict_content(dict: &Dictionary) -> String {
|
||||
let mut result = String::from("{");
|
||||
let mut count = 0;
|
||||
for (key, value) in dict.iter() {
|
||||
result.push_str(&format!(
|
||||
"{}: {}",
|
||||
key,
|
||||
PrimitiveModel::format_prim_short(value)
|
||||
));
|
||||
count += 1;
|
||||
if count < 4 {
|
||||
result.push_str(", ");
|
||||
} else {
|
||||
result.push_str(",...");
|
||||
break;
|
||||
}
|
||||
}
|
||||
result.push_str("}");
|
||||
result
|
||||
}
|
||||
fn format_arr_content(arr: &Vec<Primitive>) -> String {
|
||||
if arr.len() == 0 {
|
||||
return "[]".to_string();
|
||||
@ -600,14 +624,7 @@ impl PrimitiveModel {
|
||||
let contents = if arr.len() > 4 { &arr[0..4] } else { &arr[..] };
|
||||
for i in 0..contents.len() {
|
||||
let prim = contents.get(i).unwrap();
|
||||
result.push_str(&match prim {
|
||||
Primitive::Integer(i) => format!("{}", i),
|
||||
Primitive::Number(n) => format!("{}", n),
|
||||
Primitive::Boolean(b) => format!("{}", b),
|
||||
Primitive::String(s) => s.to_string().unwrap_or(String::from("-")),
|
||||
Primitive::Name(n) => n.as_str().to_string(),
|
||||
_ => prim.get_debug_name().to_string(),
|
||||
});
|
||||
result.push_str(&PrimitiveModel::format_prim_short(prim));
|
||||
if i != contents.len() - 1 {
|
||||
result.push_str(", ");
|
||||
}
|
||||
@ -620,6 +637,17 @@ impl PrimitiveModel {
|
||||
result
|
||||
}
|
||||
|
||||
fn format_prim_short(prim: &Primitive) -> String {
|
||||
match prim {
|
||||
Primitive::Integer(i) => format!("{}", i),
|
||||
Primitive::Number(n) => format!("{}", n),
|
||||
Primitive::Boolean(b) => format!("{}", b),
|
||||
Primitive::String(s) => s.to_string().unwrap_or(String::from("-")),
|
||||
Primitive::Name(n) => n.as_str().to_string(),
|
||||
_ => prim.get_debug_name().to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
fn from_primitive_with_children(
|
||||
primitive: &Primitive,
|
||||
trace: Vec<PathTrace>,
|
||||
|
||||
@ -66,22 +66,28 @@ mod tests {
|
||||
children: vec![TreeViewRequest {
|
||||
key: "1".to_string(),
|
||||
children: vec![],
|
||||
expand: true,
|
||||
}],
|
||||
expand: true,
|
||||
});
|
||||
path.push(TreeViewRequest {
|
||||
key: "Info".to_string(),
|
||||
children: vec![],
|
||||
expand: true,
|
||||
});
|
||||
path.push(TreeViewRequest {
|
||||
key: "Root".to_string(),
|
||||
children: vec![TreeViewRequest {
|
||||
key: "Pages".to_string(),
|
||||
children: vec![],
|
||||
expand: true,
|
||||
}],
|
||||
expand: true,
|
||||
});
|
||||
let root = TreeViewRequest {
|
||||
key: "Trailer".to_string(),
|
||||
children: path,
|
||||
expand: true,
|
||||
};
|
||||
|
||||
let message = format!("Retrieval of {:?}", root);
|
||||
|
||||
@ -22,18 +22,19 @@
|
||||
|
||||
let bodyHeight = $derived(height - headerOffset);
|
||||
let editorHeight = $derived(Math.max(800, bodyHeight - tableHeight));
|
||||
$inspect(fState.highlightedPrim);
|
||||
let imageUrl = "";
|
||||
|
||||
// Example: Simulating a binary Uint8Array (normally fetched from an API)
|
||||
let binaryData = new Uint8Array([fState.stream_data]);
|
||||
|
||||
if (binaryData.length > 0) {
|
||||
const blob = new Blob([binaryData], { type: "image/png" });
|
||||
imageUrl = URL.createObjectURL(blob);
|
||||
}
|
||||
function handlePrimSelect(prim: Primitive) {
|
||||
if (prim.isContainer()) {
|
||||
if (!prim) {
|
||||
fState.prim = prim;
|
||||
return;
|
||||
}
|
||||
const _path: string[] = fState.copyPath();
|
||||
_path.push(prim?.key);
|
||||
fState.selectPath(_path);
|
||||
}
|
||||
return;
|
||||
const _path: string[] = fState.copyPath();
|
||||
_path.push(prim?.key);
|
||||
fState.selectPath(_path);
|
||||
}
|
||||
|
||||
function handleScroll(event: Event & { currentTarget: HTMLElement }) {
|
||||
@ -45,6 +46,9 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if fState.stream_data}
|
||||
<img src={fState.stream_data} />
|
||||
{/if}
|
||||
{#if prim && prim.children && prim.children.length > 0}
|
||||
<div class="overflow-x-auto">
|
||||
<div class="w-[851px]">
|
||||
@ -72,10 +76,10 @@
|
||||
{#each entriesToDisplay as entry}
|
||||
<tr
|
||||
class:selected={entry.key ===
|
||||
fState.highlightedPrim?.key}
|
||||
fState.highlighted_prim}
|
||||
class="row"
|
||||
onclick={() =>
|
||||
(fState.highlightedPrim = entry)}
|
||||
(fState.highlighted_prim = entry.key)}
|
||||
ondblclick={() => handlePrimSelect(entry)}
|
||||
>
|
||||
<td class="page-cell t-data">
|
||||
@ -97,10 +101,9 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{#if fState.prim?.ptype === "Stream"}
|
||||
{#if fState.stream_data}
|
||||
<StreamEditor
|
||||
fileId={fState.file.id}
|
||||
path={fState.getMergedPath()}
|
||||
stream_data={fState.stream_data}
|
||||
height={editorHeight}
|
||||
></StreamEditor>
|
||||
{/if}
|
||||
|
||||
@ -4,11 +4,8 @@
|
||||
import { onMount } from "svelte";
|
||||
import * as monaco from "monaco-editor";
|
||||
|
||||
let {
|
||||
fileId,
|
||||
path,
|
||||
height,
|
||||
}: { fileId: string; path: string; height: number } = $props();
|
||||
let { stream_data, height }: { stream_data: string; height: number } =
|
||||
$props();
|
||||
|
||||
let contents: string | undefined = $state(undefined);
|
||||
let editorContainer: HTMLElement;
|
||||
@ -30,20 +27,13 @@
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
loadContents(path, fileId);
|
||||
loadContents(stream_data);
|
||||
});
|
||||
|
||||
function loadContents(path: string | undefined, id: string) {
|
||||
if (!path || !id) return;
|
||||
path = path + "/Data";
|
||||
invoke<string>("get_stream_data", { id, path })
|
||||
.then((result) => {
|
||||
contents = result;
|
||||
if (contents && editor) {
|
||||
editor.setValue(contents);
|
||||
}
|
||||
})
|
||||
.catch((err) => console.error(err));
|
||||
function loadContents(stream_data: string | undefined) {
|
||||
if (!stream_data || !editor) return;
|
||||
|
||||
editor.setValue(stream_data);
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@ -123,20 +123,22 @@
|
||||
<span class="no-caret"></span>
|
||||
{/if}
|
||||
</div>
|
||||
<PrimitiveIcon ptype={entry.ptype} />
|
||||
<p class="pl-1">
|
||||
<div>
|
||||
<PrimitiveIcon ptype={entry.ptype} />
|
||||
</div>
|
||||
<div class="pl-1 prim_name whitespace-nowrap">
|
||||
{formatDisplayKey(entry.key)}
|
||||
</p>
|
||||
<p
|
||||
class="details group-hover:text-forge-text_hint whitespace-nowrap"
|
||||
>
|
||||
{" | " +
|
||||
entry.value +
|
||||
" | " +
|
||||
entry.sub_type +
|
||||
" | " +
|
||||
entry.ptype}
|
||||
</p>
|
||||
<div
|
||||
class="details group-hover:text-forge-text_hint"
|
||||
>
|
||||
{" | " +
|
||||
entry.value +
|
||||
" | " +
|
||||
entry.sub_type +
|
||||
" | " +
|
||||
entry.ptype}
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
{/if}
|
||||
{/each}
|
||||
@ -145,6 +147,14 @@
|
||||
</div>
|
||||
|
||||
<style lang="postcss">
|
||||
.prim_name {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
position: relative;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
.item {
|
||||
@apply text-sm rounded-sm;
|
||||
text-align: center;
|
||||
@ -159,8 +169,8 @@
|
||||
}
|
||||
|
||||
.details {
|
||||
@apply ml-1 text-forge-prim text-xs whitespace-nowrap font-extralight;
|
||||
text-align: right;
|
||||
@apply ml-1 text-forge-prim whitespace-nowrap font-extralight;
|
||||
padding-top: 2px;
|
||||
}
|
||||
|
||||
.item {
|
||||
|
||||
@ -12,8 +12,9 @@ export default class FileViewState {
|
||||
public path: string[] = $state(["Trailer"]);
|
||||
public file: PdfFile;
|
||||
public prim: Primitive | undefined = $state();
|
||||
public highlightedPrim: Primitive | undefined = $state();
|
||||
public highlighted_prim: string | undefined = $state();
|
||||
public xref_entries: XRefEntry[] = $state([]);
|
||||
public stream_data: string | undefined = $state();
|
||||
|
||||
constructor(file: PdfFile) {
|
||||
|
||||
@ -38,8 +39,19 @@ export default class FileViewState {
|
||||
.catch(err => console.error(err));
|
||||
}
|
||||
|
||||
public selectPath(newPath: string[]) {
|
||||
invoke<Primitive>("get_prim_by_path", { id: this.file.id, path: this.mergePaths(newPath) })
|
||||
public async selectPath(newPath: string[]) {
|
||||
if (newPath.at(-1) === "Data") {
|
||||
let _path = newPath.slice(0, newPath.length - 1)
|
||||
const _prim = await invoke<Primitive>("get_prim_by_path", { id: this.file.id, path: this.formatPaths(_path) })
|
||||
this.stream_data = await invoke<string>("get_stream_data", { id: this.file.id, path: this.formatPaths(newPath) })
|
||||
this.prim = new Primitive(_prim);
|
||||
this.path = _path;
|
||||
this.highlighted_prim = "Data";
|
||||
return;
|
||||
} else {
|
||||
this.stream_data = undefined;
|
||||
}
|
||||
invoke<Primitive>("get_prim_by_path", { id: this.file.id, path: this.formatPaths(newPath) })
|
||||
.then(result => {
|
||||
let _prim = new Primitive(result)
|
||||
if (_prim.isContainer()) {
|
||||
@ -47,7 +59,7 @@ export default class FileViewState {
|
||||
this.path = newPath
|
||||
return;
|
||||
} else {
|
||||
this.highlightedPrim = _prim;
|
||||
this.highlighted_prim = _prim.key;
|
||||
this.selectPath(newPath.slice(0, newPath.length - 1))
|
||||
}
|
||||
})
|
||||
@ -63,7 +75,7 @@ export default class FileViewState {
|
||||
}
|
||||
|
||||
public getMergedPath() {
|
||||
return this.mergePaths(this.path);
|
||||
return this.formatPaths(this.path);
|
||||
}
|
||||
|
||||
public popPath() {
|
||||
@ -93,7 +105,7 @@ export default class FileViewState {
|
||||
}
|
||||
|
||||
|
||||
public mergePaths(paths: string[]) {
|
||||
public formatPaths(paths: string[]) {
|
||||
if (paths.length == 0) {
|
||||
return "/";
|
||||
}
|
||||
|
||||
@ -37,7 +37,6 @@ export default class TreeViewState {
|
||||
}
|
||||
i += 1;
|
||||
if (i >= end) {
|
||||
console.log("end", i, end);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@ -58,7 +57,6 @@ export default class TreeViewState {
|
||||
}
|
||||
i += 1;
|
||||
if (i >= end) {
|
||||
console.log("end", i, end);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@ -141,7 +139,6 @@ export default class TreeViewState {
|
||||
}
|
||||
|
||||
public async collapseTree(path: string[]) {
|
||||
console.log("collapseTree", path);
|
||||
if (path.length == 0) {
|
||||
console.error("Empty path");
|
||||
return;
|
||||
@ -153,7 +150,6 @@ export default class TreeViewState {
|
||||
}
|
||||
let node: TreeViewRequest | undefined = root;
|
||||
for (let key of path.slice(1, path.length)) {
|
||||
console.log("collapseTree", key);
|
||||
node = node?.getChild(key);
|
||||
}
|
||||
if (node) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user