How do you recursively zip up a directory using wxWidgets? I would like to place the resulting zip file right next to the target directory at the same level. The only input is simply one char string which contains the path of the directory to be zipped.
There's probably lots of ways to do this, but the most straightforward way might be to combine a wxDirTraverser and a wxZipOutputStream. Basically cutting and pasting from the samples in the docs, the derived traverser class could look something like:
class wxDirZipper : public wxDirTraverser
{
public:
wxDirZipper(const wxString& zip_filename, const wxString& folder)
{
wxFileName folder_to_zip_filename(folder);
folder_to_zip_filename.Normalize();
m_folder=folder_to_zip_filename.GetFullPath();
m_zip = new wxZipOutputStream(new wxFileOutputStream(zip_filename));
}
~wxDirZipper()
{
delete m_zip;
}
wxDirTraverseResult OnFile(const wxString& filename) wxOVERRIDE
{
wxFileInputStream fis(filename);
m_zip->PutNextEntry(Chop(filename));
m_zip->Write(fis);
return wxDIR_CONTINUE;
}
wxDirTraverseResult OnDir(const wxString& dirname) wxOVERRIDE
{
wxDir dir(dirname);
if( !dir.HasFiles() && !dir.HasSubDirs() )
{
m_zip->PutNextDirEntry(Chop(dirname));
}
return wxDIR_CONTINUE;
}
private:
wxString Chop(const wxString& filename) const
{
wxFileName fullpath(filename);
fullpath.Normalize();
wxString temp = fullpath.GetFullPath();
temp.Replace(m_folder,wxEmptyString);
return temp;
}
wxZipOutputStream* m_zip;
wxString m_folder;
};
You would then call this with something like:
wxString folder_to_zip = <whatever>
wxString zip_filename = folder_to_zip+".zip";
wxDirZipper zipper( zip_filename, folder_to_zip );
wxDir dir(folder_to_zip);
dir.Traverse(zipper);
This is a basic implementation, and there's lots of room for improvement. You could, for example check before overwriting the zip file or use wxZipEntry to set metadata for the entries.
Related
I am trying to overwrite a template file located in vendor/bolt/bolt/app/view/twig/editcontent/fields/_block.twig (I want to replace the "block selection" dropdown). Regarding to #1173, #1269, #5588, #3768 and #5102 this is not supported by default so I have to write a extension for this. So I tried this:
BackendBlockSelectionExtension:
namespace Bundle\Site;
use Bolt\Filesystem\Adapter\Local;
use Bolt\Filesystem\Filesystem;
use Silex\Application;
use Bolt\Extension\SimpleExtension;
class BackendBlockSelectionExtension extends SimpleExtension
{
public function getServiceProviders()
{
return [
$this,
new BackendBlockSelectionProvider(),
];
}
}
BackendBlockSelectionProvider:
namespace Bundle\Site;
use Bolt\Filesystem\Adapter\Local;
use Bolt\Filesystem\Filesystem;
use Silex\Application;
use Silex\ServiceProviderInterface;
class BackendBlockSelectionProvider implements ServiceProviderInterface
{
public function register(Application $app)
{
$side = $app['config']->getWhichEnd();
if ($side == 'backend') {
$path = __DIR__ . '/App/templates/Backend';
$filesystem = $app['filesystem'];
$filesystem->mountFilesystem('bolt', new Filesystem(new Local($path)));
$app['twig.loader.bolt_filesystem'] = $app->share(
$app->extend(
'twig.loader.bolt_filesystem',
function ($filesystem, $app) {
$path = __DIR__ . 'src/App/templates/Backend/';
$filesystem->prependPath($path, 'bolt');
return $filesystem;
}
)
);
}
}
public function boot(Application $app)
{
}
}
This seems to do the job, but I got an error I don't understand at all: The "bolt://app/theme_defaults" directory does not exist.
So my final question is: Does anyone have some example code how to overwrite/modify vendor/bolt/bolt/app/view/twig/editcontent/fields/_block.twig without touching the vendor folder?
This should be much simplier than this.
In your extension class overwrite protected function registerTwigPaths() function like this:
protected function registerTwigPaths()
{
if ($this->getEnd() == 'backend') {
return [
'view' => ['position' => 'prepend', 'namespace' => 'bolt']
];
}
return [];
}
private function getEnd()
{
$backendPrefix = $this->container['config']->get('general/branding/path');
$end = $this->container['config']->getWhichEnd();
switch ($end) {
case 'backend':
return 'backend';
case 'async':
// we have async request
// if the request begin with "/admin" (general/branding/path)
// it has been made on backend else somewhere else
$url = '/' . ltrim($_SERVER['REQUEST_URI'], $this->container['paths']['root']);
$adminUrl = '/' . trim($backendPrefix, '/');
if (strpos($url, $adminUrl) === 0) {
return 'backend';
}
default:
return $end;
}
}
Now you can crete a view directory in your extensions directory in which you can define templates in structure like in Bolt's default. I would start with copy and overwrite.
I want to remove a string from a QStringList (folders in the code below) if it is included in another string from the same list.
Example: "/tmp/a /tmp/b /tmp/a/aa /tmp/c /tmp/a/aa/aaa /tmp/d"
I want to remove the first and third string as they are included in the fifth.
I know how to do it with grep in bash, but how would I do it with Qt?
void MainWindow::on_toolButtonSourceFolders_clicked()
{
QString startDir = lineEditStartFolder->text();
QFileDialog* folderDialog = new QFileDialog(this);
folderDialog->setDirectory(lineEditStartFolder->text());
folderDialog->setFileMode(QFileDialog::Directory);
folderDialog->setOption(QFileDialog::DontUseNativeDialog, true);
folderDialog->setOption(QFileDialog::ShowDirsOnly, true);
folderDialog->setOption(QFileDialog::DontResolveSymlinks, true);
QListView *folderList = folderDialog->findChild<QListView*>("listView");
if (folderList) {
folderList->setSelectionMode(QAbstractItemView::MultiSelection);
}
QTreeView *folderTree = folderDialog->findChild<QTreeView*>();
if (folderTree) {
folderTree->setSelectionMode(QAbstractItemView::MultiSelection);
}
folderDialog->exec();
QStringList folders = folderDialog->selectedFiles();
if (!folders.isEmpty())
listWidget->addItems(folders);
}
The complete code is available at https://github.com/FluxFlux/qdir2mod
As indicated in the comments, since the maximum number of directories is 20, I would not bother optimizing the algorithm, hence I would just go with the simplest:
QStringList folders = folderDialog->selectedFiles();
QStringList outputFolders = folders;
foreach (const QString &folder, folders) {
foreach (const QString &f, folders) {
if (f.contains(folder))
outputFolders.removeOne(folder);
}
}
You could also avoid the temporary copy, but then again, it would make the code more complex which is not worth for 20 "folders".
Also, please note that "folder" is a GUI term. What you are referring to is files and directories which is more universal. It is better to use the proper term and not get stuck with GUI terms, only.
With a slight modification I've solved the problem:
QStringList folders = folderDialog->selectedFiles();
QStringList outputFolders = folders;
foreach (const QString &folder, folders) {
foreach (const QString &f, folders) {
const QString &cfolder = (folder + "/");
if (f.contains(cfolder))
outputFolders.removeOne(folder);
}
}
if (!outputFolders.isEmpty())
listWidget->addItems(outputFolders);
I have a Windows Phone application. I am using SharpZipLib to zip folders and its sub folders. This is zipping only the folder but the data inside the folders is not getting zipped. Can anyone guide me how to do this?
My code:
private void btnZip_Click(object sender, RoutedEventArgs e)
{
using (IsolatedStorageFile appStore = IsolatedStorageFile.GetUserStoreForApplication())
{
foreach (string filename in appStore.GetFileNames(directoryName + "/" + "*.txt"))
{
GetCompressedByteArray(filename);
}
textBlock2.Text = "Created file has Zipped Successfully";
}
}
public byte[] GetCompressedByteArray(string content)
{
byte[] compressedResult;
using (MemoryStream zippedMemoryStream = new MemoryStream())
{
using (ZipOutputStream zipOutputStream = new ZipOutputStream(zippedMemoryStream))
{
zipOutputStream.SetLevel(9);
byte[] buffer;
using (MemoryStream file = new MemoryStream(Encoding.UTF8.GetBytes(content)))
{
buffer = new byte[file.Length];
file.Read(buffer, 0, buffer.Length);
}
ZipEntry entry = new ZipEntry(content);
zipOutputStream.PutNextEntry(entry);
zipOutputStream.Write(buffer, 0, buffer.Length);
zipOutputStream.Finish();
}
compressedResult = zippedMemoryStream.ToArray();
}
WriteToIsolatedStorage(compressedResult);
return compressedResult;
}
public void WriteToIsolatedStorage(byte[] compressedBytes)
{
IsolatedStorageFile appStore = IsolatedStorageFile.GetUserStoreForApplication();
appStore.CreateDirectory(ZipFolder);
using (IsolatedStorageFileStream zipTemplateStream = new IsolatedStorageFileStream(ZipFolder+"/"+directoryName + ".zip", FileMode.OpenOrCreate, appStore))
using (BinaryWriter streamWriter = new BinaryWriter(zipTemplateStream))
{
streamWriter.Write(compressedBytes);
}
}
I think you'll find this guide helpful.
An excerpt from the above link
The ZipFile object provides a method called AddDirectory() that
accepts a parameter directoryName. The problem with this method is
that it doesn't add the files inside the specified directory but
instead just creates a directory inside the zip file. To make this
work, you need to get the files inside that directory by looping thru
all objects in that directory and adding them one at a time. I was
able to accomplish this task by creating a recursive function that
drills through the whole directory structure of the folder you want to
zip. Below is a snippet of the function.
I guess you too are facing the same problem where the folder is added to the zip file, but the contents and sub folders are not zipped.
Hope this helps.
Have a look over here for a code sample on how to use SharpZipLib to zip a root folder including nested folders.
I want to make the application where I can get all the images no matter whether it is in phone or in external memory. I want to import all that images in my application. How can it be possible? I came to know that it is possible through file connection. But not getting exact idea.
Get all the file system roots using FileSystemRegistry.listRoots()
Open connection to each root in turn using FileConnection fconn = (FileConnection)Connector.open(root)
List the folder using fconn.list().
For each entry in the list, if it ends with an image extension (file.getName().endsWith(".png") etc), then it's an image.
If the entry is a folder (file.isDirectory() returns true) then use fconn.setFileConnection(folder) to traverse into that directory/
Do the same recursively for all folders in all roots.
Here is a code snippet I once used for my application. It more or less does the same in funkybros steps.
protected void showFiles() {
if (path == null) {
Enumeration e = FileSystemRegistry.listRoots();
path = DATAHEAD; //DATAHEAD = file:///
setTitle(path);
while (e.hasMoreElements()) {
String root = (String) e.nextElement();
append(root, null);
}
myForm.getDisplay().setCurrent(this);
} else {
//this if-else just sets the title of the Listing Form
if (selectedItem != null) {
setTitle(path + selectedItem);
}
else {
setTitle(path);
}
try {
// works when users opens a directory, creates a connection to that directory
if (selectedItem != null) {
fileConncetion = (FileConnection) Connector.open(path + selectedItem, Connector.READ);
} else // works when presses 'Back' to go one level above/up
{
fileConncetion = (FileConnection) Connector.open(path, Connector.READ);
}
// Check if the selected item is a directory
if (fileConncetion.isDirectory()) {
if (selectedItem != null) {
path = path + selectedItem;
selectedItem = null;
}
//gathers the directory elements
Enumeration files = fileConncetion.list();
while (files.hasMoreElements()) {
String file = (String) files.nextElement();
append(file, null);
}
//
myForm.getDisplay().setCurrent(this);
try {
if (fileConncetion != null) {
fileConncetion.close();
fileConncetion = null;
}
} catch (IOException ex) {
ex.printStackTrace();
}
}//if (fileConncetion.isDirectory())
else {
System.out.println(path);
//if it gets a file then calls the publishToServer() method
myForm.publishToServer();
}
I'm making a service that among other has the "photo albums" feature that serve photos to users. User has to be "allowed" to see the photo from the album. So sending the direct link to other person shouldn't allow to view photo.
Photos are stored in the folder outside of the context.
What I need to do is to perform some checks when user requests the photo and then if checks are OK - serve the file. I want to avoid making a wheel and just let tomcat serve the image as it usually does for static files. Can you give some advice on that?
Ok, guys.
After struggling hard with this question I think I've finally found out what to do to solve it. First of all it looks like the question actually decomposes into two independent tasks. One of them is securing access to some resources and second one is feeding resources from the folder outside of the context.
First task is trivial and can be solved by writing a simple filter hanged to "/".
Second task is much less trivial but fortunately also can be resolved. Tomcat uses the implementation of javax.naming.directory.DirContext to load all resources of the given web application including class files. It also allows you to provide the custom implementation of this interface and configure it in the context.xml file. The default implementation is org.apache.naming.resources.FileDirContext. Details here: http://tomcat.apache.org/tomcat-6.0-doc/config/resources.html
I've created my own implementation of DirContext by simply extending FileDirContext. Luckily enough there was a single method that had to be overwritten in order to "hook up" file discovery. The method is called file().
I'm posting my test code here. It is far from perfect and does not take into account the corner cases like renaming files but I don't think that these are needed under a normal run of the server.
The basic idea under this code is to check if the path starts with "virtual directory" prefix and if it is - search for file in the other place in the filesystem (I know there is some duplicate code there but I hope you're not that lazy to remove it if you ever want to use it :-). setVirtualName and setVirtualBase are called automatically to inject the configuration params.
/**
* TODO: add javadocs
*
* #author Juriy Bura
*/
public class VirtualFolderDirContext extends FileDirContext {
private String virtualName;
private String realName;
private File virtualBase;
private String absoluteVirtualBase;
public VirtualFolderDirContext() {
super();
}
public VirtualFolderDirContext(Hashtable env) {
super(env);
}
public void setVirtualName(String path) {
virtualName = path;
}
public void setVirtualBase(String base) {
this.realName = base;
virtualBase = new File(realName);
try {
virtualBase = virtualBase.getCanonicalFile();
} catch (IOException e) {
// Ignore
}
this.absoluteVirtualBase = virtualBase.getAbsolutePath();
}
protected File file(String name) {
File file = null;
boolean virtualFile = name.startsWith(virtualName + "/");
if (virtualFile) {
file = new File(virtualBase, name.substring(virtualName.length()));
} else {
file = new File(base, name);
}
if (file.exists() && file.canRead()) {
if (allowLinking)
return file;
// Check that this file belongs to our root path
String canPath = null;
try {
canPath = file.getCanonicalPath();
} catch (IOException e) {
}
if (canPath == null)
return null;
// Check to see if going outside of the web application root
if (!canPath.startsWith(absoluteBase) && !canPath.startsWith(absoluteVirtualBase)) {
return null;
}
// Case sensitivity check
if (caseSensitive) {
String fileAbsPath = file.getAbsolutePath();
if (fileAbsPath.endsWith("."))
fileAbsPath = fileAbsPath + "/";
String absPath = normalize(fileAbsPath);
if (canPath != null)
canPath = normalize(canPath);
if (virtualFile) {
if ((absoluteVirtualBase.length() < absPath.length())
&& (absoluteVirtualBase.length() < canPath.length())) {
absPath = absPath.substring(absoluteVirtualBase.length() + 1);
if ((canPath == null) || (absPath == null))
return null;
if (absPath.equals(""))
absPath = "/";
canPath = canPath.substring(absoluteVirtualBase.length() + 1);
if (canPath.equals(""))
canPath = "/";
if (!canPath.equals(absPath))
return null;
}
} else {
if ((absoluteBase.length() < absPath.length())
&& (absoluteBase.length() < canPath.length())) {
absPath = absPath.substring(absoluteBase.length() + 1);
if ((canPath == null) || (absPath == null))
return null;
if (absPath.equals(""))
absPath = "/";
canPath = canPath.substring(absoluteBase.length() + 1);
if (canPath.equals(""))
canPath = "/";
if (!canPath.equals(absPath))
return null;
}
}
}
} else {
return null;
}
return file;
}
}
After you have this class in place you have to jar it and put that jar into the Tomcat lib folder. For obvious reasons it cannot go together with war file. In your context.xml you should add a config lines like these:
<?xml version="1.0" encoding="UTF-8"?>
<Context antiResourceLocking="true" antiJARLocking="true">
<Resources
className="com.juriy.tomcat.virtualdir.VirtualFolderDirContext"
virtualName="/upload"
virtualBase="c:/temp/up">
</Resources>
...
...
Now any time user asks for /upload/ it will be resolved to c:\temp. With this technique you can implement loading resources from virtually any location: http, shared folder, database, even version control system. So it is pretty cool.
P.S. I've killed the whole day to make this all work together so don't hesitate to give me your vote if you like the answer :-))
Cheers
Juriy