various bugfixes and such.
also bookmarks, temp song loaderm and undo overhaul with near complete multiplayer, but menu items disabled. i really wish i could split this into multiple commits, but i don't know how to work unreal.
This commit is contained in:
squeaksies
2018-11-07 18:00:46 -08:00
parent ac6475494a
commit 7b6050b843
180 changed files with 3336 additions and 3301 deletions

17
Plugins/ZipUtility-ue4/.gitattributes vendored Normal file
View File

@@ -0,0 +1,17 @@
# Auto detect text files and perform LF normalization
* text=auto
# Custom for Visual Studio
*.cs diff=csharp
# Standard to msysgit
*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
*.DOCX diff=astextplain
*.dot diff=astextplain
*.DOT diff=astextplain
*.pdf diff=astextplain
*.PDF diff=astextplain
*.rtf diff=astextplain
*.RTF diff=astextplain

51
Plugins/ZipUtility-ue4/.gitignore vendored Normal file
View File

@@ -0,0 +1,51 @@
# Windows image file caches
Thumbs.db
ehthumbs.db
# Folder config file
Desktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
Binaries/*
# Windows Installer files
*.cab
*.msi
*.msm
*.msp
*.pdb
# Windows shortcuts
*.lnk
# =========================
# Operating System Files
# =========================
# OSX
# =========================
.DS_Store
.AppleDouble
.LSOverride
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
Intermediate
Binaries/Win64/UE4Editor-ZipUtility.dll

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

View File

@@ -0,0 +1,93 @@
ZipUtility and 7z-cpp Modifications placed under MIT
The MIT License (MIT)
(ZipUtility)
Copyright (c) Jan Kaniewski (Getnamo) and Contributors (https://github.com/getnamo/ZipUtility-ue4/graphs/contributors)
(7z-cpp)
Copyright (c) Jan Kaniewski (Getnamo), Keith J. Jones (keithjjones), and Contributors (https://github.com/getnamo/7zip-cpp/graphs/contributors)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
=============================================================================================
SevenZip++ (C++ wrapper) by Chadwick McNab is placed in the public domain. [https://bitbucket.org/cmcnab/sevenzip/wiki/Home]
=============================================================================================
LZMA SDK (LZMA 7-zip headers) is placed in the public domain. [www.7-zip.org/sdk.html]
=============================================================================================
This software uses code of 7z.dll licensed under the LGPL + unrar restriction version 2.1 and its source can be downloaded at www.7-zip.org
7-Zip
~~~~~
License for use and distribution
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7-Zip Copyright (C) 1999-2015 Igor Pavlov.
Licenses for files are:
1) 7z.dll: GNU LGPL + unRAR restriction
2) All other files: GNU LGPL
The GNU LGPL + unRAR restriction means that you must follow both
GNU LGPL rules and unRAR restriction rules.
Note:
You can use 7-Zip on any computer, including a computer in a commercial
organization. You don't need to register or pay for 7-Zip.
GNU LGPL information
--------------------
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You can receive a copy of the GNU Lesser General Public License from
http://www.gnu.org/
unRAR restriction
-----------------
The decompression engine for RAR archives was developed using source
code of unRAR program.
All copyrights to original unRAR code are owned by Alexander Roshal.
The license for original unRAR code has the following restriction:
The unRAR sources cannot be used to re-create the RAR compression algorithm,
which is proprietary. Distribution of modified unRAR sources in separate form
or as a part of other software is permitted, provided that it is clearly
stated in the documentation and source comments that the code may
not be used to develop a RAR (WinRAR) compatible archiver.
--
Igor Pavlov

View File

@@ -0,0 +1,246 @@
# ZipUtility Plugin
[![GitHub release](https://img.shields.io/github/release/getnamo/ziputility-ue4.svg)](https://github.com/getnamo/ziputility-ue4/releases)
[![Github All Releases](https://img.shields.io/github/downloads/getnamo/ziputility-ue4/total.svg)](https://github.com/getnamo/ziputility-ue4/releases)
Event driven, blueprint accessible flexible 7zip compression, archiver, and file manipulation plugin for Unreal Engine 4. Built on [7zip-cpp](https://github.com/getnamo/7zip-cpp) modernization of the [SevenZip++](http://bitbucket.org/cmcnab/sevenzip/wiki/Home) C++ wrapper for accessing the 7-zip COM-like API in 7z.dll and 7za.dll.
Supports the following compression algorithms:
7Zip, GZip, BZip2, RAR, TAR, ISO, CAB, LZMA, LZMA86.
Plugin works in Windows only.
[Main Forum Thread](https://forums.unrealengine.com/showthread.php?95022-Plugin-ZipUtility-(7zip))
## Quick Install & Setup ##
1. [Download](https://github.com/getnamo/ZipUtility-ue4/releases)
2. Create new or choose project.
3. Browse to your project folder (typically found at Documents/Unreal Project/{Your Project Root})
4. Copy *Plugins* folder into your Project root.
5. Restart the Editor and open your project again. Plugin is now ready to use.
## Blueprint Access
Right click anywhere in a desired blueprint to access the plugin Blueprint Function Library methods. The plugin is completely multi-threaded and will not block your game thread, fire and forget.
![Right Click](http://i.imgur.com/ERYn5sM.png)
*Optional but highly recommended:* Add `ZipUtilityInterface` to your blueprint if you wish to be notified of the progress, e.g. when your archive has finished unzipping or if you wish to display a progress bar.
![Add Interface](http://i.imgur.com/9NrpOfm.png)
After you've added the interface and hit Compile on your blueprint you'll have access to the Progress and List events
![Events](http://i.imgur.com/fQFtkgA.png)
They're explained in further detail below.
## Zipping and Compressing Files
To Zip up a folder or file, right click your event graph and add the `Zip` function.
Specify a path to a folder or file as a target.
Leave the Compression format to the default SevenZip or specify a format of choice, the plugin automatically appends the default extension based on the compression format. Note that not all compression formats work for compression (e.g. RAR is extract only).
![Zip Function Call](Docs/zip.png)
## Unzipping and Extracting Files
To Unzip up a file, right click your event graph and add the `Unzip` function.
Specify the full path to a suitable archive file.
The plugin automatically detects the compression format used in the archive, but you can alternatively specify a specific format using the `UnzipWithFormat` method.
![Unzip Function Call](Docs/unzip.png)
## Listing Contents in an Archive
To list files in your archive, right click your event graph and add the `ListFilesInArchive` function.
Specify the full path to a suitable archive file. This function requires the use of the `ZipUtilityInterface` callback `OnFileFound`, so ensure you have `ZipUtilityInterface` added to your blueprint.
![List Files Function Call](http://i.imgur.com/uqkI2Gn.png)
The `OnFileFound` event gets called for every file in the archive with its path and size given in bytes. This function does not extract the contents, but instead allows you to inspect files before committing to extracting their contents.
## Events & Progress Updates
By right-clicking in your blueprint and adding various `ZipUtility` events, you can get the status of zip/unzip operations as they occur. All callbacks are received on the game thread. To receive callbacks you must satisfy two requirements:
1. Implement the `ZipUtilityInterface` interface in your blueprint from the Class Settings menu
2. Pass a reference to `self` (or a reference to the class that implements `ZipUtilityInterface`) to all zip/unzip functions
All events pass along the name of the archive being operated on. Since multiple events can be running in parallel, the archive name is useful to uniquely match events with operations.
### Event Table
| Event | Details |
| ------------- | ------------- |
| `OnStartProcess` | Called when the zip/unzip operation begins |
| `OnProgress` | Called periodically while a zip/unzip operation is running to provide the overall status of the operation |
| `OnFileDone` | Called for every file that is done being zipped/unzipped |
| `OnDone` | Called when the entire zip/unzip operation has completed |
| `OnFileFound` | Called for every file that is found as the result of a `ListFilesInArchive` call |
![Progress Updates](Docs/event.png)
## Stopping Operations
Most of the Zip and Unzip methods return a pointer to a `ZipOperation`. This pointer can be used to terminate an operation that is still running by calling the `StopOperation` function.
The returned pointer to `ZipOperation` will be Garbage Collected if it is not stored as an Object Reference or in C++ in a `UPROPERTY` declared pointer. So don't store `ZipOperation` as a soft reference/pointer. It is safe to completely ignore the returned `ZipOperation` if you do not care about manually terminating the operation.
![Unzip Function Call](Docs/stopoperation.png)
## Convenience File Functions
### Move/Rename a File
Specify full path for the file you wish to move and it's destination
![Move File](http://i.imgur.com/aPu6gdJ.png)
To rename it, simply change the destination name
![Rename Folder](http://i.imgur.com/RICA41e.png)
### Create/Make Directory
![Make Directory](http://i.imgur.com/8ocCOPF.png)
### List Contents of Folder
Expects self to be a `FileListInterface`
![List Contents](http://i.imgur.com/PPhyxFE.png)
## C++
### Setup
To use the C++ code from the plugin add it as a dependency module in your project build.cs e.g.
```c#
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "ZipUtility"});
```
then ```#include "ZipFileFunctionLibrary.h"``` in the places where you'd like to use the plugin functionality.
### [Lambda](http://en.cppreference.com/w/cpp/language/lambda)
#### [UnzipWithLambda](https://github.com/getnamo/ZipUtility-ue4/blob/master/Source/ZipUtility/Public/ZipFileFunctionLibrary.h#L63)
call the static function with *done* and *progress* callback lambdas e.g. if you're interested in both
```c++
UZipFileFunctionLibrary::UnzipWithLambda(FString("C:/path/to/your/zip.7z"),
[]()
{
//Called when done
},
[](float Percent)
{
//called when progress updates with % done
});
```
replace either with nullptr if you're not interested in that callback
#### [ZipWithLambda](https://github.com/getnamo/ZipUtility-ue4/blob/master/Source/ZipUtility/Public/ZipFileFunctionLibrary.h#L80)
call the static function with *done* and *progress* callback lambdas e.g. if you're interested in both
```c++
UZipFileFunctionLibrary::ZipWithLambda(FString("C:/path/to/your/zip.7z"),
[]()
{
//Called when done
},
[](float Percent)
{
//called when progress updates with % done
});
```
replace either with nullptr if you're not interested in that callback
### Your own class with [IZipUtilityInterface](https://github.com/getnamo/ZipUtility-ue4/blob/master/Source/ZipUtility/Public/ZipUtilityInterface.h)
Let's say you have a class called `UMyClass`. You then add the `IZipUtilityInterface` to it via multiple inheritance e.g.
```c++
class UMyClass : public UObject, public IZipUtilityInterface
{
GENERATED_BODY()
...
};
```
Because the events are of the type [BlueprintNativeEvent](https://docs.unrealengine.com/latest/INT/Programming/UnrealArchitecture/Reference/Functions/Specifiers/BlueprintNativeEvent/) you add the C++ implementation of the events like so
```c++
class UMyClass : public UObject, public IZipUtilityInterface
{
GENERATED_BODY()
...
//event overrides
virtual void OnProgress_Implementation(const FString& archive, float percentage, int32 bytes) override;
virtual void OnDone_Implementation(const FString& archive, EZipUtilityCompletionState CompletionState) override;
virtual void OnStartProcess_Implementation(const FString& archive, int32 bytes) override;
virtual void OnFileDone_Implementation(const FString& archive, const FString& file) override;
virtual void OnFileFound_Implementation(const FString& archive, const FString& file, int32 size) override;
};
```
ensure you have at least an empty implementation for each function
```c++
void UMyClass::OnProgress_Implementation(const FString& archive, float percentage, int32 bytes)
{
//your code here
}
```
To call a `ZipUtility` function you first get a valid pointer to your class (I leave that up to you) e.g.
```c++
UMyClass* MyZipClass = NewObject<UMyClass>(); //or you may already have a valid pointer from allocating elsewhere
```
then to e.g. unzip you pass the pointer to your class with the `IZipUtilityInterface` as your second parameter (and if you use them, any other optional parameters such as compression format). If you are calling the zip functions from within the class that implements `IZipUtilityInterface` then you can simply pass `this`:
```c++
UZipFileFunctionLibrary::Unzip(FString("C:/path/to/your/zip.7z"), MyZipClass);
```
See [ZipFileFunctionLibrary.h](https://github.com/getnamo/ZipUtility-ue4/blob/master/Source/ZipUtility/Public/ZipFileFunctionLibrary.h) for all the function signatures.
See [ZULambdaDelegate.h](https://github.com/getnamo/ZipUtility-ue4/blob/master/Source/ZipUtility/Private/ZULambdaDelegate.h) for an example class using the above setup to convert `IZipUtilityInterface` interface calls into lambda functions.
### Windows Utility
For windows utility functions, the callback setup is similar, kindly refer to [WindowsFileUtilityFunctionLibrary.h](https://github.com/getnamo/ZipUtility-ue4/blob/master/Source/WindowsUtility/Public/WindowsFileUtilityFunctionLibrary.h) which may use [IWFUFileListInterface](https://github.com/getnamo/ZipUtility-ue4/blob/master/Source/WindowsUtility/Public/WFUFileListInterface.h) or [IWFUFolderWatchInterface](https://github.com/getnamo/ZipUtility-ue4/blob/master/Source/WindowsUtility/Public/WFUFolderWatchInterface.h) depending on functions used.
## License
MIT for ZipUtility and 7z-cpp
LGPL for 7za.dll, LGPL + Unrar for 7z.dll
See license file for details.
## Help
Add any issues you run across to https://github.com/getnamo/ZipUtility-ue4/issues
or post to the [unreal forum thread](https://forums.unrealengine.com/showthread.php?95022-Plugin-ZipUtility-(7zip)).

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

@@ -0,0 +1,11 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "WindowsFileUtilityPrivatePCH.h"
#include "WFUFileListInterface.h"
UWFUFileListInterface::UWFUFileListInterface(const class FObjectInitializer& PCIP)
: Super(PCIP)
{
}

View File

@@ -0,0 +1,32 @@
#include "WindowsFileUtilityPrivatePCH.h"
#include "WindowsFileUtilityFunctionLibrary.h"
#include "WFUFileListLambdaDelegate.h"
UWFUFileListLambdaDelegate::UWFUFileListLambdaDelegate()
{
OnDoneCallback = nullptr;
}
void UWFUFileListLambdaDelegate::SetOnDoneCallback(TFunction<void(const TArray<FString>&, const TArray<FString>&)> InOnDoneCallback)
{
OnDoneCallback = InOnDoneCallback;
}
void UWFUFileListLambdaDelegate::OnListFileFound_Implementation(const FString& FileName, int32 ByteCount, const FString& FilePath)
{
}
void UWFUFileListLambdaDelegate::OnListDirectoryFound_Implementation(const FString& DirectoryName, const FString& FilePath)
{
}
void UWFUFileListLambdaDelegate::OnListDone_Implementation(const FString& DirectoryPath, const TArray<FString>& Files, const TArray<FString>& Folders)
{
if (OnDoneCallback != nullptr)
{
OnDoneCallback(Files, Folders);
}
}

View File

@@ -0,0 +1,24 @@
#pragma once
#include "Object.h"
#include "WFUFileListLambdaDelegate.generated.h"
UCLASS()
class WINDOWSFILEUTILITY_API UWFUFileListLambdaDelegate : public UObject, public IWFUFileListInterface
{
GENERATED_BODY()
UWFUFileListLambdaDelegate();
public:
void SetOnDoneCallback(TFunction<void(const TArray<FString>&, const TArray<FString>&)> InOnDoneCallback);
protected:
//File List Interface
virtual void OnListFileFound_Implementation(const FString& FileName, int32 ByteCount, const FString& FilePath) override;
virtual void OnListDirectoryFound_Implementation(const FString& DirectoryName, const FString& FilePath) override;
virtual void OnListDone_Implementation(const FString& DirectoryPath, const TArray<FString>& Files, const TArray<FString>& Folders) override;
TFunction<void(const TArray<FString>&, const TArray<FString>&)> OnDoneCallback;
};

View File

@@ -0,0 +1,11 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "WindowsFileUtilityPrivatePCH.h"
#include "WFUFolderWatchInterface.h"
UWFUFolderWatchInterface::UWFUFolderWatchInterface(const class FObjectInitializer& PCIP)
: Super(PCIP)
{
}

View File

@@ -0,0 +1,32 @@
#include "WindowsFileUtilityPrivatePCH.h"
#include "WindowsFileUtilityFunctionLibrary.h"
#include "WFUFolderWatchLambdaDelegate.h"
UWFUFolderWatchLambdaDelegate::UWFUFolderWatchLambdaDelegate()
{
OnFileChangedCallback = nullptr;
}
void UWFUFolderWatchLambdaDelegate::SetOnFileChangedCallback(TFunction<void(FString, FString)> InOnFileChangedCallback)
{
OnFileChangedCallback = InOnFileChangedCallback;
}
void UWFUFolderWatchLambdaDelegate::OnFileChanged_Implementation(const FString& FileName, const FString& FilePath)
{
if (OnFileChangedCallback != nullptr)
{
OnFileChangedCallback(FileName, FilePath);
}
}
void UWFUFolderWatchLambdaDelegate::OnDirectoryChanged_Implementation(const FString& DirectoryName, const FString& DirectoryPath)
{
if (OnFileChangedCallback != nullptr)
{
OnFileChangedCallback(DirectoryName, DirectoryPath);
}
}

View File

@@ -0,0 +1,22 @@
#pragma once
#include "Object.h"
#include "WFUFolderWatchLambdaDelegate.generated.h"
UCLASS()
class WINDOWSFILEUTILITY_API UWFUFolderWatchLambdaDelegate : public UObject, public IWFUFolderWatchInterface
{
GENERATED_BODY()
UWFUFolderWatchLambdaDelegate();
public:
void SetOnFileChangedCallback(TFunction<void(FString, FString)> InOnFileChangedCallback);
protected:
TFunction<void(FString, FString)> OnFileChangedCallback;
//IWFUFolderWatchInterface
virtual void OnFileChanged_Implementation(const FString& FileName, const FString& FilePath) override;
virtual void OnDirectoryChanged_Implementation(const FString& DirectoryName, const FString& DirectoryPath) override;
};

View File

@@ -0,0 +1,100 @@
#pragma once
#include "WindowsFileUtilityPrivatePCH.h"
#include "WFULambdaRunnable.h"
uint64 WFULambdaRunnable::ThreadNumber = 0;
FQueuedThreadPool* WFULambdaRunnable::ThreadPool = nullptr;
WFULambdaRunnable::WFULambdaRunnable(TFunction< void()> InFunction)
{
FunctionPointer = InFunction;
FString threadStatGroup = FString::Printf(TEXT("FLambdaRunnable%d"), ThreadNumber++);
Thread = NULL;
Thread = FRunnableThread::Create(this, *threadStatGroup, 0, TPri_BelowNormal); //windows default = 8mb for thread, could specify more
}
WFULambdaRunnable::~WFULambdaRunnable()
{
if (Thread == NULL)
{
delete Thread;
Thread = NULL;
}
ThreadPool->Destroy();
}
//Run
uint32 WFULambdaRunnable::Run()
{
if (FunctionPointer)
FunctionPointer();
//UE_LOG(LogClass, Log, TEXT("FLambdaRunnable %d Run complete"), Number);
return 0;
}
void WFULambdaRunnable::Exit()
{
//UE_LOG(LogClass, Log, TEXT("FLambdaRunnable %d Exit"), Number);
//delete ourselves when we're done
delete this;
}
void WFULambdaRunnable::InitThreadPool(int32 NumberOfThreads)
{
if (ThreadPool == nullptr)
{
ThreadPool = FQueuedThreadPool::Allocate();
int32 NumThreadsInThreadPool = NumberOfThreads;
ThreadPool->Create(NumThreadsInThreadPool, 32 * 1024);
}
}
void WFULambdaRunnable::EnsureCompletion()
{
Thread->WaitForCompletion();
}
WFULambdaRunnable* WFULambdaRunnable::RunLambdaOnBackGroundThread(TFunction< void()> InFunction)
{
if (FPlatformProcess::SupportsMultithreading())
{
//UE_LOG(LogClass, Log, TEXT("FLambdaRunnable RunLambdaBackGroundThread"));
return new WFULambdaRunnable(InFunction);
}
return nullptr;
}
IQueuedWork* WFULambdaRunnable::AddLambdaToQueue(TFunction< void()> InFunction)
{
if (ThreadPool == nullptr)
{
WFULambdaRunnable::InitThreadPool(FPlatformMisc::NumberOfIOWorkerThreadsToSpawn());
}
if (ThreadPool)
{
return AsyncLambdaPool(*ThreadPool, InFunction);
}
return nullptr;
}
bool WFULambdaRunnable::RemoveLambdaFromQueue(IQueuedWork* Work)
{
if (ThreadPool)
{
return ThreadPool->RetractQueuedWork(Work);
}
return false;
}
FGraphEventRef WFULambdaRunnable::RunShortLambdaOnGameThread(TFunction< void()> InFunction)
{
return FFunctionGraphTask::CreateAndDispatchWhenReady(InFunction, TStatId(), nullptr, ENamedThreads::GameThread);
}

View File

@@ -0,0 +1,17 @@
#include "WindowsFileUtilityPrivatePCH.h"
class FWindowsFileUtility : public IWindowsFileUtility
{
/** IModuleInterface implementation */
virtual void StartupModule() override
{
}
virtual void ShutdownModule() override
{
}
};
IMPLEMENT_MODULE(IWindowsFileUtility, WindowsFileUtility)

View File

@@ -0,0 +1,414 @@
#include "WindowsFileUtilityPrivatePCH.h"
#include "WFUFolderWatchInterface.h"
#include "WFUFileListInterface.h"
#include "WindowsFileUtilityFunctionLibrary.h"
//static TMAP definition
TMap<FString, TArray<FWatcher>> UWindowsFileUtilityFunctionLibrary::Watchers = TMap<FString, TArray<FWatcher>>();
int TotalWatchers = 0;
UWindowsFileUtilityFunctionLibrary::UWindowsFileUtilityFunctionLibrary(const class FObjectInitializer& PCIP)
: Super(PCIP)
{
}
#if PLATFORM_WINDOWS
#include "AllowWindowsPlatformTypes.h"
#include <shellapi.h>
#include <Shlwapi.h>
#pragma comment(lib, "Shlwapi.lib")
bool UWindowsFileUtilityFunctionLibrary::DoesFileExist(const FString& FullPath)
{
return 0 != PathFileExistsW(*FullPath);
}
bool UWindowsFileUtilityFunctionLibrary::MoveFileTo(const FString& From, const FString& To)
{
//Using windows api
return 0 != MoveFileW(*From, *To);
}
bool UWindowsFileUtilityFunctionLibrary::CreateDirectoryAt(const FString& FullPath)
{
//Using windows api
return 0 != CreateDirectoryW(*FullPath, NULL);
}
bool UWindowsFileUtilityFunctionLibrary::DeleteFileAt(const FString& FullPath)
{
//Using windows api
return 0 != DeleteFileW(*FullPath);
}
bool UWindowsFileUtilityFunctionLibrary::DeleteEmptyFolder(const FString& FullPath)
{
//Using windows api
return 0 != RemoveDirectoryW(*FullPath);
}
bool IsSubPathOf(const FString& path, const FString& basePath)
{
return path.Contains(basePath);
}
//Dangerous function not recommended to be exposed to blueprint
bool UWindowsFileUtilityFunctionLibrary::DeleteFolderRecursively(const FString& FullPath)
{
//Only allow user to delete folders sub-class to game folder
if (!IsSubPathOf(FullPath, FPaths::ProjectDir()))
{
return false;
}
int len = _tcslen(*FullPath);
TCHAR *pszFrom = new TCHAR[len + 2];
wcscpy_s(pszFrom, len + 2, *FullPath);
pszFrom[len] = 0;
pszFrom[len + 1] = 0;
SHFILEOPSTRUCT fileop;
fileop.hwnd = NULL; // no status display
fileop.wFunc = FO_DELETE; // delete operation
fileop.pFrom = pszFrom; // source file name as double null terminated string
fileop.pTo = NULL; // no destination needed
fileop.fFlags = FOF_NOCONFIRMATION | FOF_SILENT; // do not prompt the user
fileop.fAnyOperationsAborted = FALSE;
fileop.lpszProgressTitle = NULL;
fileop.hNameMappings = NULL;
int ret = SHFileOperation(&fileop);
delete[] pszFrom;
return (ret == 0);
}
void UWindowsFileUtilityFunctionLibrary::WatchFolder(const FString& FullPath, UObject* WatcherDelegate)
{
//Do we have an entry for this path?
if (!Watchers.Contains(FullPath))
{
//Make an entry
TArray<FWatcher> FreshList;
Watchers.Add(FullPath, FreshList);
Watchers[FullPath] = FreshList;
}
else
{
//if we do do we already watch from this object?
TArray<FWatcher>& PathWatchers = Watchers[FullPath];
for (auto Watcher : PathWatchers)
{
if (Watcher.Delegate == WatcherDelegate)
{
//Already accounted for
UE_LOG(LogTemp, Warning, TEXT("UWindowsFileUtilityFunctionLibrary::WatchFolder Duplicate watcher ignored!"));
return;
}
}
}
//Add to watchers
FWatcher FreshWatcher;
FreshWatcher.Delegate = WatcherDelegate;
FreshWatcher.Path = FullPath;
const FWatcher* WatcherPtr = &FreshWatcher;
//fork this off to another process
WFULambdaRunnable* Runnable = WFULambdaRunnable::RunLambdaOnBackGroundThread([FullPath, WatcherDelegate, WatcherPtr]()
{
UWindowsFileUtilityFunctionLibrary::WatchFolderOnBgThread(FullPath, WatcherPtr);
});
FreshWatcher.Runnable = Runnable;
TArray<FWatcher>& PathWatchers = Watchers[FullPath];
PathWatchers.Add(FreshWatcher);
}
void UWindowsFileUtilityFunctionLibrary::StopWatchingFolder(const FString& FullPath, UObject* WatcherDelegate)
{
//Do we have an entry?
if (!Watchers.Contains(FullPath))
{
return;
}
//We have an entry for this path, remove our watcher
TArray<FWatcher> PathWatchers = Watchers[FullPath];
for (int i = 0; i < PathWatchers.Num();i++)
{
FWatcher& PathWatcher = PathWatchers[i];
if (PathWatcher.Delegate == WatcherDelegate)
{
//Stop the runnable
PathWatcher.ShouldRun = false;
PathWatcher.Runnable->Stop();
//Remove the watcher and we're done
PathWatchers.RemoveAt(i);
break;
}
}
}
void UWindowsFileUtilityFunctionLibrary::ListContentsOfFolder(const FString& FullPath, UObject* Delegate)
{
//Longer than max path? throw error
if (FullPath.Len() > MAX_PATH)
{
UE_LOG(LogTemp, Warning, TEXT("UWindowsFileUtilityFunctionLibrary::ListContentsOfFolder Error, path too long, listing aborted."));
return;
}
WFULambdaRunnable* Runnable = WFULambdaRunnable::RunLambdaOnBackGroundThread([&FullPath, Delegate]()
{
WIN32_FIND_DATA ffd;
LARGE_INTEGER filesize;
HANDLE hFind = INVALID_HANDLE_VALUE;
DWORD dwError = 0;
FString SearchPath = FullPath + TEXT("\\*");
hFind = FindFirstFile(*SearchPath, &ffd);
if (INVALID_HANDLE_VALUE == hFind)
{
UE_LOG(LogTemp, Warning, TEXT("UWindowsFileUtilityFunctionLibrary::ListContentsOfFolder Error, invalid handle, listing aborted."));
return;
}
//Arrays to hold full information on Done
TArray<FString> FileNames;
TArray<FString> FolderNames;
//List loop, callback on game thread
do
{
FString Name = FString(ffd.cFileName);
FString ItemPath = FullPath + TEXT("\\") + Name;
//UE_LOG(LogTemp, Log, TEXT("Name: <%s>"), *Name);
if (Name.Equals(FString(TEXT("."))) ||
Name.Equals(FString(TEXT(".."))) )
{
//ignore these first
}
//Folder
else if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
FolderNames.Add(Name);
WFULambdaRunnable::RunShortLambdaOnGameThread([Delegate, ItemPath, Name]
{
((IWFUFileListInterface*)Delegate)->Execute_OnListDirectoryFound((UObject*)Delegate, Name, ItemPath);
});
}
//File
else
{
FileNames.Add(Name);
filesize.LowPart = ffd.nFileSizeLow;
filesize.HighPart = ffd.nFileSizeHigh;
int32 TruncatedFileSize = filesize.QuadPart;
WFULambdaRunnable::RunShortLambdaOnGameThread([Delegate, ItemPath, Name, TruncatedFileSize]
{
((IWFUFileListInterface*)Delegate)->Execute_OnListFileFound((UObject*)Delegate, Name, TruncatedFileSize, ItemPath);
});
}
} while (FindNextFile(hFind, &ffd) != 0);
dwError = GetLastError();
if (dwError != ERROR_NO_MORE_FILES)
{
UE_LOG(LogTemp, Warning, TEXT("UWindowsFileUtilityFunctionLibrary::ListContentsOfFolder Error while listing."));
return;
}
FindClose(hFind);
//Done callback with full list of names found
WFULambdaRunnable::RunShortLambdaOnGameThread([Delegate, FullPath, FileNames, FolderNames]
{
((IWFUFileListInterface*)Delegate)->Execute_OnListDone((UObject*)Delegate, FullPath, FileNames, FolderNames);
});
});
}
void UWindowsFileUtilityFunctionLibrary::ListContentsOfFolderToCallback(const FString& FullPath, TFunction<void(const TArray<FString>&, const TArray<FString>&)> OnListCompleteCallback)
{
UWFUFileListLambdaDelegate* LambdaDelegate = NewObject<UWFUFileListLambdaDelegate>();
LambdaDelegate->SetOnDoneCallback(OnListCompleteCallback);
ListContentsOfFolder(FullPath, LambdaDelegate);
}
void UWindowsFileUtilityFunctionLibrary::WatchFolderOnBgThread(const FString& FullPath, const FWatcher* WatcherPtr)
{
//mostly from https://msdn.microsoft.com/en-us/library/windows/desktop/aa365261(v=vs.85).aspx
//call the delegate when the folder changes
//TODO: find out which file changed
DWORD dwWaitStatus;
HANDLE dwChangeHandles[2];
TCHAR lpDrive[4];
TCHAR lpFile[_MAX_FNAME];
TCHAR lpExt[_MAX_EXT];
//finding out about the notification
FILE_NOTIFY_INFORMATION strFileNotifyInfo[1024];
DWORD dwBytesReturned = 0;
_tsplitpath_s(*FullPath, lpDrive, 4, NULL, 0, lpFile, _MAX_FNAME, lpExt, _MAX_EXT);
lpDrive[2] = (TCHAR)'\\';
lpDrive[3] = (TCHAR)'\0';
// Watch the directory for file creation and deletion.
dwChangeHandles[0] = FindFirstChangeNotification(
*FullPath, // directory to watch
TRUE, // watch the subtree
FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE |
FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE// watch for generic file changes
); // watch last write or file size change
if (dwChangeHandles[0] == INVALID_HANDLE_VALUE)
{
UE_LOG(LogTemp, Warning, TEXT("\n ERROR: FindFirstChangeNotification function failed.\n"));
//ExitProcess(GetLastError());
}
// Watch the subtree for directory creation and deletion.
dwChangeHandles[1] = FindFirstChangeNotification(
lpDrive, // directory to watch
TRUE, // watch the subtree
FILE_NOTIFY_CHANGE_DIR_NAME); // watch dir name changes
if (dwChangeHandles[1] == INVALID_HANDLE_VALUE)
{
UE_LOG(LogTemp, Warning, TEXT("\n ERROR: FindFirstChangeNotification function failed.\n"));
//ExitProcess(GetLastError());
}
// Make a final validation check on our handles.
if ((dwChangeHandles[0] == NULL) || (dwChangeHandles[1] == NULL))
{
UE_LOG(LogTemp, Warning, TEXT("\n ERROR: Unexpected NULL from FindFirstChangeNotification.\n"));
//ExitProcess(GetLastError());
}
const FString DrivePath = FString(lpDrive);
FString FileString;
FString DirectoryString;
const UObject* WatcherDelegate = WatcherPtr->Delegate;
//Wait while the runnable pointer hasn't been set
TotalWatchers++;
UE_LOG(LogTemp, Log, TEXT("\nStarting Watcher loop %d...\n"), TotalWatchers);
while (WatcherPtr->ShouldRun) //Watcher.Runnable->Finished == false
{
// Wait for notification.
//UE_LOG(LogTemp, Log, TEXT("\nWaiting for notification...\n"));
dwWaitStatus = WaitForMultipleObjects(2, dwChangeHandles,
FALSE, INFINITE);
if (!WatcherPtr->ShouldRun)
{
UE_LOG(LogTemp, Log, TEXT("\nStop called while sleeping\n"));
break;
}
if (!WatcherDelegate->IsValidLowLevel())
{
UE_LOG(LogTemp, Warning, TEXT("\nInvalid Watcher Delegate, exiting watch\n"));
break;
}
switch (dwWaitStatus)
{
case WAIT_OBJECT_0:
ReadDirectoryChangesW(dwChangeHandles[0], (LPVOID)&strFileNotifyInfo, sizeof(strFileNotifyInfo), FALSE, FILE_NOTIFY_CHANGE_LAST_WRITE, &dwBytesReturned, NULL, NULL);
//UE_LOG(LogTemp, Warning, TEXT("Received info about: %s"), strFileNotifyInfo->FileName);
FileString = FString(strFileNotifyInfo[0].FileNameLength, strFileNotifyInfo[0].FileName);
// A file was created, renamed, or deleted in the directory.
// Refresh this directory and restart the notification.
WFULambdaRunnable::RunShortLambdaOnGameThread([FullPath, FileString, WatcherDelegate]()
{
if (WatcherDelegate->GetClass()->ImplementsInterface(UWFUFolderWatchInterface::StaticClass()))
{
FString FilePath = FString::Printf(TEXT("%s\\%s"), *FullPath, *FileString);
((IWFUFolderWatchInterface*)WatcherDelegate)->Execute_OnFileChanged((UObject*)WatcherDelegate, FileString, FilePath);
}
});
if (FindNextChangeNotification(dwChangeHandles[0]) == FALSE)
{
UE_LOG(LogTemp, Warning, TEXT("\n ERROR: FindNextChangeNotification function failed.\n"));
return;
}
break;
case WAIT_OBJECT_0 + 1:
// A directory was created, renamed, or deleted.
// Refresh the tree and restart the notification.
ReadDirectoryChangesW(dwChangeHandles[1], (LPVOID)&strFileNotifyInfo, sizeof(strFileNotifyInfo), FALSE, FILE_NOTIFY_CHANGE_LAST_WRITE, &dwBytesReturned, NULL, NULL);
DirectoryString = FString(strFileNotifyInfo[0].FileNameLength, strFileNotifyInfo[0].FileName);
WFULambdaRunnable::RunShortLambdaOnGameThread([FullPath, WatcherDelegate, DirectoryString]()
{
if (WatcherDelegate->GetClass()->ImplementsInterface(UWFUFolderWatchInterface::StaticClass()))
{
FString ChangedDirectoryPath = FString::Printf(TEXT("%s\\%s"), *FullPath, *DirectoryString);
((IWFUFolderWatchInterface*)WatcherDelegate)->Execute_OnDirectoryChanged((UObject*)WatcherDelegate, DirectoryString, ChangedDirectoryPath);
}
});
if (FindNextChangeNotification(dwChangeHandles[1]) == FALSE)
{
UE_LOG(LogTemp, Warning, TEXT("\n ERROR: FindNextChangeNotification function failed.\n"));
return;
}
break;
case WAIT_TIMEOUT:
// A timeout occurred, this would happen if some value other
// than INFINITE is used in the Wait call and no changes occur.
// In a single-threaded environment you might not want an
// INFINITE wait.
UE_LOG(LogTemp, Warning, TEXT("\nNo changes in the timeout period.\n"));
break;
default:
UE_LOG(LogTemp, Warning, TEXT("\n ERROR: Unhandled dwWaitStatus.\n"));
return;
break;
}
}
TotalWatchers--;
UE_LOG(LogTemp, Log, TEXT("\n Watcher loop stopped, total now: %d.\n"), TotalWatchers);
}
#include "HideWindowsPlatformTypes.h"
#endif

View File

@@ -0,0 +1,10 @@
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
#include "CoreMinimal.h"
#include "CoreUObject.h"
#include "EngineMinimal.h"
#include "IWindowsFileUtility.h"
#include "WFULambdaRunnable.h"
#include "WFUFileListInterface.h"
#include "WFUFolderWatchInterface.h"

View File

@@ -0,0 +1,36 @@
#pragma once
#include "ModuleManager.h"
/**
* The public interface to this module. In most cases, this interface is only public to sibling modules
* within this plugin.
*/
class IWindowsFileUtility : public IModuleInterface
{
public:
/**
* Singleton-like access to this module's interface. This is just for convenience!
* Beware of calling this during the shutdown phase, though. Your module might have been unloaded already.
*
* @return Returns singleton instance, loading the module on demand if needed
*/
static inline IWindowsFileUtility& Get()
{
return FModuleManager::LoadModuleChecked< IWindowsFileUtility >("WindowsFileUtility");
}
/**
* Checks to see if this module is loaded and ready. It is only valid to call Get() if IsAvailable() returns true.
*
* @return True if the module is loaded and ready to use
*/
static inline bool IsAvailable()
{
return FModuleManager::Get().IsModuleLoaded("WindowsFileUtility");
}
};

View File

@@ -0,0 +1,43 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "WFUFileListInterface.generated.h"
UINTERFACE(MinimalAPI)
class UWFUFileListInterface : public UInterface
{
GENERATED_UINTERFACE_BODY()
};
class WINDOWSFILEUTILITY_API IWFUFileListInterface
{
GENERATED_IINTERFACE_BODY()
public:
/**
* Called when a file has been found inside the folder of choice
* @param FileName of the found file.
* @param Size in bytes of the found file.
* @param FilePath of the file that was found
*/
UFUNCTION(BlueprintNativeEvent, Category = FolderWatchEvent)
void OnListFileFound(const FString& FileName, int32 ByteCount, const FString& FilePath);
/**
* Called when a directory has been found inside the folder of choice
* @param DirectoryName of the found directory.
* @param FilePath of the file that was found
*/
UFUNCTION(BlueprintNativeEvent, Category = FolderWatchEvent)
void OnListDirectoryFound(const FString& DirectoryName, const FString& FilePath);
/**
* Called when the listing operation has completed.
* @param DirectoryPath Path of the directory
* @param Files array of files found
*/
UFUNCTION(BlueprintNativeEvent, Category = FolderWatchEvent)
void OnListDone(const FString& DirectoryPath, const TArray<FString>& Files, const TArray<FString>& Folders);
};

View File

@@ -0,0 +1,32 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "WFUFolderWatchInterface.generated.h"
UINTERFACE(MinimalAPI)
class UWFUFolderWatchInterface : public UInterface
{
GENERATED_UINTERFACE_BODY()
};
class WINDOWSFILEUTILITY_API IWFUFolderWatchInterface
{
GENERATED_IINTERFACE_BODY()
public:
/**
* Called when a file inside the folder has changed
* @param FilePath Path of the file that has changed
*/
UFUNCTION(BlueprintNativeEvent, Category = FolderWatchEvent)
void OnFileChanged(const FString& FileName, const FString& FilePath);
/**
* Called when a directory inside the folder has changed
* @param FilePath Path of the file that has changed
*/
UFUNCTION(BlueprintNativeEvent, Category = FolderWatchEvent)
void OnDirectoryChanged(const FString& DirectoryName, const FString& DirectoryPath);
};

View File

@@ -0,0 +1,71 @@
// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
#pragma once
/*
Long duration lambda wrapper, which are generally not supported by the taskgraph system. New thread per lambda and they will auto-delete upon
completion.
*/
class WINDOWSFILEUTILITY_API WFULambdaRunnable : public FRunnable
{
private:
/** Thread to run the worker FRunnable on */
FRunnableThread* Thread;
// Used to give each thread a unique stat group
static uint64 ThreadNumber;
//Lambda function pointer
TFunction< void()> FunctionPointer;
// A queued threadpool used to run lambda's in the background. This has lazy initialization and is meant to be used with
// - AddLambdaToQueue
// - RemoveLAmbdaFromQueue
static FQueuedThreadPool* ThreadPool;
public:
//Constructor / Destructor
WFULambdaRunnable(TFunction< void()> InFunction);
virtual ~WFULambdaRunnable();
// Begin FRunnable interface.
virtual uint32 Run() override;
virtual void Exit() override;
// End FRunnable interface
// Initializes the queued thread pool. This is called lazily when the first task is added to the queue
// but can also be called by hand to initialize with a specific number of threads. The default number
// of threads is FPlatformMisc::NumberOfIOWorkerThreadsToSpawn() which last I checked was hard-coded
// at 4. <NOTE> that if you want to call this by hand, you need to do so before ever calling AddLambdaToQueue.
static void InitThreadPool(int32 NumberOfThreads);
/** Makes sure this thread has stopped properly */
void EnsureCompletion();
// Runs the passed lambda on the background thread, new thread per call
static WFULambdaRunnable* RunLambdaOnBackGroundThread(TFunction< void()> InFunction);
// Adds a lambda to be ran on the queued thread pool. Returns a pointer to IQueuedWork which
// can be used to later remove the queued job from the pool assuming it hasn't been processed.
static IQueuedWork* AddLambdaToQueue(TFunction< void()> InFunction);
// Removes a lambda from the thread queue
static bool RemoveLambdaFromQueue(IQueuedWork* Work);
// Runs a short lambda on the game thread via task graph system
static FGraphEventRef RunShortLambdaOnGameThread(TFunction< void()> InFunction);
private:
// This was yanked from Engine/Source/Runtime/Core/Public/Async/Async.h (originally called AsyncPool(..)). FQueuedThreadPool doesn't have
// much documentation, so using the engine code as reference, pretty much everyone seems to use this templated function to queue up work.
// It was modified to return an IQueuedWork instead of a TFuture to be more convenient for actually removing items from the queue.
template<typename ResultType>
static IQueuedWork* AsyncLambdaPool(FQueuedThreadPool& ThreadPool, TFunction<ResultType()> Function, TFunction<void()> CompletionCallback = TFunction<void()>())
{
TPromise<ResultType> Promise(MoveTemp(CompletionCallback));
TFuture<ResultType> Future = Promise.GetFuture();
IQueuedWork* Work = new TAsyncQueuedWork<ResultType>(MoveTemp(Function), MoveTemp(Promise));
ThreadPool.AddQueuedWork(Work);
return Work;
}
};

View File

@@ -0,0 +1,74 @@
#pragma once
#include "WFULambdaRunnable.h"
#include "WindowsFileUtilityFunctionLibrary.generated.h"
//Struct to Track which delegate is watching files
struct FWatcher
{
UObject* Delegate;
FString Path;
WFULambdaRunnable* Runnable = nullptr;
FThreadSafeBool ShouldRun = true;
};
inline bool operator==(const FWatcher& lhs, const FWatcher& rhs)
{
return lhs.Delegate == rhs.Delegate;
}
UCLASS(ClassGroup = WindowsFileUtility, Blueprintable)
class WINDOWSFILEUTILITY_API UWindowsFileUtilityFunctionLibrary : public UBlueprintFunctionLibrary
{
GENERATED_UCLASS_BODY()
UFUNCTION(BlueprintCallable, Category = WindowsFileUtility)
static bool DoesFileExist(const FString& FullPath);
/*Expects full path including name. you can use this function to rename files.*/
UFUNCTION(BlueprintCallable, Category = WindowsFileUtility)
static bool MoveFileTo(const FString& From, const FString& To);
/*Expects full path including folder name.*/
UFUNCTION(BlueprintCallable, Category = WindowsFileUtility)
static bool CreateDirectoryAt(const FString& FullPath);
/*Deletes file (not directory). Expects full path.*/
UFUNCTION(BlueprintCallable, Category = WindowsFileUtility)
static bool DeleteFileAt(const FString& FullPath);
/*Deletes empty folders only. Expects full path.*/
UFUNCTION(BlueprintCallable, Category = WindowsFileUtility)
static bool DeleteEmptyFolder(const FString& FullPath);
/*Dangerous function, not exposed to blueprint. */
UFUNCTION(BlueprintCallable, Category = WindowsFileUtility)
static bool DeleteFolderRecursively(const FString& FullPath);
/** Watch a folder for change. WatcherDelegate should respond to FolderWatchInterface*/
UFUNCTION(BlueprintCallable, Category = WindowsFileUtility)
static void WatchFolder(const FString& FullPath, UObject* WatcherDelegate);
/** Stop watching a folder for change. WatcherDelegate should respond to FolderWatchInterface*/
UFUNCTION(BlueprintCallable, Category = WindowsFileUtility)
static void StopWatchingFolder(const FString& FullPath, UObject* WatcherDelegate);
/** List the contents, expects UFileListInterface*/
UFUNCTION(BlueprintCallable, Category = WindowsFileUtility)
static void ListContentsOfFolder(const FString& FullPath, UObject* ListDelegate);
//Convenience C++ callback
static void ListContentsOfFolderToCallback(const FString& FullPath, TFunction<void(const TArray<FString>&, const TArray<FString>&)> OnListCompleteCallback);
//Todo: add watch folder with threadsafe boolean passthrough
//static void ListContentsOfFolderToCallback(const FString& FullPath, TFunction<void(const TArray<FString>&, const TArray<FString>&)> OnListCompleteCallback);
private:
static void WatchFolderOnBgThread(const FString& FullPath, const FWatcher* Watcher);
static TMap<FString, TArray<FWatcher>> Watchers;
};

View File

@@ -0,0 +1,51 @@
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
using UnrealBuildTool;
using System.IO;
public class WindowsFileUtility : ModuleRules
{
public WindowsFileUtility(ReadOnlyTargetRules Target) : base(Target)
{
PublicIncludePaths.AddRange(
new string[] {
"WindowsFileUtility/Public"
// ... add public include paths required here ...
}
);
PrivateIncludePaths.AddRange(
new string[] {
"WindowsFileUtility/Private",
// ... add other private include paths required here ...
}
);
PublicDependencyModuleNames.AddRange(
new string[]
{
"Core",
// ... add other public dependencies that you statically link with here ...
}
);
PrivateDependencyModuleNames.AddRange(
new string[]
{
"CoreUObject",
"Engine",
// ... add private dependencies that you statically link with here ...
}
);
DynamicallyLoadedModuleNames.AddRange(
new string[]
{
// ... add any modules that your module loads dynamically here ...
}
);
}
}

View File

@@ -0,0 +1,100 @@
#include "ZipUtilityPrivatePCH.h"
#include "ZipFileFunctionLibrary.h"
#include "SevenZipCallbackHandler.h"
void SevenZipCallbackHandler::OnProgress(const TString& archivePath, uint64 bytes)
{
const UObject* interfaceDelegate = ProgressDelegate;
const uint64 bytesConst = bytes;
const FString pathConst = FString(archivePath.c_str());
if (bytes > 0) {
const float ProgressPercentage = ((double)((TotalBytes)-(BytesLeft - bytes)) / (double)TotalBytes) * 100;
UZipFileFunctionLibrary::RunLambdaOnGameThread([interfaceDelegate, pathConst, ProgressPercentage, bytesConst]
{
//UE_LOG(LogClass, Log, TEXT("Progress: %d bytes"), progress);
((IZipUtilityInterface*)interfaceDelegate)->Execute_OnProgress((UObject*)interfaceDelegate, pathConst, ProgressPercentage, bytesConst);
});
}
}
void SevenZipCallbackHandler::OnDone(const TString& archivePath)
{
const UObject* interfaceDelegate = ProgressDelegate;
const FString pathConst = FString(archivePath.c_str());
UZipFileFunctionLibrary::RunLambdaOnGameThread([pathConst, interfaceDelegate]
{
//UE_LOG(LogClass, Log, TEXT("All Done!"));
((IZipUtilityInterface*)interfaceDelegate)->Execute_OnDone((UObject*)interfaceDelegate, pathConst, EZipUtilityCompletionState::SUCCESS);
});
}
void SevenZipCallbackHandler::OnFileDone(const TString& archivePath, const TString& filePath, uint64 bytes)
{
const UObject* interfaceDelegate = ProgressDelegate;
const FString pathConst = FString(archivePath.c_str());
const FString filePathConst = FString(filePath.c_str());
const uint64 bytesConst = bytes;
UZipFileFunctionLibrary::RunLambdaOnGameThread([interfaceDelegate, pathConst, filePathConst, bytesConst]
{
//UE_LOG(LogClass, Log, TEXT("File Done: %s, %d bytes"), filePathConst.c_str(), bytesConst);
((IZipUtilityInterface*)interfaceDelegate)->Execute_OnFileDone((UObject*)interfaceDelegate, pathConst, filePathConst);
});
//Handle byte decrementing
if (bytes > 0) {
BytesLeft -= bytes;
const float ProgressPercentage = ((double)(TotalBytes - BytesLeft) / (double)TotalBytes) * 100;
UZipFileFunctionLibrary::RunLambdaOnGameThread([interfaceDelegate, pathConst, ProgressPercentage, bytes]
{
//UE_LOG(LogClass, Log, TEXT("Progress: %d bytes"), progress);
((IZipUtilityInterface*)interfaceDelegate)->Execute_OnProgress((UObject*)interfaceDelegate, pathConst, ProgressPercentage, bytes);
});
}
}
void SevenZipCallbackHandler::OnStartWithTotal(const TString& archivePath, unsigned __int64 totalBytes)
{
TotalBytes = totalBytes;
BytesLeft = TotalBytes;
const UObject* interfaceDelegate = ProgressDelegate;
const uint64 bytesConst = TotalBytes;
const FString pathConst = FString(archivePath.c_str());
UZipFileFunctionLibrary::RunLambdaOnGameThread([interfaceDelegate, pathConst, bytesConst]
{
//UE_LOG(LogClass, Log, TEXT("Starting with %d bytes"), bytesConst);
((IZipUtilityInterface*)interfaceDelegate)->Execute_OnStartProcess((UObject*)interfaceDelegate, pathConst, bytesConst);
});
}
void SevenZipCallbackHandler::OnFileFound(const TString& archivePath, const TString& filePath, int size)
{
const UObject* interfaceDelegate = ProgressDelegate;
const uint64 bytesConst = TotalBytes;
const FString pathString = FString(archivePath.c_str());
const FString fileString = FString(filePath.c_str());
UZipFileFunctionLibrary::RunLambdaOnGameThread([interfaceDelegate, pathString, fileString, bytesConst]
{
((IZipUtilityInterface*)interfaceDelegate)->Execute_OnFileFound((UObject*)interfaceDelegate, pathString, fileString, bytesConst);
});
}
void SevenZipCallbackHandler::OnListingDone(const TString& archivePath)
{
const UObject* interfaceDelegate = ProgressDelegate;
const FString pathString = FString(archivePath.c_str());
UZipFileFunctionLibrary::RunLambdaOnGameThread([interfaceDelegate, pathString]
{
((IZipUtilityInterface*)interfaceDelegate)->Execute_OnDone((UObject*)interfaceDelegate, pathString, EZipUtilityCompletionState::SUCCESS);
});
}
bool SevenZipCallbackHandler::OnCheckBreak()
{
return bCancelOperation;
}

View File

@@ -0,0 +1,53 @@
#include "ZipUtilityPrivatePCH.h"
#include "WindowsFileUtilityFunctionLibrary.h"
#include "ZipFileFunctionLibrary.h"
#include "ZULambdaDelegate.h"
UZULambdaDelegate::UZULambdaDelegate()
{
OnDoneCallback = nullptr;
OnProgressCallback = nullptr;
}
void UZULambdaDelegate::SetOnDoneCallback(TFunction<void()> InOnDoneCallback)
{
OnDoneCallback = InOnDoneCallback;
}
void UZULambdaDelegate::SetOnProgessCallback(TFunction<void(float)> InOnProgressCallback)
{
OnProgressCallback = InOnProgressCallback;
}
void UZULambdaDelegate::OnProgress_Implementation(const FString& archive, float percentage, int32 bytes)
{
if (OnProgressCallback != nullptr)
{
OnProgressCallback(percentage);
}
}
void UZULambdaDelegate::OnDone_Implementation(const FString& archive, EZipUtilityCompletionState CompletionState)
{
if (OnDoneCallback != nullptr)
{
OnDoneCallback();
}
}
void UZULambdaDelegate::OnStartProcess_Implementation(const FString& archive, int32 bytes)
{
}
void UZULambdaDelegate::OnFileDone_Implementation(const FString& archive, const FString& file)
{
}
void UZULambdaDelegate::OnFileFound_Implementation(const FString& archive, const FString& file, int32 size)
{
}

View File

@@ -0,0 +1,27 @@
#pragma once
#include "Object.h"
#include "ZULambdaDelegate.generated.h"
UCLASS()
class ZIPUTILITY_API UZULambdaDelegate : public UObject, public IZipUtilityInterface
{
GENERATED_BODY()
UZULambdaDelegate();
public:
void SetOnDoneCallback(TFunction<void()> InOnDoneCallback);
void SetOnProgessCallback(TFunction<void(float)> InOnProgressCallback);
protected:
//Zip utility interface
virtual void OnProgress_Implementation(const FString& archive, float percentage, int32 bytes) override;
virtual void OnDone_Implementation(const FString& archive, EZipUtilityCompletionState CompletionState) override;
virtual void OnStartProcess_Implementation(const FString& archive, int32 bytes) override;
virtual void OnFileDone_Implementation(const FString& archive, const FString& file) override;
virtual void OnFileFound_Implementation(const FString& archive, const FString& file, int32 size) override;
TFunction<void()> OnDoneCallback;
TFunction<void(float)> OnProgressCallback;
};

View File

@@ -0,0 +1,51 @@
#include "ZipUtilityPrivatePCH.h"
#include "ZipFileFunctionInternalCallback.h"
UZipFileFunctionInternalCallback::UZipFileFunctionInternalCallback()
{
CompressionFormat = ZipUtilityCompressionFormat::COMPRESSION_FORMAT_UNKNOWN;
DestinationFolder = FString();
File = FString();
FileIndex = 0;
Callback = NULL;
}
void UZipFileFunctionInternalCallback::OnFileFound_Implementation(const FString& archive, const FString& fileIn, int32 size)
{
if (!bFileFound && fileIn.ToLower().Contains(File.ToLower()))
{
TArray<int32> FileIndices = { FileIndex };
if (bUnzipto)
{
UZipFileFunctionLibrary::UnzipFilesTo(FileIndices, archive, DestinationFolder, Callback, CompressionFormat);
}
else
{
UZipFileFunctionLibrary::UnzipFiles(FileIndices, archive, Callback, CompressionFormat);
}
if (bSingleFile)
{
bFileFound = true;
}
}
FileIndex++;
}
void UZipFileFunctionInternalCallback::SetCallback(const FString& FileName, UObject* CallbackIn, TEnumAsByte<ZipUtilityCompressionFormat> CompressionFormatIn /*= ZipUtilityCompressionFormat::COMPRESSION_FORMAT_UNKNOWN*/)
{
File = FileName;
Callback = CallbackIn;
CompressionFormat = CompressionFormatIn;
FileIndex = 0;
}
void UZipFileFunctionInternalCallback::SetCallback(const FString& FileName, const FString& DestinationFolderIn, UObject* CallbackIn, TEnumAsByte<ZipUtilityCompressionFormat> CompressionFormatIn /*= ZipUtilityCompressionFormat::COMPRESSION_FORMAT_UNKNOWN*/)
{
SetCallback(FileName, CallbackIn, CompressionFormatIn);
bUnzipto = true;
DestinationFolder = DestinationFolderIn;
}

View File

@@ -0,0 +1,65 @@
#pragma once
#include "ZipUtilityInterface.h"
#include "ZipFileFunctionInternalCallback.generated.h"
/**
* This is used to provide a callback for unzipping single files, it ends up getting called from the ListFiles lambda.
*/
UCLASS(ClassGroup = ZipUtility)
class ZIPUTILITY_API UZipFileFunctionInternalCallback : public UObject, public IZipUtilityInterface
{
GENERATED_BODY()
private:
/** Compression format used to unzip */
UPROPERTY(Transient)
TEnumAsByte<ZipUtilityCompressionFormat> CompressionFormat;
/** Path of the file */
UPROPERTY(Transient)
FString File;
UPROPERTY(Transient)
FString DestinationFolder;
/** Current File index parsed */
UPROPERTY(Transient)
int32 FileIndex = 0;
/** Callback object */
UPROPERTY(Transient)
UObject* Callback;
UPROPERTY(Transient)
bool bSingleFile;
UPROPERTY(Transient)
bool bFileFound;
UPROPERTY(Transient)
bool bUnzipto;
public:
UZipFileFunctionInternalCallback();
//IZipUtilityInterface overrides
virtual void OnProgress_Implementation(const FString& archive, float percentage, int32 bytes) override {};
virtual void OnDone_Implementation(const FString& archive, EZipUtilityCompletionState CompletionState) override {};
virtual void OnStartProcess_Implementation(const FString& archive, int32 bytes) override {};
virtual void OnFileDone_Implementation(const FString& archive, const FString& file) override {
UE_LOG(LogTemp, Log, TEXT("OnFileDone_Implementation"));
};
virtual void OnFileFound_Implementation(const FString& archive, const FString& fileIn, int32 size) override;
void SetCallback(const FString& FileName, UObject* CallbackIn, TEnumAsByte<ZipUtilityCompressionFormat> CompressionFormatIn = ZipUtilityCompressionFormat::COMPRESSION_FORMAT_UNKNOWN);
void SetCallback(const FString& FileName, const FString& DestinationFolder, UObject* CallbackIn, TEnumAsByte<ZipUtilityCompressionFormat> CompressionFormatIn = ZipUtilityCompressionFormat::COMPRESSION_FORMAT_UNKNOWN);
FORCEINLINE bool GetSingleFile() const { return bSingleFile; }
FORCEINLINE void SetSingleFile(bool val) { bSingleFile = val; }
};

View File

@@ -0,0 +1,481 @@
#include "ZipUtilityPrivatePCH.h"
#include "ZipFileFunctionLibrary.h"
#include "ZipFileFunctionInternalCallback.h"
#include "ListCallback.h"
#include "ProgressCallback.h"
#include "IPluginManager.h"
#include "WFULambdaRunnable.h"
#include "ZULambdaDelegate.h"
#include "SevenZipCallbackHandler.h"
#include "WindowsFileUtilityFunctionLibrary.h"
#include "7zpp.h"
using namespace SevenZip;
//Private Namespace
namespace{
//Threaded Lambda convenience wrappers - Task graph is only suitable for short duration lambdas, but doesn't incur thread overhead
FGraphEventRef RunLambdaOnAnyThread(TFunction< void()> InFunction)
{
return FFunctionGraphTask::CreateAndDispatchWhenReady(InFunction, TStatId(), nullptr, ENamedThreads::AnyThread);
}
//Uses proper threading, for any task that may run longer than about 2 seconds.
void RunLongLambdaOnAnyThread(TFunction< void()> InFunction)
{
WFULambdaRunnable::RunLambdaOnBackGroundThread(InFunction);
}
// Run the lambda on the queued threadpool
IQueuedWork* RunLambdaOnThreadPool(TFunction< void()> InFunction)
{
return WFULambdaRunnable::AddLambdaToQueue(InFunction);
}
//Private static vars
SevenZipLibrary SZLib;
//Utility functions
FString PluginRootFolder()
{
return IPluginManager::Get().FindPlugin("ZipUtility")->GetBaseDir();
//return FPaths::ConvertRelativePathToFull(FPaths::GameDir());
}
FString DLLPath()
{
#if _WIN64
FString PlatformString = FString(TEXT("Win64"));
#else
FString PlatformString = FString(TEXT("Win32"));
#endif
//Swap these to change which license you wish to fall under for zip-utility
FString DLLString = FString("7z.dll"); //Using 7z.dll: GNU LGPL + unRAR restriction
//FString dllString = FString("7za.dll"); //Using 7za.dll: GNU LGPL license, crucially doesn't support .zip out of the box
return FPaths::ConvertRelativePathToFull(FPaths::Combine(*PluginRootFolder(), TEXT("ThirdParty/7zpp/dll"), *PlatformString, *DLLString));
}
FString ReversePathSlashes(FString forwardPath)
{
return forwardPath.Replace(TEXT("/"), TEXT("\\"));
}
bool IsValidDirectory(FString& Directory, FString& FileName, const FString& Path)
{
bool Found = Path.Split(TEXT("/"), &Directory, &FileName, ESearchCase::IgnoreCase, ESearchDir::FromEnd);
//try a back split
if (!Found)
{
Found = Path.Split(TEXT("\\"), &Directory, &FileName, ESearchCase::IgnoreCase, ESearchDir::FromEnd);
}
//No valid Directory found
if (!Found)
return false;
else
return true;
}
SevenZip::CompressionLevelEnum libZipLevelFromUELevel(ZipUtilityCompressionLevel ueLevel) {
switch (ueLevel)
{
case COMPRESSION_LEVEL_NONE:
return SevenZip::CompressionLevel::None;
case COMPRESSION_LEVEL_FAST:
return SevenZip::CompressionLevel::Fast;
case COMPRESSION_LEVEL_NORMAL:
return SevenZip::CompressionLevel::Normal;
default:
return SevenZip::CompressionLevel::None;
}
}
SevenZip::CompressionFormatEnum libZipFormatFromUEFormat(ZipUtilityCompressionFormat UeFormat) {
switch (UeFormat)
{
case COMPRESSION_FORMAT_UNKNOWN:
return CompressionFormat::Unknown;
case COMPRESSION_FORMAT_SEVEN_ZIP:
return CompressionFormat::SevenZip;
case COMPRESSION_FORMAT_ZIP:
return CompressionFormat::Zip;
case COMPRESSION_FORMAT_GZIP:
return CompressionFormat::GZip;
case COMPRESSION_FORMAT_BZIP2:
return CompressionFormat::BZip2;
case COMPRESSION_FORMAT_RAR:
return CompressionFormat::Rar;
case COMPRESSION_FORMAT_TAR:
return CompressionFormat::Tar;
case COMPRESSION_FORMAT_ISO:
return CompressionFormat::Iso;
case COMPRESSION_FORMAT_CAB:
return CompressionFormat::Cab;
case COMPRESSION_FORMAT_LZMA:
return CompressionFormat::Lzma;
case COMPRESSION_FORMAT_LZMA86:
return CompressionFormat::Lzma86;
default:
return CompressionFormat::Unknown;
}
}
FString defaultExtensionFromUEFormat(ZipUtilityCompressionFormat ueFormat)
{
switch (ueFormat)
{
case COMPRESSION_FORMAT_UNKNOWN:
return FString(TEXT(".dat"));
case COMPRESSION_FORMAT_SEVEN_ZIP:
return FString(TEXT(".7z"));
case COMPRESSION_FORMAT_ZIP:
return FString(TEXT(".zip"));
case COMPRESSION_FORMAT_GZIP:
return FString(TEXT(".gz"));
case COMPRESSION_FORMAT_BZIP2:
return FString(TEXT(".bz2"));
case COMPRESSION_FORMAT_RAR:
return FString(TEXT(".rar"));
case COMPRESSION_FORMAT_TAR:
return FString(TEXT(".tar"));
case COMPRESSION_FORMAT_ISO:
return FString(TEXT(".iso"));
case COMPRESSION_FORMAT_CAB:
return FString(TEXT(".cab"));
case COMPRESSION_FORMAT_LZMA:
return FString(TEXT(".lzma"));
case COMPRESSION_FORMAT_LZMA86:
return FString(TEXT(".lzma86"));
default:
return FString(TEXT(".dat"));
}
}
using namespace std;
//Background Thread convenience functions
UZipOperation* UnzipFilesOnBGThreadWithFormat(const TArray<int32> FileIndices, const FString& ArchivePath, const FString& DestinationDirectory, const UObject* ProgressDelegate, ZipUtilityCompressionFormat Format)
{
UZipOperation* ZipOperation = NewObject<UZipOperation>();
IQueuedWork* Work = RunLambdaOnThreadPool([ProgressDelegate, FileIndices, ArchivePath, DestinationDirectory, Format, ZipOperation]
{
SevenZipCallbackHandler PrivateCallback;
PrivateCallback.ProgressDelegate = (UObject*)ProgressDelegate;
ZipOperation->SetCallbackHandler(&PrivateCallback);
//UE_LOG(LogClass, Log, TEXT("path is: %s"), *path);
SevenZipExtractor Extractor(SZLib, *ArchivePath);
if (Format == COMPRESSION_FORMAT_UNKNOWN)
{
if (!Extractor.DetectCompressionFormat())
{
UE_LOG(LogTemp, Log, TEXT("auto-compression detection did not succeed, passing in unknown format to 7zip library."));
}
}
else
{
Extractor.SetCompressionFormat(libZipFormatFromUEFormat(Format));
}
// Extract indices
const int32 NumberFiles = FileIndices.Num();
unsigned int* Indices = new unsigned int[NumberFiles];
for (int32 idx = 0; idx < NumberFiles; idx++)
{
Indices[idx] = FileIndices[idx];
}
// Perform the extraction
Extractor.ExtractFilesFromArchive(Indices, NumberFiles, *DestinationDirectory, &PrivateCallback);
// Clean up the indices
delete Indices;
// Null out the callback handler now that we're exiting
ZipOperation->SetCallbackHandler(nullptr);
});
ZipOperation->SetThreadPoolWorker(Work);
return ZipOperation;
}
//Background Thread convenience functions
UZipOperation* UnzipOnBGThreadWithFormat(const FString& ArchivePath, const FString& DestinationDirectory, const UObject* ProgressDelegate, ZipUtilityCompressionFormat Format)
{
UZipOperation* ZipOperation = NewObject<UZipOperation>();
IQueuedWork* Work = RunLambdaOnThreadPool([ProgressDelegate, ArchivePath, DestinationDirectory, Format, ZipOperation]
{
SevenZipCallbackHandler PrivateCallback;
PrivateCallback.ProgressDelegate = (UObject*)ProgressDelegate;
ZipOperation->SetCallbackHandler(&PrivateCallback);
//UE_LOG(LogClass, Log, TEXT("path is: %s"), *path);
SevenZipExtractor Extractor(SZLib, *ArchivePath);
if (Format == COMPRESSION_FORMAT_UNKNOWN)
{
if (!Extractor.DetectCompressionFormat())
{
UE_LOG(LogTemp, Log, TEXT("auto-compression detection did not succeed, passing in unknown format to 7zip library."));
}
}
else
{
Extractor.SetCompressionFormat(libZipFormatFromUEFormat(Format));
}
Extractor.ExtractArchive(*DestinationDirectory, &PrivateCallback);
// Null out the callback handler now that we're exiting
ZipOperation->SetCallbackHandler(nullptr);
});
ZipOperation->SetThreadPoolWorker(Work);
return ZipOperation;
}
void ListOnBGThread(const FString& Path, const FString& Directory, const UObject* ListDelegate, ZipUtilityCompressionFormat Format)
{
//RunLongLambdaOnAnyThread - this shouldn't take long, but if it lags, swap the lambda methods
RunLambdaOnAnyThread([ListDelegate, Path, Format, Directory] {
SevenZipCallbackHandler PrivateCallback;
PrivateCallback.ProgressDelegate = (UObject*)ListDelegate;
SevenZipLister Lister(SZLib, *Path);
if (Format == COMPRESSION_FORMAT_UNKNOWN)
{
if (!Lister.DetectCompressionFormat())
{
UE_LOG(LogTemp, Log, TEXT("auto-compression detection did not succeed, passing in unknown format to 7zip library."));
}
}
else
{
Lister.SetCompressionFormat(libZipFormatFromUEFormat(Format));
}
if (!Lister.ListArchive(&PrivateCallback))
{
// If ListArchive returned false, it was most likely because the compression format was unsupported
// Call OnDone with a failure message, make sure to call this on the game thread.
if (IZipUtilityInterface* ZipInterface = Cast<IZipUtilityInterface>((UObject*)ListDelegate))
{
UE_LOG(LogClass, Warning, TEXT("ZipUtility: Unknown failure for list operation on %s"), *Path);
UZipFileFunctionLibrary::RunLambdaOnGameThread([ZipInterface, ListDelegate, Path]
{
ZipInterface->Execute_OnDone((UObject*)ListDelegate, *Path, EZipUtilityCompletionState::FAILURE_UNKNOWN);
});
}
}
});
}
UZipOperation* ZipOnBGThread(const FString& Path, const FString& FileName, const FString& Directory, const UObject* ProgressDelegate, ZipUtilityCompressionFormat UeCompressionformat, ZipUtilityCompressionLevel UeCompressionlevel)
{
UZipOperation* ZipOperation = NewObject<UZipOperation>();
IQueuedWork* Work = RunLambdaOnThreadPool([ProgressDelegate, FileName, Path, UeCompressionformat, UeCompressionlevel, Directory, ZipOperation]
{
SevenZipCallbackHandler PrivateCallback;
PrivateCallback.ProgressDelegate = (UObject*)ProgressDelegate;
ZipOperation->SetCallbackHandler(&PrivateCallback);
//Set the zip format
ZipUtilityCompressionFormat UeFormat = UeCompressionformat;
if (UeFormat == COMPRESSION_FORMAT_UNKNOWN)
{
UeFormat = COMPRESSION_FORMAT_ZIP;
}
//Disallow creating .rar archives as per unrar restriction, this won't work anyway so redirect to 7z
else if (UeFormat == COMPRESSION_FORMAT_RAR)
{
UE_LOG(LogClass, Warning, TEXT("ZipUtility: Rar compression not supported for creating archives, re-targeting as 7z."));
UeFormat = COMPRESSION_FORMAT_SEVEN_ZIP;
}
//concatenate the output filename
FString OutputFileName = FString::Printf(TEXT("%s/%s%s"), *Directory, *FileName, *defaultExtensionFromUEFormat(UeFormat));
//UE_LOG(LogClass, Log, TEXT("\noutputfile is: <%s>\n path is: <%s>"), *outputFileName, *path);
SevenZipCompressor compressor(SZLib, *ReversePathSlashes(OutputFileName));
compressor.SetCompressionFormat(libZipFormatFromUEFormat(UeFormat));
compressor.SetCompressionLevel(libZipLevelFromUELevel(UeCompressionlevel));
if (PathIsDirectory(*Path))
{
//UE_LOG(LogClass, Log, TEXT("Compressing Folder"));
compressor.CompressDirectory(*ReversePathSlashes(Path), &PrivateCallback);
}
else
{
//UE_LOG(LogClass, Log, TEXT("Compressing File"));
compressor.CompressFile(*ReversePathSlashes(Path), &PrivateCallback);
}
// Null out the callback handler
ZipOperation->SetCallbackHandler(nullptr);
//Todo: expand to support zipping up contents of current folder
//compressor.CompressFiles(*ReversePathSlashes(path), TEXT("*"), &PrivateCallback);
});
ZipOperation->SetThreadPoolWorker(Work);
return ZipOperation;
}
}//End private namespace
UZipFileFunctionLibrary::UZipFileFunctionLibrary(const class FObjectInitializer& PCIP)
: Super(PCIP)
{
UE_LOG(LogTemp, Log, TEXT("DLLPath is: %s"), *DLLPath());
SZLib.Load(*DLLPath());
}
UZipFileFunctionLibrary::~UZipFileFunctionLibrary()
{
SZLib.Free();
}
bool UZipFileFunctionLibrary::UnzipFileNamed(const FString& archivePath, const FString& Name, UObject* ZipUtilityInterfaceDelegate, ZipUtilityCompressionFormat format /*= COMPRESSION_FORMAT_UNKNOWN*/)
{
UZipFileFunctionInternalCallback* InternalCallback = NewObject<UZipFileFunctionInternalCallback>();
InternalCallback->SetFlags(RF_MarkAsRootSet);
InternalCallback->SetCallback(Name, ZipUtilityInterfaceDelegate, format);
ListFilesInArchive(archivePath, InternalCallback, format);
return true;
}
bool UZipFileFunctionLibrary::UnzipFileNamedTo(const FString& archivePath, const FString& Name, const FString& destinationPath, UObject* ZipUtilityInterfaceDelegate, ZipUtilityCompressionFormat format /*= COMPRESSION_FORMAT_UNKNOWN*/)
{
UZipFileFunctionInternalCallback* InternalCallback = NewObject<UZipFileFunctionInternalCallback>();
InternalCallback->SetFlags(RF_MarkAsRootSet);
InternalCallback->SetCallback(Name, destinationPath, ZipUtilityInterfaceDelegate, format);
ListFilesInArchive(archivePath, InternalCallback, format);
return true;
}
UZipOperation* UZipFileFunctionLibrary::UnzipFilesTo(const TArray<int32> fileIndices, const FString & archivePath, const FString & destinationPath, UObject * ZipUtilityInterfaceDelegate, ZipUtilityCompressionFormat format)
{
return UnzipFilesOnBGThreadWithFormat(fileIndices, archivePath, destinationPath, ZipUtilityInterfaceDelegate, format);
}
UZipOperation* UZipFileFunctionLibrary::UnzipFiles(const TArray<int32> fileIndices, const FString & ArchivePath, UObject * ZipUtilityInterfaceDelegate, ZipUtilityCompressionFormat format)
{
FString Directory;
FString FileName;
//Check Directory validity
if (!IsValidDirectory(Directory, FileName, ArchivePath))
{
return nullptr;
}
if (fileIndices.Num() == 0)
{
return nullptr;
}
return UnzipFilesTo(fileIndices, ArchivePath, Directory, ZipUtilityInterfaceDelegate, format);
}
UZipOperation* UZipFileFunctionLibrary::Unzip(const FString& ArchivePath, UObject* ZipUtilityInterfaceDelegate, ZipUtilityCompressionFormat Format /*= COMPRESSION_FORMAT_UNKNOWN*/)
{
FString Directory;
FString FileName;
//Check Directory validity
if (!IsValidDirectory(Directory, FileName, ArchivePath) || !UWindowsFileUtilityFunctionLibrary::DoesFileExist(ArchivePath))
{
((IZipUtilityInterface*)ZipUtilityInterfaceDelegate)->Execute_OnDone((UObject*)ZipUtilityInterfaceDelegate, ArchivePath, EZipUtilityCompletionState::FAILURE_NOT_FOUND);
return nullptr;
}
return UnzipTo(ArchivePath, Directory, ZipUtilityInterfaceDelegate, Format);
}
UZipOperation* UZipFileFunctionLibrary::UnzipWithLambda(const FString& ArchivePath, TFunction<void()> OnDoneCallback, TFunction<void(float)> OnProgressCallback, ZipUtilityCompressionFormat Format)
{
UZULambdaDelegate* LambdaDelegate = NewObject<UZULambdaDelegate>();
LambdaDelegate->AddToRoot();
LambdaDelegate->SetOnDoneCallback([LambdaDelegate, OnDoneCallback]()
{
OnDoneCallback();
LambdaDelegate->RemoveFromRoot();
});
LambdaDelegate->SetOnProgessCallback(OnProgressCallback);
return Unzip(ArchivePath, LambdaDelegate, Format);
}
UZipOperation* UZipFileFunctionLibrary::UnzipTo(const FString& ArchivePath, const FString& DestinationPath, UObject* ZipUtilityInterfaceDelegate, ZipUtilityCompressionFormat Format)
{
return UnzipOnBGThreadWithFormat(ArchivePath, DestinationPath, ZipUtilityInterfaceDelegate, Format);
}
UZipOperation* UZipFileFunctionLibrary::Zip(const FString& ArchivePath, UObject* ZipUtilityInterfaceDelegate, ZipUtilityCompressionFormat Format, TEnumAsByte<ZipUtilityCompressionLevel> Level)
{
FString Directory;
FString FileName;
//Check Directory and File validity
if (!IsValidDirectory(Directory, FileName, ArchivePath) || !UWindowsFileUtilityFunctionLibrary::DoesFileExist(ArchivePath))
{
((IZipUtilityInterface*)ZipUtilityInterfaceDelegate)->Execute_OnDone((UObject*)ZipUtilityInterfaceDelegate, ArchivePath, EZipUtilityCompletionState::FAILURE_NOT_FOUND);
return nullptr;
}
return ZipOnBGThread(ArchivePath, FileName, Directory, ZipUtilityInterfaceDelegate, Format, Level);
}
UZipOperation* UZipFileFunctionLibrary::ZipWithLambda(const FString& ArchivePath, TFunction<void()> OnDoneCallback, TFunction<void(float)> OnProgressCallback /*= nullptr*/, ZipUtilityCompressionFormat Format /*= COMPRESSION_FORMAT_UNKNOWN*/, TEnumAsByte<ZipUtilityCompressionLevel> Level /*=COMPRESSION_LEVEL_NORMAL*/)
{
UZULambdaDelegate* LambdaDelegate = NewObject<UZULambdaDelegate>();
LambdaDelegate->AddToRoot();
LambdaDelegate->SetOnDoneCallback([OnDoneCallback, LambdaDelegate]()
{
OnDoneCallback();
LambdaDelegate->RemoveFromRoot();
});
LambdaDelegate->SetOnProgessCallback(OnProgressCallback);
return Zip(ArchivePath, LambdaDelegate, Format);
}
bool UZipFileFunctionLibrary::ListFilesInArchive(const FString& path, UObject* ListDelegate, ZipUtilityCompressionFormat format)
{
FString Directory;
FString FileName;
//Check Directory validity
if (!IsValidDirectory(Directory, FileName, path))
{
return false;
}
ListOnBGThread(path, Directory, ListDelegate, format);
return true;
}
FGraphEventRef UZipFileFunctionLibrary::RunLambdaOnGameThread(TFunction< void()> InFunction)
{
return FFunctionGraphTask::CreateAndDispatchWhenReady(InFunction, TStatId(), nullptr, ENamedThreads::GameThread);
}

View File

@@ -0,0 +1,34 @@
#include "ZipUtilityPrivatePCH.h"
#include "SevenZipCallbackHandler.h"
#include "WFULambdaRunnable.h"
#include "ZipOperation.h"
UZipOperation::UZipOperation()
{
CallbackHandler = nullptr;
}
void UZipOperation::StopOperation()
{
if (ThreadPoolWork != nullptr)
{
WFULambdaRunnable::RemoveLambdaFromQueue(ThreadPoolWork);
}
if (CallbackHandler != nullptr)
{
CallbackHandler->bCancelOperation = true;
CallbackHandler = nullptr;
}
}
void UZipOperation::SetCallbackHandler(SevenZipCallbackHandler* Handler)
{
CallbackHandler = Handler;
}
void UZipOperation::SetThreadPoolWorker(IQueuedWork* Work)
{
ThreadPoolWork = Work;
}

View File

@@ -0,0 +1,10 @@
#pragma once
#include "ZipUtilityPrivatePCH.h"
#include "ZipUtilityInterface.h"
UZipUtilityInterface::UZipUtilityInterface(const class FObjectInitializer& PCIP)
: Super(PCIP)
{
}

View File

@@ -0,0 +1,20 @@
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
#include "ZipUtilityPrivatePCH.h"
#define LOCTEXT_NAMESPACE "FZipUtilityModule"
void FZipUtilityModule::StartupModule()
{
// This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module
}
void FZipUtilityModule::ShutdownModule()
{
// This function may be called during shutdown to clean up your module. For modules that support dynamic reloading,
// we call this function before unloading the module.
}
#undef LOCTEXT_NAMESPACE
IMPLEMENT_MODULE(FZipUtilityModule, ZipUtility)

View File

@@ -0,0 +1,12 @@
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
#include "ZipUtilityPlugin.h"
#include "CoreMinimal.h"
#include "CoreUObject.h"
#include "EngineMinimal.h"
// You should place include statements to your module's private header files here. You only need to
// add includes for headers that are used in most of your module's source files though.
#include "ZipFileFunctionLibrary.h"

View File

@@ -0,0 +1,28 @@
#pragma once
#include "CoreMinimal.h"
#include "7zpp.h"
#include "ListCallback.h"
#include "ProgressCallback.h"
using namespace SevenZip;
/**
* Forwards events from the 7zpp library to the UE4 listener.
*/
class ZIPUTILITY_API SevenZipCallbackHandler : public ListCallback, public ProgressCallback
{
public:
virtual void OnProgress(const TString& archivePath, uint64 bytes) override;
virtual void OnDone(const TString& archivePath) override;
virtual void OnFileDone(const TString& archivePath, const TString& filePath, uint64 bytes) override;
virtual void OnStartWithTotal(const TString& archivePath, unsigned __int64 totalBytes) override;
virtual void OnFileFound(const TString& archivePath, const TString& filePath, int size) override;
virtual void OnListingDone(const TString& archivePath) override;
virtual bool OnCheckBreak() override;
uint64 BytesLeft = 0;
uint64 TotalBytes = 0;
UObject* ProgressDelegate = nullptr;
FThreadSafeBool bCancelOperation = false;
};

View File

@@ -0,0 +1,102 @@
#pragma once
#include "ZipUtilityInterface.h"
#include "ZipOperation.h"
#include "ZipFileFunctionLibrary.generated.h"
UENUM(BlueprintType)
enum ZipUtilityCompressionFormat
{
COMPRESSION_FORMAT_UNKNOWN,
COMPRESSION_FORMAT_SEVEN_ZIP,
COMPRESSION_FORMAT_ZIP,
COMPRESSION_FORMAT_GZIP,
COMPRESSION_FORMAT_BZIP2,
COMPRESSION_FORMAT_RAR,
COMPRESSION_FORMAT_TAR,
COMPRESSION_FORMAT_ISO,
COMPRESSION_FORMAT_CAB,
COMPRESSION_FORMAT_LZMA,
COMPRESSION_FORMAT_LZMA86
};
UENUM(BlueprintType)
enum ZipUtilityCompressionLevel
{
COMPRESSION_LEVEL_NONE,
COMPRESSION_LEVEL_FAST,
COMPRESSION_LEVEL_NORMAL
};
class SevenZipCallbackHandler;
class UZipFileFunctionInternalCallback;
/**
A blueprint function library encapsulating all zip operations for both C++ and blueprint use.
For some operations a UZipOperation object may be returned, if you're interested in it, ensure
you guard it from garbage collection by e.g. storing it as a UProperty, otherwise you may safely
ignore it.
*/
UCLASS(ClassGroup = ZipUtility, Blueprintable)
class ZIPUTILITY_API UZipFileFunctionLibrary : public UBlueprintFunctionLibrary
{
GENERATED_UCLASS_BODY()
public:
~UZipFileFunctionLibrary();
/* Unzips file in archive containing Name via ListFilesInArchive/UnzipFiles. Automatically determines compression if unknown. Calls ZipUtilityInterface progress events. */
UFUNCTION(BlueprintCallable, Category = ZipUtility)
static bool UnzipFileNamed(const FString& archivePath, const FString& Name, UObject* ZipUtilityInterfaceDelegate, ZipUtilityCompressionFormat format = COMPRESSION_FORMAT_UNKNOWN);
/* Unzips file in archive containing Name at destination path via ListFilesInArchive/UnzipFilesTo. Automatically determines compression if unknown. Calls ZipUtilityInterface progress events. */
UFUNCTION(BlueprintCallable, Category = ZipUtility)
static bool UnzipFileNamedTo(const FString& archivePath, const FString& Name, const FString& destinationPath, UObject* ZipUtilityInterfaceDelegate, ZipUtilityCompressionFormat format = COMPRESSION_FORMAT_UNKNOWN);
/* Unzips the given file indexes in archive at destination path. Automatically determines compression if unknown. Calls ZipUtilityInterface progress events. */
UFUNCTION(BlueprintCallable, Category = ZipUtility)
static UZipOperation* UnzipFilesTo(const TArray<int32> fileIndices, const FString& archivePath, const FString& destinationPath, UObject* ZipUtilityInterfaceDelegate, ZipUtilityCompressionFormat format = COMPRESSION_FORMAT_UNKNOWN);
/* Unzips the given file indexes in archive at current path. Automatically determines compression if unknown. Calls ZipUtilityInterface progress events. */
UFUNCTION(BlueprintCallable, Category = ZipUtility)
static UZipOperation* UnzipFiles(const TArray<int32> fileIndices, const FString& ArchivePath, UObject* ZipUtilityInterfaceDelegate, ZipUtilityCompressionFormat format = COMPRESSION_FORMAT_UNKNOWN);
/* Unzips archive at current path. Automatically determines compression if unknown. Calls ZipUtilityInterface progress events. */
UFUNCTION(BlueprintCallable, Category = ZipUtility)
static UZipOperation* Unzip(const FString& ArchivePath, UObject* ZipUtilityInterfaceDelegate, ZipUtilityCompressionFormat Format = COMPRESSION_FORMAT_UNKNOWN);
/* Lambda C++ simple variant*/
static UZipOperation* UnzipWithLambda( const FString& ArchivePath,
TFunction<void()> OnDoneCallback,
TFunction<void(float)> OnProgressCallback = nullptr,
ZipUtilityCompressionFormat format = COMPRESSION_FORMAT_UNKNOWN);
/* Unzips archive at destination path. Automatically determines compression if unknown. Calls ZipUtilityInterface progress events. */
UFUNCTION(BlueprintCallable, Category = ZipUtility)
static UZipOperation* UnzipTo(const FString& ArchivePath, const FString& DestinationPath, UObject* ZipUtilityInterfaceDelegate, ZipUtilityCompressionFormat format = COMPRESSION_FORMAT_UNKNOWN);
/* Compresses the file or folder given at path and places the file in the same root folder. Calls ZipUtilityInterface progress events. Not all formats are supported for compression.*/
UFUNCTION(BlueprintCallable, Category = ZipUtility)
static UZipOperation* Zip( const FString& FileOrFolderPath,
UObject* ZipUtilityInterfaceDelegate,
ZipUtilityCompressionFormat Format = COMPRESSION_FORMAT_SEVEN_ZIP,
TEnumAsByte<ZipUtilityCompressionLevel> Level = COMPRESSION_LEVEL_NORMAL);
/* Lambda C++ simple variant*/
static UZipOperation* ZipWithLambda( const FString& ArchivePath,
TFunction<void()> OnDoneCallback,
TFunction<void(float)> OnProgressCallback = nullptr,
ZipUtilityCompressionFormat Format = COMPRESSION_FORMAT_UNKNOWN,
TEnumAsByte<ZipUtilityCompressionLevel> Level = COMPRESSION_LEVEL_NORMAL);
/*Queries Archive content list, calls ZipUtilityInterface list events (OnFileFound)*/
UFUNCTION(BlueprintCallable, Category = ZipUtility)
static bool ListFilesInArchive(const FString& ArchivePath, UObject* ZipUtilityInterfaceDelegate, ZipUtilityCompressionFormat format = COMPRESSION_FORMAT_UNKNOWN);
static FGraphEventRef RunLambdaOnGameThread(TFunction< void()> InFunction);
};

View File

@@ -0,0 +1,42 @@
#pragma once
#include "Object.h"
#include "ZipOperation.generated.h"
class SevenZipCallbackHandler;
/**
* Used to track a zip/unzip operation on the WFULambdaRunnable ThreadPool and allows the ability to terminate the
* operation early.
*/
UCLASS(BlueprintType)
class ZIPUTILITY_API UZipOperation : public UObject
{
GENERATED_BODY()
public:
UZipOperation();
// Stops this zip/unzip if it is still valid. This stop event can occur in two places:
// 1. The ThreadPool queue, if it can be stopped here then the operation has not yet started.
// 2. The SevenZip layer, once the operation has started, it can be canceled while still running.
// Note that calling this carries no guarantees of a successful stop, the end result might be one of:
// * The file still got extracted (you were too late)
// * The file was never extracted (caught it on time)
// * The file was created but is of zero size (oops)
// * The file was created, is of non-zero size but is not all there (cut off in the middle)
// So, it could be a good idea to do some file housekeeping afterward.
UFUNCTION(BlueprintCallable, Category = "Zip Operation")
void StopOperation();
// Set the callback handler
void SetCallbackHandler(SevenZipCallbackHandler* Handler);
// Set the queued work
void SetThreadPoolWorker(IQueuedWork* Work);
private:
// A pointer to the callback for this operation. Once the operation completes, this
// pointer will become invalid.
SevenZipCallbackHandler* CallbackHandler;
// The work that was queued on the async threadpool in WFULambdaRunnable
IQueuedWork* ThreadPoolWork;
};

View File

@@ -0,0 +1,62 @@
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
#pragma once
#include "ZipUtilityInterface.generated.h"
UENUM(BlueprintType)
enum EZipUtilityCompletionState
{
SUCCESS,
FAILURE_NOT_FOUND,
FAILURE_UNKNOWN
};
UINTERFACE(MinimalAPI)
class UZipUtilityInterface : public UInterface
{
GENERATED_UINTERFACE_BODY()
};
class ZIPUTILITY_API IZipUtilityInterface
{
GENERATED_IINTERFACE_BODY()
public:
/**
* Called during process as it completes. Currently updates on per file progress.
* @param percentage - percentage done
*/
UFUNCTION(BlueprintNativeEvent, Category = ZipUtilityProgressEvents)
void OnProgress(const FString& archive, float percentage, int32 bytes);
/**
* Called when whole process is complete (e.g. unzipping completed on archive)
*/
UFUNCTION(BlueprintNativeEvent, Category = ZipUtilityProgressEvents)
void OnDone(const FString& archive, EZipUtilityCompletionState CompletionState);
/**
* Called at beginning of process (NB this only supports providing size information for up to 2gb) TODO: fix 32bit BP size issue
*/
UFUNCTION(BlueprintNativeEvent, Category = ZipUtilityProgressEvents)
void OnStartProcess(const FString& archive, int32 bytes);
/**
* Called when file process is complete
* @param path - path of the file that finished
*/
UFUNCTION(BlueprintNativeEvent, Category = ZipUtilityProgressEvents)
void OnFileDone(const FString& archive, const FString& file);
/**
* Called when a file is found in the archive (e.g. listing the entries in the archive)
* @param path - path of file
* @param size - compressed size
*/
UFUNCTION(BlueprintNativeEvent, Category = ZipUtilityListEvents)
void OnFileFound(const FString& archive, const FString& file, int32 size);
};

View File

@@ -0,0 +1,38 @@
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
#pragma once
#include "ModuleManager.h"
class ZIPUTILITY_API FZipUtilityModule : public IModuleInterface
{
public:
//CHN:
//Maybe we need to use a public interface to fetch the module methods for C++? get a reference to zipfile etc
/**
* Singleton-like access to this module's interface. This is just for convenience!
* Beware of calling this during the shutdown phase, though. Your module might have been unloaded already.
*
* @return Returns singleton instance, loading the module on demand if needed
*/
static inline FZipUtilityModule& Get()
{
return FModuleManager::LoadModuleChecked< FZipUtilityModule >("ZipUtility");
}
/**
* Checks to see if this module is loaded and ready. It is only valid to call Get() if IsAvailable() returns true.
*
* @return True if the module is loaded and ready to use
*/
static inline bool IsAvailable()
{
return FModuleManager::Get().IsModuleLoaded("ZipUtility");
}
/** IModuleInterface implementation */
virtual void StartupModule() override;
virtual void ShutdownModule() override;
};

View File

@@ -0,0 +1,102 @@
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
using UnrealBuildTool;
using System.IO;
public class ZipUtility : ModuleRules
{
private string ThirdPartyPath
{
get { return Path.GetFullPath(Path.Combine(ModuleDirectory, "../../ThirdParty/")); }
}
private string SevenZppPath
{
get { return Path.GetFullPath(Path.Combine(ThirdPartyPath, "7zpp")); }
}
private string ATLPath
{
get { return "C:/Program Files (x86)/Microsoft Visual Studio/2017/Community/VC/Tools/MSVC/14.13.26128/atlmfc"; }
}
public ZipUtility(ReadOnlyTargetRules Target) : base(Target)
{
bEnableExceptions = true;
PublicIncludePaths.AddRange(
new string[] {
"ZipUtility/Public"
// ... add public include paths required here ...
}
);
PrivateIncludePaths.AddRange(
new string[] {
"ZipUtility/Private",
Path.Combine(SevenZppPath, "Include"),
Path.Combine(ATLPath, "include"),
// ... add other private include paths required here ...
}
);
PublicDependencyModuleNames.AddRange(
new string[]
{
"Core",
"WindowsFileUtility"
// ... add other public dependencies that you statically link with here ...
}
);
PrivateDependencyModuleNames.AddRange(
new string[]
{
"CoreUObject",
"Engine",
"Slate",
"SlateCore",
"Projects"
// ... add private dependencies that you statically link with here ...
}
);
DynamicallyLoadedModuleNames.AddRange(
new string[]
{
// ... add any modules that your module loads dynamically here ...
}
);
LoadLib(Target);
}
public bool LoadLib(ReadOnlyTargetRules Target)
{
bool isLibrarySupported = false;
if ((Target.Platform == UnrealTargetPlatform.Win64) || (Target.Platform == UnrealTargetPlatform.Win32))
{
isLibrarySupported = true;
string PlatformSubPath = (Target.Platform == UnrealTargetPlatform.Win64) ? "Win64" : "Win32";
string LibrariesPath = Path.Combine(SevenZppPath, "Lib");
string DLLPath = Path.Combine(SevenZppPath, "dll");
PublicAdditionalLibraries.Add(Path.Combine(LibrariesPath, PlatformSubPath, "atls.lib"));
PublicAdditionalLibraries.Add(Path.Combine(LibrariesPath, PlatformSubPath, "7zpp_u.lib"));
PublicLibraryPaths.Add(Path.Combine(LibrariesPath, PlatformSubPath));
PublicDelayLoadDLLs.Add("7z.dll");
RuntimeDependencies.Add(new RuntimeDependency(Path.Combine(DLLPath, PlatformSubPath, "7z.dll")));
}
if (isLibrarySupported)
{
// Include path
//PublicIncludePaths.Add(Path.Combine(SevenZppPath, "Include"));
}
return isLibrarySupported;
}
}

View File

@@ -0,0 +1,46 @@
#pragma once
#include "ListCallback.h"
#include "ProgressCallback.h"
#include "PreWindowsApi.h"
#include "AllowWindowsPlatformTypes.h"
#include "AllowWindowsPlatformAtomics.h"
#pragma warning(push)
#pragma warning(disable: 4191)
#pragma warning(disable: 4996)
#ifndef DeleteFile
#define DeleteFile DeleteFileW
#endif
#ifndef MoveFile
#define MoveFile MoveFileW
#endif
#ifndef LoadString
#define LoadString LoadStringW
#endif
#ifndef GetMessage
#define GetMessage GetMessageW
#endif
#include <atlbase.h>
#include <sphelper.h>
#undef DeleteFile
#undef MoveFile
#include "SevenZipCompressor.h"
#include "SevenZipExtractor.h"
#include "SevenZipLister.h"
#include "HideWindowsPlatformAtomics.h"
#include "HideWindowsPlatformTypes.h"
#include "PostWindowsApi.h"
#pragma warning(pop)
// Version of this library
#define SEVENZIP_VERSION L"0.2.0-20160117.1"
#define SEVENZIP_BRANCH L"master"

View File

@@ -0,0 +1,31 @@
#pragma once
#include "Enum.h"
namespace SevenZip
{
struct CompressionFormat
{
enum _Enum
{
Unknown,
SevenZip,
Zip,
GZip,
BZip2,
Rar,
Tar,
Iso,
Cab,
Lzma,
Lzma86
};
typedef intl::EnumerationDefinitionNoStrings _Definition;
typedef intl::EnumerationValue< _Enum, _Definition, Unknown > _Value;
};
typedef CompressionFormat::_Value CompressionFormatEnum;
}

View File

@@ -0,0 +1,23 @@
#pragma once
#include "Enum.h"
namespace SevenZip
{
struct CompressionLevel
{
enum _Enum
{
None,
Fast,
Normal
};
typedef intl::EnumerationDefinitionNoStrings _Definition;
typedef intl::EnumerationValue< _Enum, _Definition, Normal > _Value;
};
typedef CompressionLevel::_Value CompressionLevelEnum;
}

View File

@@ -0,0 +1,193 @@
#pragma once
//
// ###### To create an enum call MyType with string support: ######
//
//// MyType.h
//struct MyType
//{
// enum _Enum
// {
// Unknown,
// Foo,
// Bar
// };
//
// struct _Definition : public EnumerationDefinition< _Enum, _Definition > { static StringValue Strings[]; };
// typedef EnumerationValue< _Enum, _Definition, Unknown > _Value;
//};
//
//typedef MyType::_Value MyTypeEnum;
//
//
//// MyType.cpp
//#include "MyType.h"
//
//MyType::_Definition::StringValue MyType::_Definition::Strings[] =
//{
// { MyType::Foo, _T( "Foo" ) },
// { MyType::Bar, _T( "Bar" ) },
// { MyType::Unknown, NULL }
//};
//
//
// ###### To create an enum call MyType without string support: ######
//
//// MyType.h
//struct MyType
//{
// enum _Enum
// {
// Unknown,
// Foo,
// Bar
// };
//
// typedef EnumerationDefinitionNoStrings _Definition;
// typedef EnumerationValue< _Enum, _Definition, Unknown > _Value;
//};
//
//typedef MyType::_Value MyTypeEnum;
//
namespace SevenZip
{
namespace intl
{
template < typename TEnum, class DerivedDef >
struct EnumerationDefinition
{
struct StringValue
{
TEnum value;
const TCHAR* string;
};
static TEnum Parse( const TString& string, const TEnum defaultValue )
{
const StringValue* it = DerivedDef::Strings;
for (; it->string != NULL; ++it )
{
if ( string.Compare( it->string ) == 0 )
{
return it->value;
}
}
return defaultValue;
}
static TString Format( const TEnum& value )
{
const StringValue* it = DerivedDef::Strings;
for (; it->string != NULL; ++it )
{
if ( value == it->value )
{
return it->string;
}
}
return TString();
}
};
struct EnumerationDefinitionNoStrings {};
template < typename TEnum, class TEnumClass, TEnum DefaultValue >
class EnumerationValue
{
private:
typedef typename EnumerationValue< TEnum, TEnumClass, DefaultValue > ThisClass;
TEnum m_value;
public:
typedef typename TEnum Enum;
EnumerationValue():
m_value( DefaultValue )
{}
EnumerationValue( const TEnum& value ):
m_value( value )
{}
static ThisClass Parse( const TString& string )
{
return ThisClass( TEnumClass::Parse( string, DefaultValue ) );
}
const TEnum& GetValue() const
{
return m_value;
}
TString GetString() const
{
return TEnumClass::Format( m_value );
}
operator TEnum() const
{
return m_value;
}
ThisClass& operator=( const TEnum& value )
{
m_value = value;
return *this;
}
bool operator==( const ThisClass& that ) const
{
return that.m_value == m_value;
}
bool operator!=( const ThisClass& that ) const
{
return !operator==( that );
}
bool operator==( const TEnum& value ) const
{
return value == m_value;
}
bool operator!=( const TEnum& value ) const
{
return !operator==( value );
}
bool operator< ( const ThisClass& that ) const
{
return m_value < that.m_value;
}
// Bit field members
void AddFlag( const TEnum& value )
{
*reinterpret_cast< int* >( &m_value ) |= static_cast< int >( value );
}
void RemoveFlag( const TEnum& value )
{
*reinterpret_cast< int* >( &m_value ) &= ~static_cast< int >( value );
}
bool HasFlag( const TEnum& value ) const
{
return ( m_value & value ) == value;
}
bool HasAnyFlag( const TEnum& valueCombo ) const
{
return ( m_value & valueCombo ) != 0;
}
};
}
}

View File

@@ -0,0 +1,24 @@
#pragma once
namespace SevenZip
{
namespace intl
{
struct FileInfo
{
TString FileName;
FILETIME LastWriteTime;
FILETIME CreationTime;
FILETIME LastAccessTime;
ULONGLONG Size;
UINT Attributes;
bool IsDirectory;
};
struct FilePathInfo : public FileInfo
{
TString FilePath;
};
}
}

View File

@@ -0,0 +1,23 @@
#pragma once
#include "SevenZipLibrary.h"
#include "CompressionFormat.h"
namespace SevenZip
{
class ListCallback
{
public:
/*
Called for each file found in the archive. Size in bytes.
*/
virtual void OnFileFound(const TString& archivePath, const TString& filePath, int size) {}
/*
Called when all the files have been listed
*/
virtual void OnListingDone(const TString& archivePath) {}
};
}

View File

@@ -0,0 +1,40 @@
#pragma once
#include "SevenZipLibrary.h"
#include "CompressionFormat.h"
namespace SevenZip
{
class ProgressCallback
{
public:
/*
Called at beginning
*/
virtual void OnStartWithTotal(const TString& archivePath, unsigned __int64 totalBytes) = 0;
/*
Called Whenever progress has updated with a bytes complete
*/
virtual void OnProgress(const TString& archivePath, unsigned __int64 bytesCompleted) = 0;
/*
Called When progress has reached 100%
*/
virtual void OnDone(const TString& archivePath) = 0;
/*
Called When single file progress has reached 100%, returns the filepath that completed
*/
virtual void OnFileDone(const TString& archivePath, const TString& filePath, unsigned __int64 bytesCompleted) = 0;
/*
Called to determine if it's time to abort the zip operation. Return true to abort the current operation.
*/
virtual bool OnCheckBreak() = 0;
};
}

View File

@@ -0,0 +1,15 @@
#pragma once
#include <tchar.h>
#include <string>
namespace SevenZip
{
#ifdef _UNICODE
typedef std::wstring TString;
#else
typedef std::string TString;
#endif
}

View File

@@ -0,0 +1,48 @@
#pragma once
#include "SevenZipLibrary.h"
#include <atlbase.h>
#include "FileInfo.h"
#include "CompressionFormat.h"
#include "CompressionLevel.h"
namespace SevenZip
{
class SevenZipArchive
{
public:
SevenZipArchive(const SevenZipLibrary& library, const TString& archivePath);
virtual ~SevenZipArchive();
virtual bool ReadInArchiveMetadata();
virtual void SetCompressionFormat(const CompressionFormatEnum& format);
virtual CompressionFormatEnum GetCompressionFormat();
virtual void SetCompressionLevel(const CompressionLevelEnum& level);
virtual CompressionLevelEnum GetCompressionLevel();
virtual bool DetectCompressionFormat();
virtual size_t GetNumberOfItems();
virtual std::vector<TString> GetItemsNames();
virtual std::vector<size_t> GetOrigSizes();
protected:
bool m_ReadMetadata = false;
bool m_OverrideCompressionFormat = false;
const SevenZipLibrary& m_library;
TString m_archivePath;
CompressionFormatEnum m_compressionFormat;
CompressionLevelEnum m_compressionLevel;
size_t m_numberofitems = 0;
std::vector<TString> m_itemnames;
std::vector<size_t> m_origsizes;
private:
bool pri_GetNumberOfItems();
bool pri_GetItemsNames();
bool pri_DetectCompressionFormat(CompressionFormatEnum & format);
bool pri_DetectCompressionFormat();
};
}

View File

@@ -0,0 +1,43 @@
#pragma once
#include <vector>
#include <atlbase.h>
#include "SevenZipLibrary.h"
#include "SevenZipArchive.h"
#include "FileInfo.h"
#include "CompressionFormat.h"
#include "CompressionLevel.h"
#include "ProgressCallback.h"
namespace SevenZip
{
class SevenZipCompressor : public SevenZipArchive
{
public:
SevenZipCompressor( const SevenZipLibrary& library, const TString& archivePath );
virtual ~SevenZipCompressor();
// Includes the last directory as the root in the archive, e.g. specifying "C:\Temp\MyFolder"
// makes "MyFolder" the single root item in archive with the files within it included.
virtual bool CompressDirectory( const TString& directory, ProgressCallback* callback, bool includeSubdirs = true);
// Excludes the last directory as the root in the archive, its contents are at root instead. E.g.
// specifying "C:\Temp\MyFolder" make the files in "MyFolder" the root items in the archive.
virtual bool CompressFiles( const TString& directory, const TString& searchFilter, ProgressCallback* callback, bool includeSubdirs = true );
virtual bool CompressAllFiles( const TString& directory, ProgressCallback* callback, bool includeSubdirs = true );
// Compress just this single file as the root item in the archive.
virtual bool CompressFile( const TString& filePath, ProgressCallback* callback);
private:
TString m_outputPath; //the final compression result compression path. Used for tracking in callbacks
CComPtr< IStream > OpenArchiveStream();
bool FindAndCompressFiles( const TString& directory, const TString& searchPattern,
const TString& pathPrefix, bool recursion, ProgressCallback* callback);
bool CompressFilesToArchive(const TString& pathPrefix, const std::vector< intl::FilePathInfo >& filePaths, ProgressCallback* callback);
bool SetCompressionProperties( IUnknown* outArchive );
};
}

View File

@@ -0,0 +1,30 @@
#pragma once
#include <exception>
#include "SevenString.h"
#include "AllowWindowsPlatformTypes.h"
namespace SevenZip
{
TString StrFmt(const TCHAR* format, ...);
TString GetWinErrMsg(const TString& contextMessage, DWORD lastError);
TString GetCOMErrMsg(const TString& contextMessage, HRESULT lastError);
class SevenZipException
{
protected:
TString m_message;
public:
SevenZipException();
SevenZipException(const TString& message);
virtual ~SevenZipException();
const TString& GetMessage() const;
};
}
#include "HideWindowsPlatformTypes.h"

View File

@@ -0,0 +1,25 @@
#pragma once
#include "SevenZipLibrary.h"
#include "SevenZipArchive.h"
#include "CompressionFormat.h"
#include "ProgressCallback.h"
namespace SevenZip
{
class SevenZipExtractor : public SevenZipArchive
{
public:
SevenZipExtractor( const SevenZipLibrary& library, const TString& archivePath );
virtual ~SevenZipExtractor();
virtual bool ExtractArchive(const TString& directory, ProgressCallback* callback);
virtual bool ExtractFilesFromArchive(const unsigned int* fileIndices, const unsigned int numberFiles, const TString& directory, ProgressCallback* callback);
private:
bool ExtractFilesFromArchive(const CComPtr< IStream >& archiveStream, const unsigned int* fileIndices, const unsigned int numberFiles, const TString& directory, ProgressCallback* callback);
};
}

View File

@@ -0,0 +1,28 @@
#pragma once
#include "SevenZipException.h"
#include "CompressionFormat.h"
namespace SevenZip
{
class SevenZipLibrary
{
private:
typedef UINT32 (WINAPI * CreateObjectFunc)( const GUID* clsID, const GUID* interfaceID, void** outObject );
HMODULE m_dll;
CreateObjectFunc m_func;
public:
SevenZipLibrary();
~SevenZipLibrary();
bool Load();
bool Load( const TString& libraryPath );
void Free();
bool CreateObject( const GUID& clsID, const GUID& interfaceID, void** outObject ) const;
};
}

View File

@@ -0,0 +1,24 @@
#pragma once
#include "SevenZipLibrary.h"
#include "SevenZipArchive.h"
#include "CompressionFormat.h"
#include "ListCallback.h"
namespace SevenZip
{
class SevenZipLister : public SevenZipArchive
{
public:
TString m_archivePath;
SevenZipLister( const SevenZipLibrary& library, const TString& archivePath );
virtual ~SevenZipLister();
virtual bool ListArchive(ListCallback* callback);
private:
bool ListArchive(const CComPtr< IStream >& archiveStream, ListCallback* callback);
};
}

View File

@@ -0,0 +1,56 @@
7-Zip
~~~~~
License for use and distribution
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7-Zip Copyright (C) 1999-2015 Igor Pavlov.
Licenses for files are:
1) 7z.dll: GNU LGPL + unRAR restriction
2) 7za.dll: GNU LGPL
The GNU LGPL + unRAR restriction means that you must follow both
GNU LGPL rules and unRAR restriction rules.
Note:
You can use 7-Zip on any computer, including a computer in a commercial
organization. You don't need to register or pay for 7-Zip.
GNU LGPL information
--------------------
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You can receive a copy of the GNU Lesser General Public License from
http://www.gnu.org/
unRAR restriction
-----------------
The decompression engine for RAR archives was developed using source
code of unRAR program.
All copyrights to original unRAR code are owned by Alexander Roshal.
The license for original unRAR code has the following restriction:
The unRAR sources cannot be used to re-create the RAR compression algorithm,
which is proprietary. Distribution of modified unRAR sources in separate form
or as a part of other software is permitted, provided that it is clearly
stated in the documentation and source comments that the code may
not be used to develop a RAR (WinRAR) compatible archiver.
--
Igor Pavlov

View File

@@ -0,0 +1,26 @@
{
"FileVersion": 3,
"Version": 2,
"VersionName": "0.4.3",
"FriendlyName": "ZipUtility",
"Description": "",
"Category": "Utility",
"CreatedBy": "Getnamo",
"CreatedByURL": "http://www.getnamo.com",
"DocsURL": "https://github.com/getnamo/ZipUtility-ue4",
"MarketplaceURL": "",
"SupportURL": "",
"EnabledByDefault": true,
"CanContainContent": false,
"Modules": [
{
"Name": "ZipUtility",
"Type": "Runtime",
"LoadingPhase": "Default",
"WhitelistPlatforms": [
"Win64",
"Win32"
]
}
]
}