Spaces:
Sleeping
Sleeping
Commit
ยท
50a6f4d
1
Parent(s):
7068929
handle bytes extra
Browse files- compressedContentViewer.py +78 -66
compressedContentViewer.py
CHANGED
@@ -4,6 +4,7 @@ import xml.sax.saxutils
|
|
4 |
import html
|
5 |
import io
|
6 |
import xml.dom.minidom
|
|
|
7 |
|
8 |
# Initialize Panel with Bootstrap design
|
9 |
pn.extension(design="bootstrap", sizing_mode="stretch_width")
|
@@ -14,38 +15,44 @@ ICON_URLS = {
|
|
14 |
"message-circle": "https://discourse.holoviz.org/",
|
15 |
}
|
16 |
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
def decompress_CompressContent(data):
|
21 |
"""
|
22 |
-
|
23 |
-
|
24 |
-
:
|
|
|
25 |
"""
|
26 |
if data is None or not isinstance(data, bytes):
|
27 |
-
return ""
|
|
|
|
|
28 |
try:
|
29 |
dst = lz4.block.decompress(data, uncompressed_size=len(data) << 10)
|
30 |
decoded_string = dst.decode().replace("\x00", "") # Remove any null characters
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
37 |
|
38 |
def unescape_xml(text):
|
39 |
# First handle standard XML entities
|
40 |
text = xml.sax.saxutils.unescape(text)
|
41 |
-
|
42 |
# Then handle HTML entities that might be present
|
43 |
text = html.unescape(text)
|
44 |
-
|
45 |
return text
|
46 |
|
47 |
-
|
48 |
-
# Function to format XML with proper indentation using lxml
|
49 |
def format_xml(xml_string):
|
50 |
try:
|
51 |
# Parse the XML string
|
@@ -56,7 +63,6 @@ def format_xml(xml_string):
|
|
56 |
# If parsing fails, return the original string with the error
|
57 |
return f"XML formatting error: {str(e)}\n\nOriginal XML:\n{xml_string}"
|
58 |
|
59 |
-
|
60 |
# Create the UI with modern styling
|
61 |
file_input = pn.widgets.FileInput(
|
62 |
accept='.bin',
|
@@ -64,8 +70,13 @@ file_input = pn.widgets.FileInput(
|
|
64 |
sizing_mode="stretch_width"
|
65 |
)
|
66 |
|
|
|
|
|
|
|
|
|
|
|
67 |
status = pn.widgets.StaticText(
|
68 |
-
value="##### ๐ Upload a .bin file to
|
69 |
align="center"
|
70 |
)
|
71 |
|
@@ -86,19 +97,15 @@ unescape_checkbox = pn.widgets.Checkbox(
|
|
86 |
margin=(10, 10)
|
87 |
)
|
88 |
|
89 |
-
# Function to get the XML content for download
|
90 |
-
|
91 |
-
|
92 |
def get_xml_content():
|
93 |
if processed_xml:
|
94 |
return io.StringIO(processed_xml)
|
95 |
return None
|
96 |
|
97 |
-
|
98 |
# Modern styled download button
|
99 |
download_button = pn.widgets.FileDownload(
|
100 |
callback=get_xml_content,
|
101 |
-
filename="
|
102 |
button_type="primary",
|
103 |
label="๐ฅ Download XML",
|
104 |
disabled=True,
|
@@ -109,65 +116,69 @@ download_button = pn.widgets.FileDownload(
|
|
109 |
# Global variable to store the processed XML
|
110 |
processed_xml = None
|
111 |
|
112 |
-
# Connect the function to the file input
|
113 |
-
|
114 |
-
|
115 |
def process_file(event):
|
116 |
global processed_xml
|
117 |
if event.new is not None:
|
118 |
status.value = "##### โ๏ธ Processing file..."
|
|
|
|
|
119 |
try:
|
120 |
-
#
|
121 |
-
|
122 |
-
|
123 |
-
if
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
149 |
else:
|
150 |
-
|
151 |
-
|
152 |
download_button.disabled = True
|
153 |
processed_xml = None
|
154 |
except Exception as e:
|
155 |
status.value = f"##### โ Error: {str(e)}"
|
156 |
result_area.value = ""
|
|
|
157 |
download_button.disabled = True
|
158 |
processed_xml = None
|
159 |
|
160 |
-
|
161 |
file_input.param.watch(process_file, 'value')
|
162 |
|
163 |
-
# Add a callback for the checkbox to reprocess the current file when toggled
|
164 |
-
|
165 |
-
|
166 |
def toggle_unescape(event):
|
167 |
if file_input.value is not None:
|
168 |
process_file(pn.param.ParamEvent(obj=file_input, name='value', old=None, new=file_input.value))
|
169 |
|
170 |
-
|
171 |
unescape_checkbox.param.watch(toggle_unescape, 'value')
|
172 |
|
173 |
# Add footer with social links
|
@@ -183,13 +194,14 @@ main = pn.WidgetBox(
|
|
183 |
pn.Column(
|
184 |
pn.pane.Markdown("##### ๐ Drop your .bin file here or click to upload"),
|
185 |
file_input,
|
|
|
186 |
pn.Row(
|
187 |
unescape_checkbox,
|
188 |
download_button,
|
189 |
align="center"
|
190 |
),
|
191 |
status,
|
192 |
-
pn.pane.Markdown("##### ๐
|
193 |
result_area,
|
194 |
footer_row,
|
195 |
sizing_mode="stretch_width"
|
@@ -197,7 +209,7 @@ main = pn.WidgetBox(
|
|
197 |
)
|
198 |
|
199 |
# Create the template
|
200 |
-
title = "
|
201 |
template = pn.template.BootstrapTemplate(
|
202 |
title=title,
|
203 |
main=main,
|
|
|
4 |
import html
|
5 |
import io
|
6 |
import xml.dom.minidom
|
7 |
+
from wechatlog.adaptors.pywxdumpAdapter import decode_bytes_extra
|
8 |
|
9 |
# Initialize Panel with Bootstrap design
|
10 |
pn.extension(design="bootstrap", sizing_mode="stretch_width")
|
|
|
15 |
"message-circle": "https://discourse.holoviz.org/",
|
16 |
}
|
17 |
|
18 |
+
def process_content(data):
|
|
|
|
|
|
|
19 |
"""
|
20 |
+
Process both CompressContent and BytesExtra content.
|
21 |
+
First tries to decompress (for CompressContent), if fails treats as BytesExtra.
|
22 |
+
:param data: bytes data to process
|
23 |
+
:return: tuple (decoded_string, content_type, error_message)
|
24 |
"""
|
25 |
if data is None or not isinstance(data, bytes):
|
26 |
+
return "", "unknown", "Invalid input: data must be bytes"
|
27 |
+
|
28 |
+
# First try to decompress (assuming it's CompressContent)
|
29 |
try:
|
30 |
dst = lz4.block.decompress(data, uncompressed_size=len(data) << 10)
|
31 |
decoded_string = dst.decode().replace("\x00", "") # Remove any null characters
|
32 |
+
return decoded_string, "CompressContent", None
|
33 |
+
except Exception: # If decompression fails, try BytesExtra
|
34 |
+
try:
|
35 |
+
# Try to decode as BytesExtra
|
36 |
+
decoded_dict = decode_bytes_extra(data)
|
37 |
+
if isinstance(decoded_dict, dict):
|
38 |
+
# Convert dictionary to a formatted string representation
|
39 |
+
decoded_string = "{\n"
|
40 |
+
for key, value in decoded_dict.items():
|
41 |
+
decoded_string += f" {key}: {value}\n"
|
42 |
+
decoded_string += "}"
|
43 |
+
return decoded_string, "BytesExtra", None
|
44 |
+
else:
|
45 |
+
return "", "unknown", "BytesExtra decoding did not return a dictionary"
|
46 |
+
except Exception as decode_error:
|
47 |
+
return "", "unknown", f"Failed to process content: {str(decode_error)}"
|
48 |
|
49 |
def unescape_xml(text):
|
50 |
# First handle standard XML entities
|
51 |
text = xml.sax.saxutils.unescape(text)
|
|
|
52 |
# Then handle HTML entities that might be present
|
53 |
text = html.unescape(text)
|
|
|
54 |
return text
|
55 |
|
|
|
|
|
56 |
def format_xml(xml_string):
|
57 |
try:
|
58 |
# Parse the XML string
|
|
|
63 |
# If parsing fails, return the original string with the error
|
64 |
return f"XML formatting error: {str(e)}\n\nOriginal XML:\n{xml_string}"
|
65 |
|
|
|
66 |
# Create the UI with modern styling
|
67 |
file_input = pn.widgets.FileInput(
|
68 |
accept='.bin',
|
|
|
70 |
sizing_mode="stretch_width"
|
71 |
)
|
72 |
|
73 |
+
content_type_indicator = pn.widgets.StaticText(
|
74 |
+
value="",
|
75 |
+
align="center"
|
76 |
+
)
|
77 |
+
|
78 |
status = pn.widgets.StaticText(
|
79 |
+
value="##### ๐ Upload a .bin file to view its content",
|
80 |
align="center"
|
81 |
)
|
82 |
|
|
|
97 |
margin=(10, 10)
|
98 |
)
|
99 |
|
|
|
|
|
|
|
100 |
def get_xml_content():
|
101 |
if processed_xml:
|
102 |
return io.StringIO(processed_xml)
|
103 |
return None
|
104 |
|
|
|
105 |
# Modern styled download button
|
106 |
download_button = pn.widgets.FileDownload(
|
107 |
callback=get_xml_content,
|
108 |
+
filename="content.xml",
|
109 |
button_type="primary",
|
110 |
label="๐ฅ Download XML",
|
111 |
disabled=True,
|
|
|
116 |
# Global variable to store the processed XML
|
117 |
processed_xml = None
|
118 |
|
|
|
|
|
|
|
119 |
def process_file(event):
|
120 |
global processed_xml
|
121 |
if event.new is not None:
|
122 |
status.value = "##### โ๏ธ Processing file..."
|
123 |
+
content_type_indicator.value = ""
|
124 |
+
|
125 |
try:
|
126 |
+
# Process the content (either CompressContent or BytesExtra)
|
127 |
+
content, content_type, error = process_content(event.new)
|
128 |
+
|
129 |
+
if error:
|
130 |
+
status.value = f"##### โ {error}"
|
131 |
+
result_area.value = ""
|
132 |
+
content_type_indicator.value = ""
|
133 |
+
download_button.disabled = True
|
134 |
+
processed_xml = None
|
135 |
+
return
|
136 |
+
|
137 |
+
# Update content type indicator with icon
|
138 |
+
icon = "๐๏ธ" if content_type == "CompressContent" else "๐"
|
139 |
+
content_type_indicator.value = f"##### {icon} Detected type: {content_type}"
|
140 |
+
|
141 |
+
if content:
|
142 |
+
if content_type == "CompressContent":
|
143 |
+
try:
|
144 |
+
# Unescape XML entities if checkbox is checked
|
145 |
+
if unescape_checkbox.value:
|
146 |
+
content = unescape_xml(content)
|
147 |
+
|
148 |
+
# Format XML with proper indentation
|
149 |
+
pretty_content = format_xml(content)
|
150 |
+
result_area.value = pretty_content
|
151 |
+
processed_xml = pretty_content
|
152 |
+
download_button.filename = f"{file_input.filename.rsplit('.', 1)[0]}_xml.xml"
|
153 |
+
except Exception as xml_error:
|
154 |
+
result_area.value = content
|
155 |
+
processed_xml = content
|
156 |
+
status.value = f"##### โ ๏ธ Content extracted, but XML formatting failed: {str(xml_error)}"
|
157 |
+
else: # BytesExtra
|
158 |
+
result_area.value = content
|
159 |
+
processed_xml = content
|
160 |
+
download_button.filename = f"{file_input.filename.rsplit('.', 1)[0]}_dict.txt"
|
161 |
+
|
162 |
+
status.value = "##### โ
Content processed successfully!"
|
163 |
+
download_button.disabled = False
|
164 |
else:
|
165 |
+
status.value = "##### โ Processing failed"
|
166 |
+
result_area.value = ""
|
167 |
download_button.disabled = True
|
168 |
processed_xml = None
|
169 |
except Exception as e:
|
170 |
status.value = f"##### โ Error: {str(e)}"
|
171 |
result_area.value = ""
|
172 |
+
content_type_indicator.value = ""
|
173 |
download_button.disabled = True
|
174 |
processed_xml = None
|
175 |
|
|
|
176 |
file_input.param.watch(process_file, 'value')
|
177 |
|
|
|
|
|
|
|
178 |
def toggle_unescape(event):
|
179 |
if file_input.value is not None:
|
180 |
process_file(pn.param.ParamEvent(obj=file_input, name='value', old=None, new=file_input.value))
|
181 |
|
|
|
182 |
unescape_checkbox.param.watch(toggle_unescape, 'value')
|
183 |
|
184 |
# Add footer with social links
|
|
|
194 |
pn.Column(
|
195 |
pn.pane.Markdown("##### ๐ Drop your .bin file here or click to upload"),
|
196 |
file_input,
|
197 |
+
content_type_indicator,
|
198 |
pn.Row(
|
199 |
unescape_checkbox,
|
200 |
download_button,
|
201 |
align="center"
|
202 |
),
|
203 |
status,
|
204 |
+
pn.pane.Markdown("##### ๐ Content Preview"),
|
205 |
result_area,
|
206 |
footer_row,
|
207 |
sizing_mode="stretch_width"
|
|
|
209 |
)
|
210 |
|
211 |
# Create the template
|
212 |
+
title = "Content Viewer"
|
213 |
template = pn.template.BootstrapTemplate(
|
214 |
title=title,
|
215 |
main=main,
|