Skip to content

Instantly share code, notes, and snippets.

@RecursiveG
Created February 10, 2014 04:20
Show Gist options
  • Save RecursiveG/8910316 to your computer and use it in GitHub Desktop.
Save RecursiveG/8910316 to your computer and use it in GitHub Desktop.
#!/usr/bin/python3
from gi.repository import Gtk
import os
import zipfile
GLADE_STRING='''<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.16.1 -->
<interface>
<requires lib="gtk+" version="3.10"/>
<object class="GtkListStore" id="ZipContentList">
<columns>
<!-- column-name FileName -->
<column type="gchararray"/>
<!-- column-name FileSize -->
<column type="gchararray"/>
</columns>
</object>
<object class="GtkWindow" id="MainWindow">
<property name="can_focus">False</property>
<property name="title" translatable="yes">Nonstandard Encoded ZIP File Unpacker</property>
<signal name="delete-event" handler="onCloseWindow" swapped="no"/>
<child>
<object class="GtkBox" id="_box1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="margin_left">5</property>
<property name="margin_right">5</property>
<property name="margin_top">1</property>
<property name="margin_bottom">5</property>
<property name="orientation">vertical</property>
<property name="spacing">5</property>
<child>
<object class="GtkBox" id="_box2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">5</property>
<child>
<object class="GtkEntry" id="FilePathEntry">
<property name="visible">True</property>
<property name="can_focus">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="ChooseFileBtn">
<property name="label" translatable="yes">Choose File</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="on_ChooseFileBtn_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow" id="_scrolledwindow1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="shadow_type">in</property>
<property name="min_content_width">500</property>
<property name="min_content_height">300</property>
<child>
<object class="GtkTreeView" id="_MainFileList">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="model">ZipContentList</property>
<property name="headers_clickable">False</property>
<property name="enable_grid_lines">both</property>
<child internal-child="selection">
<object class="GtkTreeSelection" id="FileSelection">
<property name="mode">browse</property>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="_columnname">
<property name="min_width">400</property>
<property name="title" translatable="yes">File Name</property>
<child>
<object class="GtkCellRendererText" id="_cellrenderertext1"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="_columnsize">
<property name="title" translatable="yes">File Size</property>
<property name="expand">True</property>
<child>
<object class="GtkCellRendererText" id="_cellrenderertext2"/>
<attributes>
<attribute name="size">1</attribute>
<attribute name="text">1</attribute>
</attributes>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkBox" id="_box3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">5</property>
<child>
<object class="GtkComboBoxText" id="_comboboxtext1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="has_entry">True</property>
<items>
<item translatable="yes">ASCII</item>
<item translatable="yes">GBK</item>
<item translatable="yes">SHIFT-JIS</item>
<item translatable="yes">BIG5</item>
<item translatable="yes">UTF-8</item>
</items>
<signal name="changed" handler="on_comboboxtext1_changed" swapped="no"/>
<child internal-child="entry">
<object class="GtkEntry" id="EncodeSelectEntry">
<property name="can_focus">False</property>
<property name="text" translatable="yes">ASCII</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="ExtractAllBtn">
<property name="label" translatable="yes">Extract All</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="on_ExtractAllBtn_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="ExtractOneBtn">
<property name="label" translatable="yes">Extract Selected File</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="on_ExtractOneBtn_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
</object>
</interface>'''
class MyApplication():
def MessageBox(self,message):
dia=Gtk.Dialog("MessageBox",self.MainWindow,0,
(Gtk.STOCK_OK, Gtk.ResponseType.OK,))
dia.get_content_area().add(Gtk.Label(message))
dia.show_all()
res=dia.run()
dia.destroy()
def try_decode(self):
self.ZipContentList.clear()
try:
enc=self.EncodeSelectEntry.get_text()
for x in self.zf:
self.ZipContentList.append([x.decode(enc),str(self.zf[x])])
except UnicodeDecodeError:
self.MessageBox("Error when decoding. Try with another Encoding.")
def do_extract_file(self,pth,fname):
if (fname[-1]=="/") or (fname[-1]=="\\"):
return
folders=fname.split(os.path.sep)
folderpth=os.path.join(pth,os.path.sep.join(folders[:-1]))
if not os.path.isdir(folderpth):
os.makedirs(folderpth,0o755,exist_ok=True)
fullpth=os.path.join(pth,fname)
innerpth=fname.encode(self.EncodeSelectEntry.get_text()).decode('CP437')
f1=open(fullpth,"wb")
f1.write(self.z.read(innerpth))
f1.close()
def onCloseWindow(self,*args):
Gtk.main_quit()
def on_ChooseFileBtn_clicked(self,*args):
dialog=Gtk.FileChooserDialog("Select A ZIP file",self.MainWindow,
Gtk.FileChooserAction.OPEN,
(Gtk.STOCK_CANCEL,Gtk.ResponseType.CANCEL,
Gtk.STOCK_OPEN,Gtk.ResponseType.OK))
fi=Gtk.FileFilter()
fi.set_name("ZIP File")
fi.add_mime_type("application/zip")
dialog.add_filter(fi)
rsp=dialog.run()
if rsp!=Gtk.ResponseType.OK:
dialog.destroy()
return
pth=dialog.get_filename()
dialog.destroy()
self.FilePathEntry.set_text(pth)
self.z=zipfile.ZipFile(pth)
for i in self.z.infolist():
self.zf[i.filename.encode('CP437')]=i.file_size
self.try_decode()
def on_comboboxtext1_changed(self,*args):
self.try_decode()
def on_ExtractAllBtn_clicked(self,*args):
dialog=Gtk.FileChooserDialog("Select A Folder",self.MainWindow,
Gtk.FileChooserAction.SELECT_FOLDER,
(Gtk.STOCK_CANCEL,Gtk.ResponseType.CANCEL,
"Select",Gtk.ResponseType.OK))
rsp=dialog.run()
if rsp!=Gtk.ResponseType.OK:
dialog.destroy()
return
pth=dialog.get_filename()+"/"
dialog.destroy()
self.FilePathEntry.set_text("Extracting...")
for x in self.ZipContentList:
self.do_extract_file(pth,x[0])
self.FilePathEntry.set_text("Extract Finished.")
def on_ExtractOneBtn_clicked(self,*args):
model,treeiter=self.FileSelection.get_selected()
if treeiter==None:
self.MessageBox("Choose a file first")
return
fname=model[treeiter][0]
if fname[-1]=="/":
self.MessageBox("This is a Folder, not a File")
dialog=Gtk.FileChooserDialog("Select A Folder",self.MainWindow,
Gtk.FileChooserAction.SELECT_FOLDER,
(Gtk.STOCK_CANCEL,Gtk.ResponseType.CANCEL,
"Select",Gtk.ResponseType.OK))
rsp=dialog.run()
if rsp!=Gtk.ResponseType.OK:
dialog.destroy()
return
pth=dialog.get_filename()+"/"
dialog.destroy()
self.FilePathEntry.set_text("Extracting...")
self.do_extract_file(pth,fname)
self.FilePathEntry.set_text("Extract Finished.")
def _load(self):
handlers={
"onCloseWindow":self.onCloseWindow,
"on_ChooseFileBtn_clicked":self.on_ChooseFileBtn_clicked,
"on_comboboxtext1_changed":self.on_comboboxtext1_changed,
"on_ExtractAllBtn_clicked":self.on_ExtractAllBtn_clicked,
"on_ExtractOneBtn_clicked":self.on_ExtractOneBtn_clicked,
}
self.builder.connect_signals(handlers)
go=self.builder.get_object
self.ZipContentList=go("ZipContentList")
self.MainWindow=go("MainWindow")
self.FilePathEntry=go("FilePathEntry")
self.ChooseFileBtn=go("ChooseFileBtn")
self.FileSelection=go("FileSelection")
self.EncodeSelectEntry=go("EncodeSelectEntry")
self.ExtractAllBtn=go("ExtractAllBtn")
self.ExtractOneBtn=go("ExtractOneBtn")
def __init__(self):
self.builder=Gtk.Builder();
self.builder.add_from_string(GLADE_STRING)
self._load()
self.zf=dict()
def Start(self):
self.MainWindow.show_all()
Gtk.main()
if __name__=="__main__":
Application=MyApplication()
Application.Start()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment