2018-01-01 22:07:24 +00:00
|
|
|
|
/***********************************************************************************************
|
|
|
|
|
*
|
|
|
|
|
* Copyright <EFBFBD> DreamWorks Interactive, 1998.
|
|
|
|
|
*
|
|
|
|
|
* Contents:
|
|
|
|
|
* Implementation of ImageLoader.hpp
|
|
|
|
|
*
|
|
|
|
|
* Bugs:
|
|
|
|
|
*
|
|
|
|
|
* To do:
|
|
|
|
|
*
|
|
|
|
|
***********************************************************************************************
|
|
|
|
|
*
|
|
|
|
|
* $Log:: /JP2_PC/Source/Lib/Loader/ImageLoader.cpp $
|
|
|
|
|
*
|
|
|
|
|
* 28 10/05/98 6:17a Agrant
|
|
|
|
|
* better? calculation of swap file space management
|
|
|
|
|
*
|
|
|
|
|
* 27 10/02/98 9:49p Rwyatt
|
|
|
|
|
* Chnaged swpspace registry key to SwapSpaceMb
|
|
|
|
|
*
|
|
|
|
|
* 26 9/25/98 7:21p Rwyatt
|
|
|
|
|
* Image loader no longer sets the VM to use blocking loads
|
|
|
|
|
*
|
|
|
|
|
* 25 9/16/98 9:18p Agrant
|
|
|
|
|
* Image loader succeeds unless overridden elsewhere.
|
|
|
|
|
*
|
|
|
|
|
* 24 98.09.14 12:23p Mmouni
|
|
|
|
|
* Out of date for bad local swap files are now deleted before the image loader tries to do its
|
|
|
|
|
* thing.
|
|
|
|
|
*
|
|
|
|
|
* 23 9/04/98 4:40p Mmouni
|
|
|
|
|
* Added preliminary assembly version of de-compression (currently disabled).
|
|
|
|
|
* Added support for handling write errors.
|
|
|
|
|
*
|
|
|
|
|
* 22 9/03/98 4:30p Shernd
|
|
|
|
|
* Checking for out of disk space
|
|
|
|
|
*
|
|
|
|
|
* 21 98.09.02 10:02p Mmouni
|
|
|
|
|
* Added progress counters to new de-compression.
|
|
|
|
|
*
|
|
|
|
|
* 20 98.09.01 8:58p Mmouni
|
|
|
|
|
* Added switch to enable/disable loading of new swap file compressed format.
|
|
|
|
|
*
|
|
|
|
|
* 19 98.09.01 8:43p Mmouni
|
|
|
|
|
* Added the first version (optimized C) of the new image file decompression.
|
|
|
|
|
*
|
|
|
|
|
* 18 8/31/98 6:46p Mmouni
|
|
|
|
|
* Added optional warning message for no swap file.
|
|
|
|
|
*
|
|
|
|
|
* 17 8/27/98 1:33p Shernd
|
|
|
|
|
* Improved callback updates
|
|
|
|
|
*
|
|
|
|
|
* 16 8/25/98 2:13p Rwyatt
|
|
|
|
|
* Made the load heap 16Mb maximum
|
|
|
|
|
*
|
|
|
|
|
* 15 8/23/98 4:30p Rwyatt
|
|
|
|
|
* Added an assert for zero length PID files
|
|
|
|
|
*
|
|
|
|
|
* 14 8/23/98 2:45a Agrant
|
|
|
|
|
* Don't wait for the swap thread if we already have a swap file.
|
|
|
|
|
*
|
|
|
|
|
* 13 8/23/98 12:24a Shernd
|
|
|
|
|
* While waiting for the local Copy to finish we now use an Even instead of a CritialSection.
|
|
|
|
|
*
|
|
|
|
|
* 12 8/19/98 1:38p Rwyatt
|
|
|
|
|
* New allocation functions to load from the Image Loader fast heap
|
|
|
|
|
*
|
|
|
|
|
* 11 98.08.13 4:26p Mmouni
|
|
|
|
|
* Changes for VC++ 5.0sp3 compatibility.
|
|
|
|
|
*
|
|
|
|
|
* 10 8/03/98 6:34p Shernd
|
|
|
|
|
* Changes for Progress Loading Bar
|
|
|
|
|
*
|
|
|
|
|
* 9 6/24/98 3:22p Rwyatt
|
|
|
|
|
* Use synchronous VM for the first few frames so image cahces and terrain textures are at full
|
|
|
|
|
* resolution.
|
|
|
|
|
*
|
|
|
|
|
* 8 6/12/98 2:33p Rwyatt
|
|
|
|
|
* If Trespasser is not installed the image loader will default to a non compressed swap file if
|
|
|
|
|
* it can find one. It will assert if a SWP file cannot be found.
|
|
|
|
|
*
|
|
|
|
|
* 7 6/10/98 4:52p Rwyatt
|
|
|
|
|
* Now loads compressed swap files (.spp). If one of these files cannot be found then the
|
|
|
|
|
* existing swap file is loaded in the usual way,
|
|
|
|
|
*
|
|
|
|
|
* 6 6/02/98 11:17p Rwyatt
|
|
|
|
|
* Fixed the problem of finding and deleting old swap files if they are read only
|
|
|
|
|
*
|
|
|
|
|
* 5 4/23/98 7:58p Rwyatt
|
|
|
|
|
* Copy local of swap files now deletes old swap file once the specified quota is reached. The
|
|
|
|
|
* quota is obtained from the registry.
|
|
|
|
|
* Commit all is now idsabled by default.
|
|
|
|
|
*
|
|
|
|
|
* 4 4/22/98 2:54p Rwyatt
|
|
|
|
|
* The VM thread is only resumed if we do not have the commit all flag set
|
|
|
|
|
*
|
|
|
|
|
* 3 4/21/98 3:10p Rwyatt
|
|
|
|
|
* New format swap files (110).
|
|
|
|
|
* These support a pageable and non-pageable section.
|
|
|
|
|
*
|
|
|
|
|
* 2 2/25/98 3:16p Rwyatt
|
|
|
|
|
* Added an extentsion to the swp and pid file so multiples can exist for different versions of
|
|
|
|
|
* the GUIApp
|
|
|
|
|
*
|
|
|
|
|
* 1 2/18/98 1:08p Rwyatt
|
|
|
|
|
* Moved from TextureManager.cpp
|
|
|
|
|
*
|
|
|
|
|
**********************************************************************************************/
|
|
|
|
|
|
|
|
|
|
#include "Common.hpp"
|
|
|
|
|
#include "stdio.h"
|
|
|
|
|
#include "stdlib.h"
|
|
|
|
|
#include "io.h"
|
|
|
|
|
#include "Lib/W95/WinInclude.hpp"
|
|
|
|
|
#include "ImageLoader.hpp"
|
|
|
|
|
#include "Lib/Sys/VirtualMem.hpp"
|
|
|
|
|
#include "TextureManager.hpp"
|
|
|
|
|
#include "Loader.hpp"
|
|
|
|
|
#include "Lib/Sys/MemoryLog.hpp"
|
|
|
|
|
#include "Lib/Sys/DebugConsole.hpp"
|
|
|
|
|
#include "Lib/Sys/FileEx.hpp"
|
|
|
|
|
#include "Lib/sys/Reg.h"
|
|
|
|
|
#include "Lib/EntityDBase/RenderDB.hpp"
|
|
|
|
|
#include "Lib/EntityDBase/WorldDBase.hpp"
|
|
|
|
|
#include "Lib/Sys/Profile.hpp"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//*********************************************************************************************
|
|
|
|
|
#define THREADED_COPY (1)
|
|
|
|
|
|
|
|
|
|
#define NEW_SWAP_COMPRESSION (1)
|
|
|
|
|
|
|
|
|
|
#if !defined(WARN_ON_NO_SWAP)
|
|
|
|
|
|
|
|
|
|
#define WARN_ON_NO_SWAP (0)
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//*********************************************************************************************
|
|
|
|
|
// Load Image Directory Static Variables
|
|
|
|
|
//
|
|
|
|
|
CLoadImageDirectory* CLoadImageDirectory::plidImageDir = NULL;
|
|
|
|
|
bool CLoadImageDirectory::bValidImage = false;
|
|
|
|
|
bool CLoadImageDirectory::bImageLoader = true;
|
|
|
|
|
bool CLoadImageDirectory::bAutoCommit = false;
|
|
|
|
|
HANDLE CLoadImageDirectory::hCopyLocal = NULL;
|
|
|
|
|
bool CLoadImageDirectory::bCopyResult = false;
|
|
|
|
|
bool CLoadImageDirectory::bCompressed = false;
|
|
|
|
|
bool CLoadImageDirectory::bNewCompression = false;
|
|
|
|
|
void* CLoadImageDirectory::pvThreadHandle = NULL;
|
|
|
|
|
CFastHeap CLoadImageDirectory::fhImageLoad(1 << 24); // 16Mb
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//*********************************************************************************************
|
|
|
|
|
//
|
|
|
|
|
// A Function that reads the size from one of our newly compressed files.
|
|
|
|
|
//
|
|
|
|
|
uint32 u4OriginalFileSize(const char *str_filename);
|
|
|
|
|
//
|
|
|
|
|
//*************************************
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//*********************************************************************************************
|
|
|
|
|
// Image Directory Loading
|
|
|
|
|
//
|
|
|
|
|
// This will create all of the structures for relocating rasters and will start the VM system
|
|
|
|
|
// if all goes well.
|
|
|
|
|
//
|
|
|
|
|
CLoadImageDirectory::CLoadImageDirectory
|
|
|
|
|
(
|
|
|
|
|
const char* str_grf_name, // name of the GRF file being loaded
|
|
|
|
|
PFNWORLDLOADNOTIFY pfnInWorldNotify, // Notification callback
|
|
|
|
|
uint32 u4InNotifyParam // Notificaiton parameter
|
|
|
|
|
)
|
|
|
|
|
//*************************************
|
|
|
|
|
{
|
|
|
|
|
char str_dir_name[MAX_PATH];
|
|
|
|
|
HANDLE h_load;
|
|
|
|
|
uint32 u4_len;
|
|
|
|
|
uint32 u4_load_bytes;
|
|
|
|
|
|
|
|
|
|
// Assume success unless set elsewhere.
|
|
|
|
|
i4Error = 0;
|
|
|
|
|
|
|
|
|
|
Assert(plidImageDir==NULL); // there can be only one.
|
|
|
|
|
|
|
|
|
|
hCopyLocal = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
|
|
|
|
|
|
|
|
pfnWorldNotify = pfnInWorldNotify;
|
|
|
|
|
u4NotifyParam = u4InNotifyParam;
|
|
|
|
|
|
|
|
|
|
strcpy(str_dir_name,str_grf_name);
|
|
|
|
|
strcpy(str_dir_name + strlen(str_dir_name) - 4, strPID_FILE_EXTENTSION);
|
|
|
|
|
|
|
|
|
|
plidImageDir = this; // set the global class pointer to this
|
|
|
|
|
|
|
|
|
|
bValidImage = false;
|
|
|
|
|
pdfhDirHeader = NULL;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// if the image loader is disbaled then return without doing anything,
|
|
|
|
|
// if the virtual memory manager is already image based we must use the conventional loader,
|
|
|
|
|
// if the virtual memory manager has allocated any memory we must use the conventional loader,
|
|
|
|
|
// if exit path is taken and something is allocated then we cannot create a swap file later, this
|
|
|
|
|
// happens when two GRF files are loaded. Also, if this exit is taken then make sure that there
|
|
|
|
|
// is no small texture manager. Small textures should be forced to use the normal allocator.
|
|
|
|
|
//
|
|
|
|
|
if ((!bImageLoader) || (gtxmTexMan.pvmeTextures->bFileBased()) ||
|
|
|
|
|
(gtxmTexMan.pvmeTextures->bAnythingAllocated()))
|
|
|
|
|
{
|
|
|
|
|
gtxmTexMan.DestroySmallTextureAllocator();
|
|
|
|
|
bImageLoader = false;
|
|
|
|
|
SetEvent(hCopyLocal);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// There must not be a sub allocator at this point or something is really wrong.
|
|
|
|
|
Assert(gtxmTexMan.pvmsaSmallTextures == NULL);
|
|
|
|
|
|
|
|
|
|
// process the local swap file.
|
|
|
|
|
if ( bProcessLocalSwapFile
|
|
|
|
|
(
|
|
|
|
|
str_grf_name // name of the GRF file to find a swap file for
|
|
|
|
|
) == false )
|
|
|
|
|
{
|
|
|
|
|
// We need to create the small texture allocator before we continue with the conventional
|
|
|
|
|
// load.
|
|
|
|
|
gtxmTexMan.CreateSmallTextureAllocator();
|
|
|
|
|
|
|
|
|
|
// cannot process the swap file, probably because it does not exist.
|
|
|
|
|
bImageLoader = false;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// open the directory file....
|
|
|
|
|
//
|
|
|
|
|
h_load=CreateFile(str_dir_name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
|
|
|
|
|
FILE_ATTRIBUTE_READONLY|FILE_FLAG_SEQUENTIAL_SCAN,NULL);
|
|
|
|
|
|
|
|
|
|
if (h_load == INVALID_HANDLE_VALUE)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// size of the file
|
|
|
|
|
u4_len = GetFileSize(h_load, NULL);
|
|
|
|
|
|
|
|
|
|
Assert(u4_len > 0);
|
|
|
|
|
|
|
|
|
|
pdfhDirHeader = (SDirectoryFileHeader*) new char[u4_len];
|
|
|
|
|
|
|
|
|
|
if (ReadFile(h_load, pdfhDirHeader , u4_len ,(DWORD*)&u4_load_bytes, NULL) == false)
|
|
|
|
|
{
|
|
|
|
|
CloseHandle(h_load);
|
|
|
|
|
delete pdfhDirHeader;
|
|
|
|
|
pdfhDirHeader = NULL;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// make sure we got the whole file, if not fail on the image file so it is not used.
|
|
|
|
|
if (u4_load_bytes != u4_len)
|
|
|
|
|
{
|
|
|
|
|
CloseHandle(h_load);
|
|
|
|
|
delete pdfhDirHeader;
|
|
|
|
|
pdfhDirHeader = NULL;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CloseHandle(h_load);
|
|
|
|
|
|
|
|
|
|
// We must have the correct version number
|
|
|
|
|
AlwaysAssert(pdfhDirHeader->u4Version == u4DIRECTORY_FILE_VERSION);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// check if the bump maps in this file match the bit depth of the current build...
|
|
|
|
|
if (pdfhDirHeader->u4BumpMapBitDepth != iBUMPMAP_RESOLUTION)
|
|
|
|
|
{
|
|
|
|
|
delete pdfhDirHeader;
|
|
|
|
|
pdfhDirHeader = NULL;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Construct an array of CPals
|
|
|
|
|
//
|
|
|
|
|
uint32 u4_pal_count = pdfhDirHeader->u4PaletteCount;
|
|
|
|
|
SDirectoryPaletteChunk* pdpc = (SDirectoryPaletteChunk*)( ((uint8*)pdfhDirHeader) +
|
|
|
|
|
pdfhDirHeader->u4PaletteOffset);
|
|
|
|
|
uint32 u4_pal = 0;
|
|
|
|
|
|
|
|
|
|
// get the actual palette data from the directory file
|
|
|
|
|
while (u4_pal_count)
|
|
|
|
|
{
|
|
|
|
|
// create a new palette of the correct size and set its hash value to the stored value
|
|
|
|
|
|
|
|
|
|
CPal* ppal = new CPal(pdpc->u4ColoursUsed);
|
|
|
|
|
ppal->SetHashValue(pdpc->u4HashValue);
|
|
|
|
|
|
|
|
|
|
// push the palettes into an STL vector.
|
|
|
|
|
CLoadImageDirectory::plidImageDir->appal.push_back(ppal);
|
|
|
|
|
|
|
|
|
|
// copy the data across
|
|
|
|
|
memcpy(&ppal->aclrPalette[0], &pdpc->clr[0], pdpc->u4ColoursUsed * sizeof(CColour) );
|
|
|
|
|
|
|
|
|
|
pdpc = (SDirectoryPaletteChunk*) ((char*)pdpc + pdpc->u4Size);
|
|
|
|
|
u4_pal_count--;
|
|
|
|
|
u4_pal++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// add the raster elements to the map for easy locating
|
|
|
|
|
//
|
|
|
|
|
uint32 u4_chunks = pdfhDirHeader->u4RasterChunkCount;
|
|
|
|
|
SDirectoryFileChunk* pdfc = (SDirectoryFileChunk*)( ((uint8*)pdfhDirHeader) +
|
|
|
|
|
pdfhDirHeader->u4RasterChunkOffset);
|
|
|
|
|
|
|
|
|
|
// pdfc points to the first of the nodes...
|
|
|
|
|
while (u4_chunks)
|
|
|
|
|
{
|
|
|
|
|
// check that this ID is not already in directory map.
|
|
|
|
|
Assert(mapChunk[pdfc->u8HashValue] == NULL);
|
|
|
|
|
|
|
|
|
|
mapChunk[pdfc->u8HashValue] = pdfc;
|
|
|
|
|
pdfc = (SDirectoryFileChunk*) ((char*)pdfc + pdfc->u4Size);
|
|
|
|
|
u4_chunks--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Reserve enough virtual memory for the image file
|
|
|
|
|
gtxmTexMan.pvmeTextures->SetPagingRegion(u4LocalImageSize);
|
|
|
|
|
|
|
|
|
|
bValidImage = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//*********************************************************************************************
|
|
|
|
|
//
|
|
|
|
|
CLoadImageDirectory::~CLoadImageDirectory
|
|
|
|
|
(
|
|
|
|
|
)
|
|
|
|
|
//*************************************
|
|
|
|
|
{
|
|
|
|
|
dprintf("Waiting for local copy..\n");
|
|
|
|
|
|
|
|
|
|
// Spin and wait for mutext to finish
|
|
|
|
|
DWORD dw;
|
|
|
|
|
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
dw = WaitForSingleObject(hCopyLocal, 250);
|
|
|
|
|
if (dw == WAIT_TIMEOUT && pfnWorldNotify)
|
|
|
|
|
{
|
|
|
|
|
(pfnWorldNotify)(u4NotifyParam, 0, 0, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
while (dw != WAIT_OBJECT_0);
|
|
|
|
|
|
|
|
|
|
CloseHandle(hCopyLocal);
|
|
|
|
|
|
|
|
|
|
CloseHandle((HANDLE)pvThreadHandle);
|
|
|
|
|
|
|
|
|
|
if (bValidImage)
|
|
|
|
|
{
|
|
|
|
|
if (!bCopyResult)
|
|
|
|
|
{
|
|
|
|
|
// what should we do because the copy has failed....
|
|
|
|
|
AlwaysAssert(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Start the VM system...
|
|
|
|
|
if (!gtxmTexMan.pvmeTextures->bBeginPaging(strLocalImage,
|
|
|
|
|
pdfhDirHeader->u4PageableOffset,pdfhDirHeader->u4NonPageableCount,false))
|
|
|
|
|
{
|
|
|
|
|
// failed to start the VM system.
|
|
|
|
|
Assert(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If the auto commit flag is set then load the whole swap file, otherwise
|
|
|
|
|
// start the loader thread so we can begin loading the required data.
|
|
|
|
|
if (bAutoCommit)
|
|
|
|
|
{
|
|
|
|
|
gtxmTexMan.pvmeTextures->CommitAll();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Start the thread
|
|
|
|
|
gtxmTexMan.pvmeTextures->ResumeVMLoadThread();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// go through all the palettes in the STL vector and delete them. This is safe because no
|
|
|
|
|
// raster should reference one of these palettes. All rasters should have created their
|
|
|
|
|
// own palettes.
|
|
|
|
|
|
2020-03-31 09:51:46 +00:00
|
|
|
|
for (std::vector<CPal*>::iterator i = appal.begin(); i<appal.end(); ++i)
|
2018-01-01 22:07:24 +00:00
|
|
|
|
{
|
|
|
|
|
delete (*i);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// delete the memory for the image file..
|
|
|
|
|
delete pdfhDirHeader;
|
|
|
|
|
pdfhDirHeader = NULL;
|
|
|
|
|
|
|
|
|
|
plidImageDir = NULL; // zero out the static class pointer
|
|
|
|
|
bValidImage = false; // image is not longer valid
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//*********************************************************************************************
|
|
|
|
|
// process the local swap file, if there is not a swap file locally copy it
|
|
|
|
|
// across.
|
|
|
|
|
// This will return true if all is OK. str_local_swap_image is the name returned by this
|
|
|
|
|
// function as the name of the swap file to load. If we are loading the non-local swap file
|
|
|
|
|
// copy its filename into this buffer.
|
|
|
|
|
//
|
|
|
|
|
bool CLoadImageDirectory::bProcessLocalSwapFile
|
|
|
|
|
(
|
|
|
|
|
const char* str_grf_name // name of the GRF swap file
|
|
|
|
|
)
|
|
|
|
|
//*************************************
|
|
|
|
|
{
|
|
|
|
|
char str_local_swap_dir[MAX_PATH];
|
|
|
|
|
|
|
|
|
|
bCopyResult = false;
|
|
|
|
|
bCompressed = true;
|
|
|
|
|
bNewCompression = true;
|
|
|
|
|
|
|
|
|
|
i4Error = 0;
|
|
|
|
|
|
|
|
|
|
GetRegString("Installed Directory", str_local_swap_dir, MAX_PATH, "");
|
|
|
|
|
|
|
|
|
|
// Check the last character of the install path.
|
|
|
|
|
char ch_last = *(str_local_swap_dir+strlen(str_local_swap_dir)-1);
|
|
|
|
|
if ((ch_last == '\\') || (ch_last == '/'))
|
|
|
|
|
{
|
|
|
|
|
*(str_local_swap_dir+strlen(str_local_swap_dir)-1) = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Make the name of the compressed file
|
|
|
|
|
strcpy(strSourceImage, str_grf_name);
|
|
|
|
|
strcpy(strSourceImage + strlen(strSourceImage) - 4, strCOMP_FILE_EXTENTSION);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// check if the GRF file has a swap file with it, if it does not then
|
|
|
|
|
// do not bother looking any futher
|
|
|
|
|
//
|
|
|
|
|
if (!NEW_SWAP_COMPRESSION || !bFileExists(strSourceImage))
|
|
|
|
|
{
|
|
|
|
|
dprintf("No SPZ file (compressed swap file) with GRF file. (%s)\n", strSourceImage);
|
|
|
|
|
bNewCompression = false;
|
|
|
|
|
|
|
|
|
|
// Modify the pathname to look for a old style compressed swap file.
|
|
|
|
|
strcpy(strSourceImage + strlen(strSourceImage) - strlen(strCOMP_FILE_EXTENTSION), strCOMP_FILE_EXTENTSION_OLD);
|
|
|
|
|
if (!bFileExists(strSourceImage))
|
|
|
|
|
{
|
|
|
|
|
dprintf("No SPP file (old compressed swap file) with GRF file. (%s)\n", strSourceImage);
|
|
|
|
|
bCompressed = false;
|
|
|
|
|
|
|
|
|
|
// Modify the pathname to look for a uncompressed swap file.
|
|
|
|
|
strcpy(strSourceImage + strlen(strSourceImage) - strlen(strCOMP_FILE_EXTENTSION), strSWP_FILE_EXTENTSION);
|
|
|
|
|
if (!bFileExists(strSourceImage))
|
|
|
|
|
{
|
|
|
|
|
dprintf("No SWP file (uncompressed swap file) with GRF file. (%s)\n", strSourceImage);
|
|
|
|
|
|
|
|
|
|
#if (WARN_ON_NO_SWAP)
|
|
|
|
|
Warning("No swap file");
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
SetEvent(hCopyLocal);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// get the last written time of the swp file with the GRF file and its size
|
|
|
|
|
u8SourceImageTime = u8FileTimeLastWritten(strSourceImage);
|
|
|
|
|
u4SourceSize = u4FileSize(strSourceImage);
|
|
|
|
|
|
|
|
|
|
if (bNewCompression)
|
|
|
|
|
u4LocalImageSize = u4OriginalFileSize(strSourceImage);
|
|
|
|
|
else
|
|
|
|
|
u4LocalImageSize = u4FileSize(strSourceImage, bCompressed);
|
|
|
|
|
|
|
|
|
|
Assert(u8SourceImageTime>0);
|
|
|
|
|
Assert(u8SourceImageTime!=0xffffffff);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// The GRF file has a swap file so check if we have a local version of
|
|
|
|
|
// the same swp file.
|
|
|
|
|
//
|
|
|
|
|
// This is the name of the local swap file if one exists..
|
|
|
|
|
//
|
|
|
|
|
strcpy(strLocalImage, str_local_swap_dir);
|
|
|
|
|
strcat(strLocalImage, "\\");
|
|
|
|
|
strcat(strLocalImage, strLeafName(strSourceImage) );
|
|
|
|
|
// Make sure the local image ends in SWP
|
|
|
|
|
strcpy(strLocalImage + strlen(strLocalImage) - strlen(strSWP_FILE_EXTENTSION), strSWP_FILE_EXTENTSION);
|
|
|
|
|
|
|
|
|
|
if (bFileExists(strLocalImage))
|
|
|
|
|
{
|
|
|
|
|
// There is a local version of this swap file, does it have the same last accessed date
|
|
|
|
|
// and the same size as the version with the GRF file??
|
|
|
|
|
uint64 u8_local_time = u8FileTimeLastWritten(strLocalImage);
|
|
|
|
|
|
|
|
|
|
if ((u8_local_time == u8SourceImageTime) && (u4LocalImageSize == u4FileSize(strLocalImage)))
|
|
|
|
|
{
|
|
|
|
|
// We have a match for the swap file so copy the name of the file to load.
|
|
|
|
|
dprintf("Using local swap file..\n");
|
|
|
|
|
|
|
|
|
|
if (pfnWorldNotify)
|
|
|
|
|
{
|
|
|
|
|
(pfnWorldNotify)(u4NotifyParam, 2, 99, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SetEvent(hCopyLocal);
|
|
|
|
|
|
|
|
|
|
bCopyResult = true;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Local swap file is out of date or bad, delete it.
|
|
|
|
|
SetFileAttributes(strLocalImage, FILE_ATTRIBUTE_NORMAL);
|
|
|
|
|
DeleteFile(strLocalImage);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// We cannot create a temp file called the same as local swap file so we must assume
|
|
|
|
|
// that the copy will fail, or the local directory path is NULL.
|
|
|
|
|
// In this case we can use the swap file that is with the GRF file..
|
|
|
|
|
//
|
|
|
|
|
if ((*str_local_swap_dir == 0) || !bCanCreateFile(strLocalImage))
|
|
|
|
|
{
|
|
|
|
|
dprintf("Cannot create local swap file - Is Trespasser installed??\n");
|
|
|
|
|
if (bCompressed)
|
|
|
|
|
{
|
|
|
|
|
// We have found a compressed swap file and this cannot be used so we need to look for
|
|
|
|
|
// a uncompressed version or fail the load and force it to use the conventional loader.
|
|
|
|
|
strcpy(strSourceImage + strlen(strSourceImage) - strlen(strCOMP_FILE_EXTENTSION), strSWP_FILE_EXTENTSION);
|
|
|
|
|
if (!bFileExists(strSourceImage))
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
// There is only a compressed swap file and this machine does not have Trespasser installed so
|
|
|
|
|
// no registry key can be found, hence we have no idea where to decompress the file to. If the
|
|
|
|
|
// uncompressed swap file had been present it would have been used in place without being copied
|
|
|
|
|
// locally. Compressed swap files must be copied locally in order to decompress them and therefore
|
|
|
|
|
// Trespasser must be installed.
|
|
|
|
|
//
|
|
|
|
|
dprintf("No uncompressed swap file with GRF file. Using conventional loader\n", strSourceImage);
|
|
|
|
|
AlwaysAssert(0);
|
|
|
|
|
SetEvent(hCopyLocal);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
dprintf("Using GRF swap file - Cannot create local.\n");
|
|
|
|
|
strcpy(strLocalImage,strSourceImage);
|
|
|
|
|
bCopyResult = true;
|
|
|
|
|
SetEvent(hCopyLocal);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// If we manage to get to here we need to create a local swap file....
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Before we copy local ensure that we have not reached our quota for used disk space
|
|
|
|
|
char str_wildcard[MAX_PATH];
|
|
|
|
|
_finddata_t fnd;
|
2020-03-31 09:51:46 +00:00
|
|
|
|
std::vector<SDiskSwapFile> vdsf;
|
2018-01-01 22:07:24 +00:00
|
|
|
|
|
|
|
|
|
strcpy(str_wildcard,str_local_swap_dir);
|
|
|
|
|
strcat(str_wildcard,"\\*.swp");
|
|
|
|
|
|
|
|
|
|
int32 i4_ffhandle = _findfirst(str_wildcard, &fnd);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// If FindFirst reports an error there is probably no files that match so copy the
|
|
|
|
|
// swap file without any other regards.
|
|
|
|
|
//
|
|
|
|
|
if (i4_ffhandle!=-1)
|
|
|
|
|
{
|
|
|
|
|
uint32 u4_count = 0;
|
|
|
|
|
uint32 u4_totalsize = 0;
|
|
|
|
|
int32 i4_res = 0;
|
|
|
|
|
|
|
|
|
|
while (i4_res==0)
|
|
|
|
|
{
|
|
|
|
|
SDiskSwapFile dsf;
|
|
|
|
|
|
|
|
|
|
strcpy(dsf.strFilename,str_local_swap_dir);
|
|
|
|
|
strcat(dsf.strFilename,"\\");
|
|
|
|
|
strcat(dsf.strFilename,fnd.name);
|
|
|
|
|
|
|
|
|
|
// FAT system do not support a last access time stamp, if this time is -1 then use
|
|
|
|
|
// the write time stamp. This effectively changes the caching system from an LRU to
|
|
|
|
|
// FIFO.
|
|
|
|
|
if (fnd.time_access == -1)
|
|
|
|
|
{
|
|
|
|
|
dsf.u4Time = fnd.time_write;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
dsf.u4Time = fnd.time_access;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dsf.u4Size = fnd.size;
|
|
|
|
|
u4_totalsize += fnd.size;
|
|
|
|
|
|
|
|
|
|
dsf.bDeleted = false;
|
|
|
|
|
|
|
|
|
|
vdsf.push_back(dsf);
|
|
|
|
|
u4_count++;
|
|
|
|
|
|
|
|
|
|
// find the next matching file
|
|
|
|
|
i4_res = _findnext(i4_ffhandle, &fnd);
|
|
|
|
|
}
|
|
|
|
|
_findclose(i4_ffhandle);
|
|
|
|
|
|
|
|
|
|
// If the SwpSpace registry key is not present then assume the max size is 0,
|
|
|
|
|
// This is effect means that there will only ever be a single swap file locally.
|
|
|
|
|
uint32 u4_swap_disk_space = (uint32)GetRegValue("SwapSpaceMb", 0) * 1024 * 1024;
|
|
|
|
|
int32 i4_space_free = int(u4_swap_disk_space) - int(u4_totalsize);
|
|
|
|
|
|
|
|
|
|
// Have a guess at the decompressed size
|
|
|
|
|
int32 i4_space_required = int(u4LocalImageSize) - i4_space_free;
|
|
|
|
|
|
|
|
|
|
if (i4_space_required>0)
|
|
|
|
|
{
|
|
|
|
|
uint32 u4_files = u4_count;
|
|
|
|
|
uint32 u4_oldest = 0xffffffff;
|
|
|
|
|
uint32 u4_oldtime = 0xffffffff;
|
|
|
|
|
|
|
|
|
|
// we need to clean out some old swap files to make our new one fit.
|
|
|
|
|
dprintf("Cleaning out old swap files.\n");
|
|
|
|
|
|
|
|
|
|
// If we have any swap files left in the directory and we still need to find more room
|
|
|
|
|
// go and delete another file.
|
|
|
|
|
while ((u4_files>0) && (i4_space_required>0))
|
|
|
|
|
{
|
|
|
|
|
for (int i=0; i<u4_count; i++)
|
|
|
|
|
{
|
|
|
|
|
if ( vdsf[i].bDeleted == false)
|
|
|
|
|
{
|
|
|
|
|
if ( vdsf[i].u4Time<u4_oldtime)
|
|
|
|
|
{
|
|
|
|
|
u4_oldest = i;
|
|
|
|
|
u4_oldtime = vdsf[i].u4Time;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Assert(u4_oldest!=0xffffffff);
|
|
|
|
|
|
|
|
|
|
// delete the element u4_oldest in the vector
|
|
|
|
|
Assert(vdsf[u4_oldest].bDeleted == false);
|
|
|
|
|
vdsf[u4_oldest].bDeleted = true;
|
|
|
|
|
|
|
|
|
|
// Switch off any flags, such as read only, so it can be deleted.
|
|
|
|
|
char* str_delete = vdsf[u4_oldest].strFilename;
|
|
|
|
|
SetFileAttributes(str_delete,FILE_ATTRIBUTE_NORMAL);
|
|
|
|
|
if (DeleteFile(str_delete))
|
|
|
|
|
{
|
|
|
|
|
// if we successfully deleted the file, subtract its size from the amount required.
|
|
|
|
|
i4_space_required-=vdsf[u4_oldest].u4Size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
u4_oldest = 0xffffffff;
|
|
|
|
|
u4_oldtime = 0xffffffff;
|
|
|
|
|
|
|
|
|
|
u4_files--;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// At this point we need to check to see if there is enough space
|
|
|
|
|
// on the local drive to copy the swap file.
|
|
|
|
|
//
|
|
|
|
|
{
|
|
|
|
|
char szDrive[50];
|
|
|
|
|
uint32 u4SectorsPerCluster;
|
|
|
|
|
uint32 u4BytesPerSector;
|
|
|
|
|
uint32 u4FreeClusters;
|
|
|
|
|
uint32 u4TotalClusters;
|
|
|
|
|
|
|
|
|
|
_splitpath(strLocalImage, szDrive, NULL, NULL, NULL);
|
|
|
|
|
strcat(szDrive, "\\");
|
|
|
|
|
|
|
|
|
|
GetDiskFreeSpace(szDrive,
|
|
|
|
|
(unsigned long *)&u4SectorsPerCluster,
|
|
|
|
|
(unsigned long *)&u4BytesPerSector,
|
|
|
|
|
(unsigned long *)&u4FreeClusters,
|
|
|
|
|
(unsigned long *)&u4TotalClusters);
|
|
|
|
|
// Check for enough free space for a save
|
|
|
|
|
if (u4SectorsPerCluster * u4BytesPerSector * u4FreeClusters < u4LocalImageSize)
|
|
|
|
|
{
|
|
|
|
|
i4Error = -2;
|
|
|
|
|
SetEvent(hCopyLocal);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if (THREADED_COPY)
|
|
|
|
|
uint32 u4_thread_id;
|
|
|
|
|
|
|
|
|
|
// Create the thread that will do the processing.....
|
|
|
|
|
pvThreadHandle = (void*)CreateThread(
|
|
|
|
|
NULL, // no security attributes
|
|
|
|
|
0, // use default stack size
|
|
|
|
|
(LPTHREAD_START_ROUTINE) u4CopyLocalThread,
|
|
|
|
|
NULL, // argument to thread function
|
|
|
|
|
0, // create running
|
|
|
|
|
(ULONG*)&u4_thread_id); // returns the thread identifier
|
|
|
|
|
|
|
|
|
|
dprintf("Thread Create: CopyLocalThread [Thread handle 0x%x]\n", u4_thread_id);
|
|
|
|
|
#else
|
|
|
|
|
// if we are not threaded, just call the thread function..
|
|
|
|
|
u4CopyLocalThread(0);
|
|
|
|
|
pvThreadHandle = NULL;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//*********************************************************************************************
|
|
|
|
|
//
|
|
|
|
|
// A Function that reads the size from one of our newly compressed files.
|
|
|
|
|
//
|
|
|
|
|
uint32 u4OriginalFileSize(const char *str_filename)
|
|
|
|
|
//
|
|
|
|
|
//*************************************
|
|
|
|
|
{
|
|
|
|
|
HANDLE hFileSrc;
|
|
|
|
|
DWORD dwRead;
|
|
|
|
|
BOOL bRet;
|
|
|
|
|
|
|
|
|
|
uint32 u4_file_size = 0;
|
|
|
|
|
|
|
|
|
|
// Open the source file.
|
|
|
|
|
hFileSrc = CreateFile(str_filename,
|
|
|
|
|
GENERIC_READ,
|
|
|
|
|
0,
|
|
|
|
|
NULL,
|
|
|
|
|
OPEN_EXISTING,
|
|
|
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
|
|
if (hFileSrc == INVALID_HANDLE_VALUE)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Read the un-compressed size from the file.
|
|
|
|
|
bRet = ReadFile(hFileSrc, &u4_file_size, sizeof(u4_file_size), &dwRead, NULL);
|
|
|
|
|
Assert(bRet && dwRead == sizeof(u4_file_size));
|
|
|
|
|
|
|
|
|
|
// Close the file.
|
|
|
|
|
CloseHandle(hFileSrc);
|
|
|
|
|
|
|
|
|
|
return u4_file_size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//*********************************************************************************************
|
|
|
|
|
// Function actually does the copy operation, either in a thread or by being called directly.
|
|
|
|
|
//
|
|
|
|
|
uint32 CLoadImageDirectory::u4CopyLocalThread
|
|
|
|
|
(
|
|
|
|
|
uint32 u4_user
|
|
|
|
|
)
|
|
|
|
|
//*************************************
|
|
|
|
|
{
|
|
|
|
|
// get the data passed in..
|
|
|
|
|
CLoadImageDirectory* plid = CLoadImageDirectory::plidImageDir;
|
|
|
|
|
|
|
|
|
|
#if VER_TEST
|
|
|
|
|
dprintf("Creating local swap file (%s)...\n", bCompressed ? "Compressed" : "Copy");
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
CCycleTimer ctmr;
|
|
|
|
|
|
|
|
|
|
if (bNewCompression)
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
// Constants defining how the file was compressed.
|
|
|
|
|
//
|
|
|
|
|
const int N = 4096; // Size of ring buffer.
|
|
|
|
|
const int F = 18; // Upper limit for match_length.
|
|
|
|
|
const int THRESHOLD = 2; // Encode string into position and length
|
|
|
|
|
// if match_length is greater than this.
|
|
|
|
|
|
|
|
|
|
unsigned char text_buf[N]; // Ring buffer of size N.
|
|
|
|
|
int r; // Index into ring buffer.
|
|
|
|
|
int i;
|
|
|
|
|
unsigned int flags; // Decompression flags.
|
|
|
|
|
|
|
|
|
|
// File I/O stuff.
|
|
|
|
|
HANDLE hFileSrc; // Input file handle.
|
|
|
|
|
HANDLE hFileDest; // Output file handle.
|
|
|
|
|
const int i_bufsize = 4096; // Read buffer size.
|
|
|
|
|
unsigned char src_buf[i_bufsize]; // Buffer for reading.
|
|
|
|
|
unsigned char *src_base; // Points to one past the end of the data.
|
|
|
|
|
int i_srccnt = 0; // Source offset.
|
|
|
|
|
int i_dest_start; // Where we started filling the ring buffer at.
|
|
|
|
|
DWORD dwWritten, dwRead;
|
|
|
|
|
BOOL bRet;
|
|
|
|
|
uint32 u4_file_size;
|
2020-04-20 18:33:25 +00:00
|
|
|
|
uint32 u4_bytes_written = 0;
|
2018-01-01 22:07:24 +00:00
|
|
|
|
int iPercent;
|
|
|
|
|
int iLastPercent;
|
|
|
|
|
|
|
|
|
|
// Open the source file.
|
|
|
|
|
hFileSrc = CreateFile((char*)plid->strSourceImage,
|
|
|
|
|
GENERIC_READ,
|
|
|
|
|
0,
|
|
|
|
|
NULL,
|
|
|
|
|
OPEN_EXISTING,
|
|
|
|
|
FILE_ATTRIBUTE_NORMAL + FILE_FLAG_SEQUENTIAL_SCAN,
|
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
|
|
if (hFileSrc == INVALID_HANDLE_VALUE)
|
|
|
|
|
{
|
|
|
|
|
goto ThreadError;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Open the destination file.
|
|
|
|
|
hFileDest = CreateFile((char*)plid->strLocalImage,
|
|
|
|
|
GENERIC_WRITE,
|
|
|
|
|
0,
|
|
|
|
|
NULL,
|
|
|
|
|
CREATE_ALWAYS,
|
|
|
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
|
|
if (hFileDest == INVALID_HANDLE_VALUE)
|
|
|
|
|
{
|
|
|
|
|
CloseHandle(hFileSrc);
|
|
|
|
|
goto ThreadError;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Initialize progress bar.
|
|
|
|
|
if (plid->pfnWorldNotify)
|
|
|
|
|
{
|
|
|
|
|
(plid->pfnWorldNotify)(plid->u4NotifyParam, 3, 0, 100);
|
|
|
|
|
}
|
|
|
|
|
iLastPercent = 0;
|
|
|
|
|
|
|
|
|
|
// Read the un-compressed size from the file.
|
|
|
|
|
bRet = ReadFile(hFileSrc, &u4_file_size, sizeof(u4_file_size), &dwRead, NULL);
|
|
|
|
|
Assert(bRet);
|
|
|
|
|
|
|
|
|
|
// Clear the ring buffer.
|
|
|
|
|
for (i = 0; i < N - F; i++)
|
|
|
|
|
text_buf[i] = '\0';
|
|
|
|
|
|
|
|
|
|
r = N - F;
|
|
|
|
|
i_dest_start = r;
|
|
|
|
|
flags = 0;
|
|
|
|
|
|
|
|
|
|
#if (0 && VER_ASM && TARGET_PROCESSOR == PROCESSOR_PENTIUM)
|
|
|
|
|
|
|
|
|
|
// This doesn't seem to be any faster than the non-asm version.
|
|
|
|
|
__asm
|
|
|
|
|
{
|
|
|
|
|
mov eax,[flags] // eax = flags
|
|
|
|
|
mov esi,[i_srccnt] // esi = i_srccnt
|
|
|
|
|
mov ecx,[r] // ecx = r
|
|
|
|
|
mov ebx,[src_base] // ebx = src_base
|
|
|
|
|
lea edi,[text_buf] // edi = text_buf
|
|
|
|
|
|
|
|
|
|
FOREVER_LOOP:
|
|
|
|
|
shl ah,1 // mask & count
|
|
|
|
|
jnz KEEP_DECODING
|
|
|
|
|
|
|
|
|
|
// Check if we need to read.
|
|
|
|
|
cmp esi,0
|
|
|
|
|
jne NO_READ1
|
|
|
|
|
|
|
|
|
|
// Read.
|
|
|
|
|
call READ_BUFFER
|
|
|
|
|
|
|
|
|
|
test esi,esi
|
|
|
|
|
jnz NO_READ1
|
|
|
|
|
|
|
|
|
|
// EOF.
|
|
|
|
|
mov [r],ecx // ecx = r
|
|
|
|
|
jmp DONE
|
|
|
|
|
|
|
|
|
|
NO_READ1:
|
|
|
|
|
// Load new flags.
|
|
|
|
|
mov al,[ebx+esi] // src_base[i_srccnt]
|
|
|
|
|
inc esi // i_srccnt++
|
|
|
|
|
|
|
|
|
|
mov ah,1 // use ah as bit mask and to count 8.
|
|
|
|
|
|
|
|
|
|
KEEP_DECODING:
|
|
|
|
|
test al,ah // test encoding bit.
|
|
|
|
|
jz ENCODED
|
|
|
|
|
|
|
|
|
|
// Not encoded.
|
|
|
|
|
|
|
|
|
|
// Check if we need to read.
|
|
|
|
|
cmp esi,0
|
|
|
|
|
jne NO_READ2
|
|
|
|
|
|
|
|
|
|
// Read.
|
|
|
|
|
call READ_BUFFER
|
|
|
|
|
|
|
|
|
|
test esi,esi
|
|
|
|
|
jnz NO_READ2
|
|
|
|
|
|
|
|
|
|
// EOF.
|
|
|
|
|
mov [r],ecx // ecx = r
|
|
|
|
|
jmp DONE
|
|
|
|
|
|
|
|
|
|
NO_READ2:
|
|
|
|
|
// Copy character.
|
|
|
|
|
mov dl,[ebx+esi]
|
|
|
|
|
inc esi
|
|
|
|
|
|
|
|
|
|
mov [edi+ecx],dl
|
|
|
|
|
inc ecx
|
|
|
|
|
|
|
|
|
|
// Check if we need to write.
|
|
|
|
|
cmp ecx,4096
|
|
|
|
|
jne FOREVER_LOOP
|
|
|
|
|
|
|
|
|
|
// Write.
|
|
|
|
|
call WRITE_BUFFER
|
|
|
|
|
|
|
|
|
|
jmp FOREVER_LOOP
|
|
|
|
|
|
|
|
|
|
ENCODED:
|
|
|
|
|
// Check if we have 2 bytes.
|
|
|
|
|
cmp esi,-2
|
|
|
|
|
jle HAVE_TWO
|
|
|
|
|
|
|
|
|
|
// Check if we need to read.
|
|
|
|
|
cmp esi,0
|
|
|
|
|
jne NO_READ3
|
|
|
|
|
|
|
|
|
|
// Read.
|
|
|
|
|
call READ_BUFFER
|
|
|
|
|
|
|
|
|
|
test esi,esi
|
|
|
|
|
jnz NO_READ3
|
|
|
|
|
|
|
|
|
|
// EOF.
|
|
|
|
|
mov [r],ecx // ecx = r
|
|
|
|
|
jmp DONE
|
|
|
|
|
|
|
|
|
|
NO_READ3:
|
|
|
|
|
mov dl,[ebx+esi] // lower 8 bits of index
|
|
|
|
|
inc esi
|
|
|
|
|
|
|
|
|
|
// Check if we need to read.
|
|
|
|
|
cmp esi,0
|
|
|
|
|
jne NO_READ4
|
|
|
|
|
|
|
|
|
|
push edx
|
|
|
|
|
|
|
|
|
|
// Read.
|
|
|
|
|
call READ_BUFFER
|
|
|
|
|
|
|
|
|
|
pop edx
|
|
|
|
|
|
|
|
|
|
test esi,esi
|
|
|
|
|
jnz NO_READ4
|
|
|
|
|
|
|
|
|
|
// EOF.
|
|
|
|
|
mov [r],ecx // ecx = r
|
|
|
|
|
jmp DONE
|
|
|
|
|
|
|
|
|
|
NO_READ4:
|
|
|
|
|
mov bl,[ebx+esi] // upper 4 bits of index + count
|
|
|
|
|
inc esi
|
|
|
|
|
|
|
|
|
|
jmp DONE_WITH_READ
|
|
|
|
|
|
|
|
|
|
HAVE_TWO:
|
|
|
|
|
mov dl,[ebx+esi] // lower 8 bits of index
|
|
|
|
|
|
|
|
|
|
mov bl,[ebx+esi+1] // upper 4 bits of index + count
|
|
|
|
|
add esi,2 // i_srccnt += 2
|
|
|
|
|
|
|
|
|
|
DONE_WITH_READ:
|
|
|
|
|
mov dh,bl // copy count
|
|
|
|
|
and bl,0x0f // mask bits of count
|
|
|
|
|
|
|
|
|
|
shr dh,4 // shift bits of index down
|
|
|
|
|
add bl,3 // add THRESHOLD+1
|
|
|
|
|
|
|
|
|
|
and edx,4095 // and with N-1
|
|
|
|
|
|
|
|
|
|
DECODE_LOOP:
|
|
|
|
|
mov bh,[edi+edx] // read byte from ring buffer.
|
|
|
|
|
inc edx
|
|
|
|
|
|
|
|
|
|
mov [edi+ecx],bh // write byte to ring buffer.
|
|
|
|
|
inc ecx
|
|
|
|
|
|
|
|
|
|
// Check if we need to write.
|
|
|
|
|
cmp ecx,4096
|
|
|
|
|
jne NO_WRITE
|
|
|
|
|
|
|
|
|
|
push edx
|
|
|
|
|
push ebx
|
|
|
|
|
|
|
|
|
|
// Write.
|
|
|
|
|
call WRITE_BUFFER
|
|
|
|
|
|
|
|
|
|
pop ebx
|
|
|
|
|
pop edx
|
|
|
|
|
|
|
|
|
|
NO_WRITE:
|
|
|
|
|
and edx,4095 // and with N-1
|
|
|
|
|
|
|
|
|
|
dec bl
|
|
|
|
|
jnz DECODE_LOOP
|
|
|
|
|
|
|
|
|
|
mov ebx,[src_base]
|
|
|
|
|
jmp FOREVER_LOOP
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Write a block of data to the output file.
|
|
|
|
|
WRITE_BUFFER:
|
|
|
|
|
__asm
|
|
|
|
|
{
|
|
|
|
|
mov [flags],eax // eax = flags
|
|
|
|
|
mov [i_srccnt],esi // esi = i_srccnt
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
// Write from ring buffer.
|
|
|
|
|
bRet = WriteFile(hFileDest, text_buf+i_dest_start, N-i_dest_start, &dwWritten, NULL);
|
|
|
|
|
if (!bRet || (iRead != dwWritten))
|
|
|
|
|
{
|
|
|
|
|
plid->i4Error = -2;
|
|
|
|
|
CloseHandle(hFileSrc);
|
|
|
|
|
CloseHandle(hFileDest);
|
|
|
|
|
// TODO: return error code here.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Show progress.
|
|
|
|
|
u4_bytes_written += N-i_dest_start;
|
|
|
|
|
iPercent = (u4_bytes_written * 100 / u4_file_size);
|
|
|
|
|
if (iPercent > iLastPercent)
|
|
|
|
|
{
|
|
|
|
|
if (plid->pfnWorldNotify)
|
|
|
|
|
{
|
|
|
|
|
(plid->pfnWorldNotify)(plid->u4NotifyParam, 2, iPercent, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
iLastPercent = iPercent;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r = 0;
|
|
|
|
|
i_dest_start = 0;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
__asm
|
|
|
|
|
{
|
|
|
|
|
mov eax,[flags] // eax = flags
|
|
|
|
|
mov esi,[i_srccnt] // esi = i_srccnt
|
|
|
|
|
mov ecx,[r] // ecx = r
|
|
|
|
|
mov ebx,[src_base] // ebx = src_base
|
|
|
|
|
lea edi,[text_buf] // edi = text_buf
|
|
|
|
|
|
|
|
|
|
ret
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Read a block of data from the input file.
|
|
|
|
|
READ_BUFFER:
|
|
|
|
|
__asm
|
|
|
|
|
{
|
|
|
|
|
mov [flags],eax // eax = flags
|
|
|
|
|
mov [r],ecx // ecx = r
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
// Read buffer.
|
|
|
|
|
bRet = ReadFile(hFileSrc, src_buf, i_bufsize, &dwRead, NULL);
|
|
|
|
|
Assert(bRet);
|
|
|
|
|
|
|
|
|
|
// EOF if (dwRead == 0).
|
|
|
|
|
|
|
|
|
|
src_base = src_buf + dwRead;
|
|
|
|
|
i_srccnt = -dwRead;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
__asm
|
|
|
|
|
{
|
|
|
|
|
mov eax,[flags] // eax = flags
|
|
|
|
|
mov esi,[i_srccnt] // esi = i_srccnt
|
|
|
|
|
mov ecx,[r] // ecx = r
|
|
|
|
|
mov ebx,[src_base] // ebx = src_base
|
|
|
|
|
lea edi,[text_buf] // edi = text_buf
|
|
|
|
|
|
|
|
|
|
ret
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DONE:
|
|
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
int j, k;
|
|
|
|
|
|
|
|
|
|
for (;;)
|
|
|
|
|
{
|
|
|
|
|
// Shift encoding flags & decrement count.
|
|
|
|
|
flags >>= 1;
|
|
|
|
|
|
|
|
|
|
// Check count to see if we need new flags.
|
|
|
|
|
if ((flags & 256) == 0)
|
|
|
|
|
{
|
|
|
|
|
// Read a character.
|
|
|
|
|
if (i_srccnt == 0)
|
|
|
|
|
{
|
|
|
|
|
// Read buffer.
|
|
|
|
|
bRet = ReadFile(hFileSrc, src_buf, i_bufsize, &dwRead, NULL);
|
|
|
|
|
Assert(bRet);
|
|
|
|
|
|
|
|
|
|
// EOF.
|
|
|
|
|
if (dwRead == 0)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
src_base = src_buf + dwRead;
|
|
|
|
|
i_srccnt = -dwRead;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
flags = src_base[i_srccnt++];
|
|
|
|
|
|
|
|
|
|
flags |= 0xff00; // Uses higher byte cleverly to count eight.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check encoding flags.
|
|
|
|
|
if (flags & 1)
|
|
|
|
|
{
|
|
|
|
|
// Read a character.
|
|
|
|
|
if (i_srccnt == 0)
|
|
|
|
|
{
|
|
|
|
|
// Read buffer.
|
|
|
|
|
bRet = ReadFile(hFileSrc, src_buf, i_bufsize, &dwRead, NULL);
|
|
|
|
|
Assert(bRet);
|
|
|
|
|
|
|
|
|
|
// EOF.
|
|
|
|
|
if (dwRead == 0)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
src_base = src_buf + dwRead;
|
|
|
|
|
i_srccnt = -dwRead;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Copy character.
|
|
|
|
|
text_buf[r++] = src_base[i_srccnt++];
|
|
|
|
|
|
|
|
|
|
// See if we need to write.
|
|
|
|
|
if (r == N)
|
|
|
|
|
{
|
|
|
|
|
// Write from ring buffer.
|
|
|
|
|
bRet = WriteFile(hFileDest, text_buf+i_dest_start, r-i_dest_start, &dwWritten, NULL);
|
|
|
|
|
if (!bRet || (r-i_dest_start != dwWritten))
|
|
|
|
|
{
|
|
|
|
|
plid->i4Error = -2;
|
|
|
|
|
CloseHandle(hFileSrc);
|
|
|
|
|
CloseHandle(hFileDest);
|
|
|
|
|
goto ThreadError;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Show progress.
|
|
|
|
|
u4_bytes_written += r-i_dest_start;
|
|
|
|
|
iPercent = (u4_bytes_written * 100 / u4_file_size);
|
|
|
|
|
if (iPercent > iLastPercent)
|
|
|
|
|
{
|
|
|
|
|
if (plid->pfnWorldNotify)
|
|
|
|
|
{
|
|
|
|
|
(plid->pfnWorldNotify)(plid->u4NotifyParam, 2, iPercent, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
iLastPercent = iPercent;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r = 0;
|
|
|
|
|
i_dest_start = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Read a 2 characters.
|
|
|
|
|
if (i_srccnt > -2)
|
|
|
|
|
{
|
|
|
|
|
// Read buffer.
|
|
|
|
|
if (i_srccnt == 0)
|
|
|
|
|
{
|
|
|
|
|
bRet = ReadFile(hFileSrc, src_buf, i_bufsize, &dwRead, NULL);
|
|
|
|
|
Assert(bRet);
|
|
|
|
|
|
|
|
|
|
// EOF.
|
|
|
|
|
if (dwRead == 0)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
src_base = src_buf + dwRead;
|
|
|
|
|
i_srccnt = -dwRead;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
i = src_base[i_srccnt++];
|
|
|
|
|
|
|
|
|
|
// Read a character.
|
|
|
|
|
if (i_srccnt == 0)
|
|
|
|
|
{
|
|
|
|
|
// Read buffer.
|
|
|
|
|
bRet = ReadFile(hFileSrc, src_buf, i_bufsize, &dwRead, NULL);
|
|
|
|
|
Assert(bRet);
|
|
|
|
|
|
|
|
|
|
// EOF.
|
|
|
|
|
if (dwRead == 0)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
src_base = src_buf + dwRead;
|
|
|
|
|
i_srccnt = -dwRead;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
j = src_base[i_srccnt++];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
i = src_base[i_srccnt++];
|
|
|
|
|
j = src_base[i_srccnt++];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Convert to index & count.
|
|
|
|
|
i |= ((j & 0xf0) << 4);
|
|
|
|
|
j = (j & 0x0f) + THRESHOLD;
|
|
|
|
|
|
|
|
|
|
for (k = i; k <= i+j; k++)
|
|
|
|
|
{
|
|
|
|
|
// Store in ring buffer.
|
|
|
|
|
text_buf[r++] = text_buf[k & (N - 1)];
|
|
|
|
|
|
|
|
|
|
// See if we need to write.
|
|
|
|
|
if (r == N)
|
|
|
|
|
{
|
|
|
|
|
// Write from ring buffer.
|
|
|
|
|
bRet = WriteFile(hFileDest, text_buf+i_dest_start, r-i_dest_start, &dwWritten, NULL);
|
|
|
|
|
if (!bRet || (r-i_dest_start != dwWritten))
|
|
|
|
|
{
|
|
|
|
|
plid->i4Error = -2;
|
|
|
|
|
CloseHandle(hFileSrc);
|
|
|
|
|
CloseHandle(hFileDest);
|
|
|
|
|
goto ThreadError;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Show progress.
|
|
|
|
|
u4_bytes_written += r-i_dest_start;
|
|
|
|
|
iPercent = (u4_bytes_written * 100 / u4_file_size);
|
|
|
|
|
if (iPercent > iLastPercent)
|
|
|
|
|
{
|
|
|
|
|
if (plid->pfnWorldNotify)
|
|
|
|
|
{
|
|
|
|
|
(plid->pfnWorldNotify)(plid->u4NotifyParam, 2, iPercent, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
iLastPercent = iPercent;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r = 0;
|
|
|
|
|
i_dest_start = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// Flush buffer.
|
|
|
|
|
bRet = WriteFile(hFileDest, text_buf+i_dest_start, r-i_dest_start, &dwWritten, NULL);
|
|
|
|
|
if (!bRet || (r-i_dest_start != dwWritten))
|
|
|
|
|
{
|
|
|
|
|
plid->i4Error = -2;
|
|
|
|
|
CloseHandle(hFileSrc);
|
|
|
|
|
CloseHandle(hFileDest);
|
|
|
|
|
goto ThreadError;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Show progress as done.
|
|
|
|
|
if (plid->pfnWorldNotify)
|
|
|
|
|
{
|
|
|
|
|
(plid->pfnWorldNotify)(plid->u4NotifyParam, 2, 100, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Close the files.
|
|
|
|
|
CloseHandle(hFileSrc);
|
|
|
|
|
CloseHandle(hFileDest);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
int i_file_s;
|
|
|
|
|
OFSTRUCT ofs_s;
|
|
|
|
|
BYTE ab[4096];
|
|
|
|
|
int iRead;
|
|
|
|
|
HANDLE hFile;
|
|
|
|
|
DWORD dwWritten;
|
|
|
|
|
BOOL bRet;
|
|
|
|
|
int iLen;
|
|
|
|
|
int iChunk;
|
|
|
|
|
int iPercent;
|
|
|
|
|
int iLastPercent;
|
|
|
|
|
|
|
|
|
|
// Open the source file.
|
|
|
|
|
i_file_s = LZOpenFile((char*)plid->strSourceImage,&ofs_s,OF_READ);
|
|
|
|
|
if (i_file_s < 0)
|
|
|
|
|
{
|
|
|
|
|
goto ThreadError;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Open the destination file.
|
|
|
|
|
hFile = CreateFile((char*)plid->strLocalImage,
|
|
|
|
|
GENERIC_WRITE,
|
|
|
|
|
0,
|
|
|
|
|
NULL,
|
|
|
|
|
CREATE_ALWAYS,
|
|
|
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
|
|
if (hFile == INVALID_HANDLE_VALUE)
|
|
|
|
|
{
|
|
|
|
|
LZClose(i_file_s);
|
|
|
|
|
goto ThreadError;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
iLen = LZSeek(i_file_s, 0, 2);
|
|
|
|
|
LZSeek(i_file_s, 0, 0);
|
|
|
|
|
|
|
|
|
|
iLen /= 4096;
|
|
|
|
|
iChunk = 0;
|
|
|
|
|
iLastPercent = 0;
|
|
|
|
|
|
|
|
|
|
if (plid->pfnWorldNotify)
|
|
|
|
|
{
|
|
|
|
|
(plid->pfnWorldNotify)(plid->u4NotifyParam, 3, 0, 100);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while ((iRead = LZRead(i_file_s, (LPSTR)&ab, sizeof(ab))) > 0)
|
|
|
|
|
{
|
|
|
|
|
iChunk++;
|
|
|
|
|
iPercent = (iChunk * 100 / iLen);
|
|
|
|
|
if (iPercent > iLastPercent)
|
|
|
|
|
{
|
|
|
|
|
if (plid->pfnWorldNotify)
|
|
|
|
|
{
|
|
|
|
|
(plid->pfnWorldNotify)(plid->u4NotifyParam, 2, iPercent, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
iLastPercent = iPercent;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bRet = WriteFile(hFile, ab, iRead, &dwWritten, NULL);
|
|
|
|
|
if (!bRet || (iRead != dwWritten))
|
|
|
|
|
{
|
|
|
|
|
plid->i4Error = -2;
|
|
|
|
|
LZClose(i_file_s);
|
|
|
|
|
CloseHandle(hFile);
|
|
|
|
|
goto ThreadError;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (plid->pfnWorldNotify)
|
|
|
|
|
{
|
|
|
|
|
(plid->pfnWorldNotify)(plid->u4NotifyParam, 2, 100, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// close the files and clean up
|
|
|
|
|
LZClose(i_file_s);
|
|
|
|
|
CloseHandle(hFile);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dprintf("done creating local swap file...\n");
|
|
|
|
|
dprintf("in %f seconds.\n", (double)ctmr() * ctmr.fSecondsPerCycle());
|
|
|
|
|
bCopyResult = true;
|
|
|
|
|
|
|
|
|
|
// Now set the time stamp of the swap file to be the same as the swap file source
|
|
|
|
|
bFileSetTimeStamp(plid->strLocalImage, plid->u8SourceImageTime);
|
|
|
|
|
|
|
|
|
|
// Signal that the CopyLocal event is complete
|
|
|
|
|
SetEvent(hCopyLocal);
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
//******************************************************************************************
|
|
|
|
|
ThreadError:
|
|
|
|
|
dprintf("Failed to create local swap file..\n");
|
|
|
|
|
AlwaysAssert(0);
|
|
|
|
|
bCopyResult = false;
|
|
|
|
|
SetEvent(hCopyLocal);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|