iw5-mod/deps/HDiffPatch/dirDiffPatch/dir_patch/new_dir_output.c

341 lines
14 KiB
C

// new_dir_output.c
// hdiffz dir patch
//
/*
The MIT License (MIT)
Copyright (c) 2018-2019 HouSisong
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 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.
*/
#include "new_dir_output.h"
#include "../../file_for_patch.h"
#if (_IS_NEED_DIR_DIFF_PATCH)
#include "dir_patch_tools.h"
#include <stdio.h>
#include <string.h>
#define TUInt hpatch_StreamPos_t
#define checki(value,errorInfo) { if (!(value)){ LOG_ERR("dir_patch " errorInfo " error!\n"); \
result=hpatch_FALSE; goto clear; } }
#define check(value) checki(value,"check " #value)
static hpatch_BOOL _TDirPatcher_copyFile(const char* oldFileName_utf8,const char* newFileName_utf8,
hpatch_ICopyDataListener* copyListener,hpatch_FileError_t* out_fileError){
#define _tempCacheSize hpatch_kFileIOBufBetterSize
hpatch_BOOL result=hpatch_TRUE;
TByte temp_cache[_tempCacheSize];
hpatch_StreamPos_t pos=0;
hpatch_TFileStreamInput oldFile;
hpatch_TFileStreamOutput newFile;
hpatch_TFileStreamInput_init(&oldFile);
hpatch_TFileStreamOutput_init(&newFile);
check(hpatch_TFileStreamInput_open(&oldFile,oldFileName_utf8));
if (newFileName_utf8)
check(hpatch_TFileStreamOutput_open(&newFile,newFileName_utf8,oldFile.base.streamSize));
while (pos<oldFile.base.streamSize) {
size_t copyLen=_tempCacheSize;
if (pos+copyLen>oldFile.base.streamSize)
copyLen=(size_t)(oldFile.base.streamSize-pos);
check(oldFile.base.read(&oldFile.base,pos,temp_cache,temp_cache+copyLen));
if (newFileName_utf8)
check(newFile.base.write(&newFile.base,pos,temp_cache,temp_cache+copyLen));
if (copyListener)
copyListener->copyedData(copyListener,temp_cache,temp_cache+copyLen);
pos+=copyLen;
}
if (newFileName_utf8)
check(newFile.out_length==newFile.base.streamSize);
clear:
if (newFile.fileError) { result=hpatch_FALSE; set_ferr(*out_fileError,newFile.fileError); }
if (oldFile.fileError) { result=hpatch_FALSE; set_ferr(*out_fileError,oldFile.fileError); }
if (!hpatch_TFileStreamOutput_close(&newFile)){
result=hpatch_FALSE; mix_ferr(*out_fileError,newFile.fileError); }
if (!hpatch_TFileStreamInput_close(&oldFile)){
result=hpatch_FALSE; mix_ferr(*out_fileError,oldFile.fileError); }
return result;
#undef _tempCacheSize
}
hpatch_BOOL TDirPatcher_copyFile(const char* oldFileName_utf8,const char* newFileName_utf8,
hpatch_ICopyDataListener* copyListener,hpatch_FileError_t* out_fileError){
hpatch_BOOL result=hpatch_TRUE;
check(newFileName_utf8!=0);
result=_TDirPatcher_copyFile(oldFileName_utf8,newFileName_utf8,copyListener,out_fileError);
clear:
return result;
}
hpatch_BOOL TDirPatcher_readFile(const char* oldFileName_utf8,hpatch_ICopyDataListener* copyListener,hpatch_FileError_t* out_fileError){
return _TDirPatcher_copyFile(oldFileName_utf8,0,copyListener,out_fileError);
}
static hpatch_BOOL _tryCloseNewFile(TNewDirOutput* self){
hpatch_BOOL result;
hpatch_FileError_t fileError;
if (self->_curNewFile==0) return hpatch_TRUE;
result=self->_listener->closeNewFile(self->_listener,self->_curNewFile);
fileError=self->_curNewFile->fileError;
hpatch_TFileStreamOutput_init(self->_curNewFile);
return result&&(!fileError);
}
static hpatch_BOOL _makeNewDirOrEmptyFile(hpatch_INewStreamListener* listener,size_t newPathIndex){
hpatch_BOOL result=hpatch_TRUE;
TNewDirOutput* self=(TNewDirOutput*)listener->listenerImport;
const char* pathName=TNewDirOutput_getNewPathByIndex(self,newPathIndex);
check(pathName!=0);
if (hpatch_getIsDirName(pathName)){ //
check(self->_listener->makeNewDir(self->_listener,pathName));
}else{ //empty file
check(self->_listener->openNewFile(self->_listener,self->_curNewFile,pathName,0));
check(_tryCloseNewFile(self));
}
clear:
return result;
}
static const char* _getOldPathByIndex(TNewDirOutput* self,size_t oldPathIndex){
assert(self->_oldPathListener.getOldPathByIndex!=0);
return self->_oldPathListener.getOldPathByIndex(&self->_oldPathListener,oldPathIndex);
}
static hpatch_BOOL _copySameFile(hpatch_INewStreamListener* listener,size_t newPathIndex,size_t oldPathIndex){
hpatch_BOOL result=hpatch_TRUE;
TNewDirOutput* self=(TNewDirOutput*)listener->listenerImport;
const char* newFileName=0;
const char* oldFileName=0;
assert(newPathIndex<self->newPathCount);
newFileName=TNewDirOutput_getNewPathByIndex(self,newPathIndex);
check(newFileName!=0);
check(self->_oldPathListener.getOldPathByIndex!=0);
oldFileName=_getOldPathByIndex(self,oldPathIndex);
check(oldFileName!=0);
checki(self->_listener->copySameFile(self->_listener,oldFileName,newFileName,
self->isCheck_copyFileData?(&self->_sameFileCopyListener):0),
"_copySameFile() copySameFile");
clear:
return result;
}
static hpatch_BOOL _openNewFile(hpatch_INewStreamListener* listener,size_t newRefIndex,
const hpatch_TStreamOutput** out_newFileStream){
hpatch_BOOL result=hpatch_TRUE;
TNewDirOutput* self=(TNewDirOutput*)listener->listenerImport;
const char* utf8fileName=0;
hpatch_StreamPos_t fileSize;
assert((newRefIndex<self->newRefFileCount)&&(self->_curNewFile->base.write==0));
fileSize=self->newRefSizeList[newRefIndex];
if (fileSize==0){
size_t newPathIndex=self->newRefList?self->newRefList[newRefIndex]:newRefIndex;
check(_makeNewDirOrEmptyFile(listener,newPathIndex));
*out_newFileStream=0;
}else{
utf8fileName=TNewDirOutput_getNewPathByRefIndex(self,newRefIndex);
check(utf8fileName!=0);
checki(self->_listener->openNewFile(self->_listener,self->_curNewFile,
utf8fileName,fileSize),
"_openNewFile() openNewFile");
*out_newFileStream=&self->_curNewFile->base;
}
clear:
return result;
}
static hpatch_BOOL _closeNewFile(hpatch_INewStreamListener* listener,const hpatch_TStreamOutput* newFileStream){
hpatch_BOOL result=hpatch_TRUE;
TNewDirOutput* self=(TNewDirOutput*)listener->listenerImport;
assert((self->_curNewFile!=0)&&(newFileStream==&self->_curNewFile->base));
check(_tryCloseNewFile(self));
clear:
return result;
}
static void _writedNewRefData(struct hpatch_INewStreamListener* listener,const unsigned char* data,
const unsigned char* dataEnd){
TNewDirOutput* self=(TNewDirOutput*)listener->listenerImport;
if (self->isCheck_newRefData)
self->_checksumPlugin->append(self->_newRefChecksumHandle,data,dataEnd);
}
static hpatch_BOOL _do_checksumEnd(TNewDirOutput* self,const TByte* checksumTest,TByte* checksumTemp,
hpatch_checksumHandle* pcsHandle){
size_t checksumByteSize=self->_checksumPlugin->checksumByteSize();
hpatch_checksumHandle* csHandle=*pcsHandle;
assert(csHandle!=0);
*pcsHandle=0;
self->_checksumPlugin->end(csHandle,checksumTemp,checksumTemp+checksumByteSize);
self->_checksumPlugin->close(self->_checksumPlugin,csHandle);
return (0==memcmp(checksumTest,checksumTemp,checksumByteSize));
}
#define _pchecksumNewRef(_self) ((_self)->_pChecksum_newRefData_copyFileData)
#define _pchecksumCopyFile(_self) ((_self)->_pChecksum_newRefData_copyFileData+(_self)->checksumByteSize)
#define _pchecksumTemp(_self) ((_self)->_pChecksum_temp)
static hpatch_BOOL _writedFinish(struct hpatch_INewStreamListener* listener){
hpatch_BOOL result=hpatch_TRUE;
TNewDirOutput* self=(TNewDirOutput*)listener->listenerImport;
//checksum newRefData end
if (self->isCheck_newRefData){
if (!_do_checksumEnd(self,_pchecksumNewRef(self),_pchecksumTemp(self),&self->_newRefChecksumHandle))
self->_isNewRefDataChecksumError=hpatch_TRUE;
}
//checksum sameFileData end
if (self->isCheck_copyFileData){
if (!_do_checksumEnd(self,_pchecksumCopyFile(self),_pchecksumTemp(self),&self->_sameFileChecksumHandle))
self->_isCopyDataChecksumError=hpatch_TRUE;
}
check(!self->_isNewRefDataChecksumError);
check(!self->_isCopyDataChecksumError);
clear:
return result;
}
static void _sameFile_copyedData(hpatch_ICopyDataListener* listener,const unsigned char* data,
const unsigned char* dataEnd){
TNewDirOutput* self=(TNewDirOutput*)listener->listenerImport;
if (self->isCheck_copyFileData)
self->_checksumPlugin->append(self->_sameFileChecksumHandle,data,dataEnd);
}
hpatch_BOOL TNewDirOutput_openDir(TNewDirOutput* self,IDirPatchListener* listener,
size_t kAlignSize,const hpatch_TStreamOutput** out_newDirStream){
hpatch_BOOL result=hpatch_TRUE;
size_t refCount=self->newRefFileCount;
assert(self->_pmem==0);
assert(self->_newDirStream.stream==0);
assert(self->_newDirStreamListener.listenerImport==0);
self->_listener=listener;
{//open new
size_t memSize=sizeof(hpatch_TFileStreamOutput);
self->_pmem=malloc(memSize);
check(self->_pmem!=0);
self->_curNewFile=(hpatch_TFileStreamOutput*)self->_pmem;
hpatch_TFileStreamOutput_init(self->_curNewFile);
self->_newDirStreamListener.listenerImport=self;
self->_newDirStreamListener.makeNewDirOrEmptyFile=_makeNewDirOrEmptyFile;
self->_newDirStreamListener.copySameFile=_copySameFile;
self->_newDirStreamListener.openNewFile=_openNewFile;
self->_newDirStreamListener.closeNewFile=_closeNewFile;
self->_newDirStreamListener.writedNewRefData=_writedNewRefData;
self->_newDirStreamListener.writedFinish=_writedFinish;
}
//checksum newRefData begin
if (self->isCheck_newRefData){
assert(self->_newRefChecksumHandle==0);
self->_newRefChecksumHandle=self->_checksumPlugin->open(self->_checksumPlugin);
check(self->_newRefChecksumHandle!=0);
self->_checksumPlugin->begin(self->_newRefChecksumHandle);
}
//checksum sameFileData begin
if (self->isCheck_copyFileData){
assert(self->_sameFileChecksumHandle==0);
self->_sameFileChecksumHandle=self->_checksumPlugin->open(self->_checksumPlugin);
check(self->_sameFileChecksumHandle!=0);
self->_checksumPlugin->begin(self->_sameFileChecksumHandle);
if (self->isCheck_copyFileData){
self->_sameFileCopyListener.listenerImport=self;
self->_sameFileCopyListener.copyedData=_sameFile_copyedData;
}
}
checki(hpatch_TNewStream_open(&self->_newDirStream,&self->_newDirStreamListener,
self->newDataSize,self->newPathCount,
self->newRefList,refCount,self->dataSamePairList,
self->sameFilePairCount,kAlignSize),
"TNewDirOutput_openDir() hpatch_TNewStream_open");
*out_newDirStream=self->_newDirStream.stream;
clear:
return result;
}
hpatch_BOOL TNewDirOutput_closeNewDirHandles(TNewDirOutput* self){
hpatch_BOOL result=hpatch_TNewStream_closeFileHandles(&self->_newDirStream);
if (!_tryCloseNewFile(self)) result=hpatch_FALSE;
return result;
}
hpatch_BOOL TNewDirOutput_close(TNewDirOutput* self){
hpatch_BOOL result=TNewDirOutput_closeNewDirHandles(self);
hpatch_TChecksum* checksumPlugin=self->_checksumPlugin;
if (!hpatch_TNewStream_close(&self->_newDirStream))
result=hpatch_FALSE;
self->_newRootDir=0;
self->_newRootDir_end=0;
self->_newRootDir_bufEnd=0;
self->_curNewFile=0;
if (self->_newRefChecksumHandle){
checksumPlugin->close(checksumPlugin,self->_newRefChecksumHandle);
self->_newRefChecksumHandle=0;
}
if (self->_sameFileChecksumHandle){
checksumPlugin->close(checksumPlugin,self->_sameFileChecksumHandle);
self->_sameFileChecksumHandle=0;
}
if (self->_pmem) {
free(self->_pmem);
self->_pmem=0;
}
return result;
}
const char* TNewDirOutput_getNewPathRoot(TNewDirOutput* self){
if (!setPath(self->_newRootDir_end,self->_newRootDir_bufEnd,"")) return 0; //error
return self->_newRootDir;
}
const char* TNewDirOutput_getNewPathByIndex(TNewDirOutput* self,size_t newPathIndex){
assert(newPathIndex<self->newPathCount);
if (!setPath(self->_newRootDir_end,self->_newRootDir_bufEnd,
self->newUtf8PathList[newPathIndex])) return 0; //error
return self->_newRootDir;
}
const char* TNewDirOutput_getNewPathByRefIndex(TNewDirOutput* self,size_t newRefIndex){
size_t newPathIndex;
assert(newRefIndex<self->newRefFileCount);
newPathIndex=self->newRefList?self->newRefList[newRefIndex]:newRefIndex;
return TNewDirOutput_getNewPathByIndex(self,newPathIndex);
}
const char* TNewDirOutput_getNewExecuteFileByIndex(TNewDirOutput* self,size_t newExecuteIndex){
assert(newExecuteIndex<self->newExecuteCount);
return TNewDirOutput_getNewPathByIndex(self,self->newExecuteList[newExecuteIndex]);
}
const char* TNewDirOutput_getOldPathBySameIndex(TNewDirOutput* self,size_t sameIndex){
assert(sameIndex<self->sameFilePairCount);
assert(self->dataSamePairList!=0);
return _getOldPathByIndex(self,self->dataSamePairList[sameIndex].oldIndex);
}
const char* TNewDirOutput_getNewPathBySameIndex(TNewDirOutput* self,size_t sameIndex){
assert(sameIndex<self->sameFilePairCount);
assert(self->dataSamePairList!=0);
return TNewDirOutput_getNewPathByIndex(self,self->dataSamePairList[sameIndex].newIndex);
}
#endif