Vous êtes sur la page 1sur 6

// Copyright 1998-2013 Epic Games, Inc. All Rights Reserved.

#pragma once

#include "Engine/Texture2D.h"
#include "DDSLoader.h"
#include "TaskGraphInterfaces.h"
#include "Developer/ImageWrapper/Public/ImageWrapper.h"

#include "zlib.h"

#include "ZipReaderFunctionLibrary.generated.h"

// BP Library for reading zip files from disk at runtime.


//
// Written by n00854180t

#define JZ_BUFFER_SIZE 2048

class FZipReaderWorker : public FRunnable


{
/** Thread to run the worker FRunnable on */
FRunnableThread* Thread;

bool resize;
FString filename;

unsigned char tmpBuffer[JZ_BUFFER_SIZE];


bool mipDone;
bool decompressDone;
void* compressedBuffer;
void* tmpDecompressedBuffer;
void** outMipData;
int32 compressedSize;
int32 uncompressedSize;

unsigned char *bytes;


void* workingcompressedBuf;

long compressedLeft, uncompressedLeft;


z_stream strm;

int32 height, width;


int32* outWidth;
int32* outHeight;
TArray<uint8>* RawImgData;

IImageWrapperPtr ImageWrapper;

int32 x, y;

/** Stop this thread? Uses Thread Safe Counter */


FThreadSafeCounter StopTaskCounter;

int32 uncompress();

private:
int32 bytesRemaining;

public:

int32 TotalPrimesToFind;

//Done?
bool IsFinished() const
{
return bytesRemaining == 0 && x >= width && y >= height;
}

//~~~ Thread Core Functions ~~~

//Constructor / Destructor
FZipReaderWorker(FString Filename, void* CompressedBuffer, void** OutMipData,
int32 CompressedSize, int32 UncompressedSize, int32* OutWidth, int32* OutHeight,
IImageWrapperPtr ImgWrapper, bool Resize);
virtual ~FZipReaderWorker();

// Begin FRunnable interface.


virtual bool Init();
virtual uint32 Run();
virtual void Stop();
// End FRunnable interface

/** Makes sure this thread has stopped properly */


void EnsureCompletion();

//~~~ Starting and Stopping Thread ~~~


/*
Start the thread and the worker from static (easy access)!
This code ensures only 1 Prime Number thread will be able to run at a time.
This function returns a handle to the newly started instance.
*/
static FZipReaderWorker* InitWorker(FString filename, void* compressedBuffer,
void** outMipData, int32 compressedSize, int32 uncompressedSize, int32* outWidth,
int32* outHeight, IImageWrapperPtr imgWrapper, bool resize);

/** Shuts down the thread. Static so it can easily be called from outside the
thread context */
void Shutdown();

bool IsThreadFinished();

};

struct CompressedChunkInfo
{
// Default constructor, zero initializing all members.
CompressedChunkInfo()
{
UncompressedSize = 0;
CompressedSize = 0;
CompressedOffset = 0;
}

// Uncompressed size in bytes.


int32 UncompressedSize;
/// Offset in compressed file.
int32 CompressedOffset;
/// Compressed size in bytes.
int32 CompressedSize;

// Name of this compressed file, if applicable.


FString ChunkFileName;
};

struct CachedTextureInfo
{
CachedTextureInfo()
{
PageNumber = 0;
Width = 0;
Height = 0;
TmpMipData = NULL;
Texture = NULL;
}

int32 PageNumber;
void* TmpMipData;
int32 Width;
int32 Height;
TWeakObjectPtr<UTexture2D> Texture;
};

struct ZipFile
{
// Default constructor, zero initializing all members.
ZipFile()
{
CompressedData = NULL;
RequestId = -1;
IsCompressedReadComplete = false;

MainPagesLoaded = 0;
SecondaryPagesLoaded = 0;

FileSize = 0;
}

// Zip file name.


FString FileName;

// Compressed zip data.


void* CompressedData;

// Size of zip.
int32 FileSize;

// Has the compressed read been requested.


uint32 RequestId;

// Is the async read of compressed zip data complete?


bool IsCompressedReadComplete;

// Info about each file in the zip.


TArray<CompressedChunkInfo> FileChunks;

// Main page cache - limited number of full-resolution pages kept in memory.


TArray<CachedTextureInfo> MainTextureCache;

// Secondary page cache - low resolution version of all pages, to show if a


high res is not available, while loading.
TArray<CachedTextureInfo> SecondaryTextureCache;

// A list of pages requested from this zip that haven't been dispatched for
load.
TArray<int32> PendingPageRequests;

// A list of page requests with jobs that have been started already.
TArray<int32> ActivePageRequests;

// Number of hi res pages loaded.


int32 MainPagesLoaded;

// Number of secondary low res pages loaded.


int32 SecondaryPagesLoaded;
};

typedef struct {
#pragma pack(push,1) // Supposedly, this is supported on GCC as of certain
versions, definitely 4.0 and greater. *Important for porting - make sure that
something equivalent is done for your compiler, otherwise archives will fail to
load due to wrong offsets in reading/seeking.
uint32 signature;
uint16 versionNeededToExtract; // unsupported
uint16 generalPurposeBitFlag; // unsupported
uint16 compressionMethod;
uint16 lastModFileTime;
uint16 lastModFileDate;
uint32 crc32;
uint32 compressedSize;
uint32 uncompressedSize;
uint16 fileNameLength;
uint16 extraFieldLength; // unsupported
#pragma pack(pop)
} JZLocalFileHeader;

typedef struct {
#pragma pack(push,1)
uint32 signature;
uint16 versionMadeBy; // unsupported
uint16 versionNeededToExtract; // unsupported
uint16 generalPurposeBitFlag; // unsupported
uint16 compressionMethod;
uint16 lastModFileTime;
uint16 lastModFileDate;
uint32 crc32;
uint32 compressedSize;
uint32 uncompressedSize;
uint16 fileNameLength;
uint16 extraFieldLength; // unsupported
uint16 fileCommentLength; // unsupported
uint16 diskNumberStart; // unsupported
uint16 internalFileAttributes; // unsupported
uint32 externalFileAttributes; // unsupported
uint32 relativeOffsetOflocalHeader;
#pragma pack(pop)
} JZGlobalFileHeader;

typedef struct {
#pragma pack(push,1)
uint16 compressionMethod;
uint16 lastModFileTime;
uint16 lastModFileDate;
uint32 crc32;
uint32 compressedSize;
uint32 uncompressedSize;
uint32 offset;
#pragma pack(pop)
} JZFileHeader;

typedef struct {
#pragma pack(push,1)
uint32 signature; // 0x06054b50
uint16 diskNumber; // unsupported
uint16 centralDirectoryDiskNumber; // unsupported
uint16 numEntriesThisDisk; // unsupported
uint16 numEntries;
uint32 centralDirectorySize;
uint32 centralDirectoryOffset;
uint16 zipCommentLength;
#pragma pack(pop)
// Followed by .ZIP file comment (variable size)
} JZEndRecord;

UCLASS()
class ZIPREADER_API UZipReaderFunctionLibrary : public UBlueprintFunctionLibrary
{
GENERATED_UCLASS_BODY()

//

UFUNCTION(BlueprintCallable, Category = "ZipReader")


static int32 GetFileCount(const FString& FilePath);

UFUNCTION(BlueprintCallable, Category = "ZipReader")


static class UTexture2D* CheckCachedTexture(int32 TextureIndex);

UFUNCTION(BlueprintCallable, Category = "ZipReader")


static void CleanUpCache();

//static void CheckAllThreadsDone();

//static int32 CollectSimpleZipInfo(IFileHandle *zip, JZEndRecord *endRecord,


SimpleZipData* outZipData);
static void CheckAllFilesLoaded();
static bool TasksAreComplete();
static class UTexture2D* GetTextureFromMipData(FString FileName, void*
SrcData, int32 Width, int32 Height, int32 Size);
UFUNCTION(BlueprintCallable, Category = "ZipReader")
static void QueueTextureLoad(const FString& ZipFileName, int32 TextureIndex);

UFUNCTION(BlueprintCallable, Category = "ZipReader")


static void QueueAllTextures(const FString& ZipFileName, int32 TextureCount);

private:

static TArray<FZipReaderWorker*> ReaderWorkers;

static TArray<UTexture2D*> CachedTextures;


//static SimpleZipData* CachedZipData;

static FTimerDelegate FinishedLoadingDelegate;


static FString CacheFileName;

static ZipFile* GetOrAddCachedZip(const FString& ZipFileName);

static void StartThreadCheckerTimer();

static class IFileHandle* OpenFromFileName(const FString& FileName);


static int32 CollectSimpleZipInfo(ZipFile* zip, JZEndRecord *endRecord, int32
offset);

static bool AddZipReadRequest(ZipFile* Zip, int32 ChunkIndex);

static TArray<ZipFile*> ZipFileCache;

// Thanks to @Ehamloptiran for the base code for loading a texture:


// https://docs.google.com/file/d/0BzqpBc4MrAMXLXN1ZGNzUEJZc1k/edit
};

// Read ZIP file end record. Will move within file.


int jzReadEndRecord(IFileHandle *ZipFile, JZEndRecord *endRecord);

// Read local ZIP file header. Silent on errors so optimistic reading possible.
int jzReadLocalFileHeader(IFileHandle *zip, JZFileHeader *header, char *filename,
int len);

// Read ZIP file end record. Will move within file.


int jzReadEndRecordFromMemory(void* zipData, JZEndRecord *endRecord, int32
currentOffset, int32 zipFileSize);

// Read local ZIP file header. Silent on errors so optimistic reading possible.
int jzReadLocalFileHeaderFromMemory(void* zipData, JZFileHeader *header, char
*filename, int len, int32 currentOffset);

Vous aimerez peut-être aussi