bool Replay::OpenReplay(const wchar_t* name) { wchar_t fname[256]; myswprintf(fname, mainGame->fileManager->GetRealPath(L"./replay/%ls").ToWString().c_str(), name); #ifdef WIN32 fp = _wfopen(fname, L"rb"); #else char fname2[256]; BufferIO::EncodeUTF8(fname, fname2); fp = fopen(fname2, "rb"); #endif if(!fp) return false; fseek(fp, 0, SEEK_END); comp_size = ftell(fp) - sizeof(pheader); fseek(fp, 0, SEEK_SET); fread(&pheader, sizeof(pheader), 1, fp); if(pheader.flag & REPLAY_COMPRESSED) { fread(comp_data, 0x1000, 1, fp); fclose(fp); replay_size = pheader.datasize; if(LzmaUncompress(replay_data, &replay_size, comp_data, &comp_size, pheader.props, 5) != SZ_OK) return false; } else { fread(replay_data, 0x20000, 1, fp); fclose(fp); replay_size = comp_size; } pdata = replay_data; is_replaying = true; return true; }
static int lzma_decompress_buf(struct stream *s, size_t c_len) { uchar *c_buf; size_t dlen = (size_t)s->buflen; int lzmaerr; c_buf = s->buf; s->buf = malloc(dlen); if (!s->buf) { err_msg("Failed to allocate %d bytes for decompression\n", dlen); return -1; } /* With LZMA SDK 4.63 we pass control.lzma_properties * which is needed for proper uncompress */ lzmaerr = LzmaUncompress(s->buf, &dlen, c_buf, &c_len, control.lzma_properties, 5); if (lzmaerr != 0) { err_msg("Failed to decompress buffer - lzmaerr=%d\n", lzmaerr); return -1; } if ((i64)dlen != s->buflen) { err_msg("Inconsistent length after decompression. Got %d bytes, expected %d\n", dlen, s->buflen); return -1; } free(c_buf); return 0; }
void Data::decompress(int FileID_) { #ifdef _WIN32 DWORD size = 0; #else /*_WIN32*/ size_t size = 0; #endif /*_WIN32*/ const uint8_t* compressedBuf = nullptr; int result; LoadFileInResource(FileID_, LZMA_STREAM, size, compressedBuf); assert(size > 13); uint8_t* compressedData = (uint8_t *)malloc(size+1); memcpy(compressedData, compressedBuf, size); compressedData[size] = 0; decompressedSize = *((size_t *)(compressedData+5)); DecompressedData = (uint8_t *)malloc(decompressedSize); result = LzmaUncompress(DecompressedData, &decompressedSize, (const uint8_t *)(compressedData+13), (SizeT *)&size, (const uint8_t *)compressedData, 5); free(compressedData); compressedData = nullptr; if (result != SZ_OK) { CodeConv::tostringstream o; o << _T("LZMAストリームのデコードに失敗しました。ファイルが壊れている虞があります。") << _T("エラーコード: ") << result; Raise(EXCEPTION_MJCORE_DECOMPRESSION_FAILURE, o.str().c_str()); } else { info(_T("LZMAストリームをデコードしました。")); } return; }
bool Replay::OpenReplay(const wchar_t* name) { wchar_t fname[256]; myswprintf(fname, L"./replay/%ls", name); #ifdef WIN32 fp = _wfopen(fname, L"rb"); #else char fname2[256]; BufferIO::EncodeUTF8(fname, fname2); fp = fopen(fname2, "rb"); #endif if(!fp) return false; fread(&pheader, sizeof(pheader), 1, fp); if(pheader.flag & REPLAY_COMPRESSED) { comp_size = fread(comp_data, 1, 0x1000, fp); fclose(fp); replay_size = pheader.datasize; if(LzmaUncompress(replay_data, &replay_size, comp_data, &comp_size, pheader.props, 5) != SZ_OK) return false; } else { comp_size = fread(replay_data, 1, 0x20000, fp); fclose(fp); replay_size = comp_size; } pdata = replay_data; is_replaying = true; return true; }
static u32 uncompress(BufferDest& dest, std::size_t& destlen, const BufferSrc& src, std::size_t& srclen, const lzma_props& props, std::size_t props_size = lzma_props::E_length) { return LzmaUncompress(reinterpret_cast<u8*>(&dest[0]), &destlen, reinterpret_cast<const u8*>(&src[0]), &srclen, &props[0], props_size); }
int sqlzma_un(struct sqlzma_un *un, struct sized_buf *src, struct sized_buf *dst) { int err, by_lzma = 1; if (un->un_lzma && is_lzma(*src->buf)) { un->un_cmbuf = src->buf; un->un_cmlen = src->sz; un->un_resbuf = dst->buf; un->un_reslen = dst->sz; /* this library is thread-safe */ err = LzmaUncompress(un); goto out; } by_lzma = 0; //#if defined(CONFIG_MIPS_BRCM) #if 1//disable zlib inflate /* The FS is compressed with LZMA for BRCM: do not use zlib */ printk("%s: ZLIB decompression is not supported\n", __func__); err = -EINVAL; #else err = zlib_inflateReset(&un->un_stream); if (unlikely(err != Z_OK)) goto out; un->un_stream.next_in = src->buf; un->un_stream.avail_in = src->sz; un->un_stream.next_out = dst->buf; un->un_stream.avail_out = dst->sz; err = zlib_inflate(&un->un_stream, Z_FINISH); if (err == Z_STREAM_END) err = 0; #endif out: if (unlikely(err)) { #ifdef __KERNEL__ WARN_ON_ONCE(1); #else char a[64] = "ZLIB "; if (by_lzma) { strcpy(a, "LZMA "); #ifdef _REENTRANT strerror_r(err, a + 5, sizeof(a) - 5); #else strncat(a, strerror(err), sizeof(a) - 5); #endif } else strncat(a, zError(err), sizeof(a) - 5); fprintf(stderr, "%s: %.*s\n", __func__, sizeof(a), a); #endif } return err; }
int LzmaCdecUncompress(BYTE* dest, int& destLen, const BYTE* src, int& srcLen, const BYTE* props, int propsSize) { size_t destLen_st = destLen; size_t srcLen_st = srcLen; int ret = LzmaUncompress(dest, &destLen_st, src, &srcLen_st, props, propsSize); destLen = (int)destLen_st; srcLen = (int)srcLen_st; return ret; }
size_t LzmaCompressor::decompress(void *dest_buf, size_t dest_size, const void *src_buf, size_t src_size) { int status; size_t destlen, propsize; const unsigned char *propbuf; propsize = LZMA_PROPS_SIZE; destlen = dest_size; propbuf = (unsigned char *)src_buf; status = LzmaUncompress((unsigned char *)dest_buf, &destlen, &(((unsigned char *)src_buf)[propsize]), &destlen, propbuf, propsize); return (status == SZ_OK) ? destlen : 0; }
int read_block(int fd, long long start, long long *next, unsigned char *block, squashfs_super_block *sBlk) { unsigned short c_byte; int offset = 2; if(swap) { read_bytes(fd, start, 2, (char *) block); ((unsigned char *) &c_byte)[1] = block[0]; ((unsigned char *) &c_byte)[0] = block[1]; } else read_bytes(fd, start, 2, (char *)&c_byte); if(SQUASHFS_CHECK_DATA(sBlk->flags)) offset = 3; if(SQUASHFS_COMPRESSED(c_byte)) { char buffer[SQUASHFS_METADATA_SIZE]; int res; unsigned long bytes = SQUASHFS_METADATA_SIZE; c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte); read_bytes(fd, start + offset, c_byte, buffer); if(!lzma) { if((res = uncompress(block, &bytes, (const unsigned char *) buffer, c_byte)) != Z_OK) { if(res == Z_MEM_ERROR) ERROR("zlib::uncompress failed, not enough memory\n"); else if(res == Z_BUF_ERROR) ERROR("zlib::uncompress failed, not enough room in output buffer\n"); else ERROR("zlib::uncompress failed, unknown error %d\n", res); return 0; } } /* lzma */ else { if((res = LzmaUncompress(block, &bytes, buffer, c_byte)) != SZ_OK) ERROR("LzmaUncompress: error (%d)\n", res); } if(next) *next = start + offset + c_byte; return bytes; } else { c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte); read_bytes(fd, start + offset, c_byte, (char *) block); if(next) *next = start + offset + c_byte; return c_byte; } }
int sqlzma_un(struct sqlzma_un *un, struct sized_buf *src, struct sized_buf *dst) { int err, by_lzma = 0; if (un->un_lzma && is_lzma(*src->buf)) { by_lzma = 1; un->un_cmbuf = src->buf; un->un_cmlen = src->sz; un->un_resbuf = dst->buf; un->un_reslen = dst->sz; /* this library is thread-safe */ err = LzmaUncompress(un); goto out; } err = zlib_inflateReset(&un->un_stream); if (unlikely(err != Z_OK)) goto out; un->un_stream.next_in = src->buf; un->un_stream.avail_in = src->sz; un->un_stream.next_out = dst->buf; un->un_stream.avail_out = dst->sz; err = zlib_inflate(&un->un_stream, Z_FINISH); if (err == Z_STREAM_END) err = 0; out: if (err) { #ifdef __KERNEL__ WARN_ON_ONCE(1); #else char a[64] = "ZLIB "; if (by_lzma) { strcpy(a, "LZMA "); #ifdef _REENTRANT strerror_r(err, a + 5, sizeof(a) - 5); #else strncat(a, strerror(err), sizeof(a) - 5); #endif } else strncat(a, zError(err), sizeof(a) - 5); fprintf(stderr, "%s: %.*s\n", __func__, sizeof(a), a); #endif } return err; }
int DecompressFile(FILE*fpOut,FILE*fpIn) { void*pSrcBuffer; size_t InSize; void*pDestBuffer; size_t OutSize; unsigned char Props[LZMA_PROPS_SIZE]; fread(&OutSize,1,sizeof(OutSize),fpIn);//读取原数据大小 fread(&InSize,1,sizeof(InSize),fpIn);//读取压缩后的数据大小 pDestBuffer=malloc(OutSize);//分配内存 pSrcBuffer=malloc(InSize);//分配内存 if(!pSrcBuffer||!pDestBuffer)//内存不足 { free(pSrcBuffer); free(pDestBuffer); return 2; } fread(Props,1,sizeof(Props),fpIn); fread(pSrcBuffer,1,InSize,fpIn); //MY_STDAPI LzmaUncompress(unsigned char *dest, size_t *destLen, const unsigned char *src, SizeT *srcLen, // const unsigned char *props, size_t propsSize); switch(LzmaUncompress((unsigned char*)pDestBuffer,&OutSize,(unsigned char*)pSrcBuffer,&InSize,Props,sizeof(Props))) { case SZ_OK: fwrite(pDestBuffer,1,OutSize,fpOut); free(pDestBuffer); free(pSrcBuffer); return 0; case SZ_ERROR_DATA: case SZ_ERROR_UNSUPPORTED: case SZ_ERROR_INPUT_EOF: free(pDestBuffer); free(pSrcBuffer); return 1; default: case SZ_ERROR_MEM: free(pDestBuffer); free(pSrcBuffer); return 2; } }
int main(int argc, char** argv) { if(argc < 2) return 1; FILE* fp = fopen(argv[1], "rb"); if(!fp) return 1; ReplayHeader pheader; fseek(fp, 0, SEEK_END); size_t comp_size = ftell(fp) - sizeof(pheader); fseek(fp, 0, SEEK_SET); fread(&pheader, sizeof(pheader), 1, fp); size_t replay_size = pheader.datasize; if(0 == (pheader.flag & REPLAY_COMPRESSED)) { fclose(fp); return 1; } unsigned char* replay_data = (unsigned char*)malloc(0x20000); unsigned char* comp_data = (unsigned char*)malloc(0x2000); fread(comp_data, 0x1000, 1, fp); fclose(fp); if(LzmaUncompress(replay_data, &replay_size, comp_data, &comp_size, pheader.props, 5) != SZ_OK) return 1; fp = fopen(argv[1], "wb"); if(!fp) return 1; pheader.flag &= ~REPLAY_COMPRESSED; fwrite(&pheader,sizeof(pheader),1,fp); fwrite(replay_data,replay_size,1,fp); fclose(fp); free(replay_data); free(comp_data); }
char *LzmaUncompressImp(const char *psrc,int asrcLen,char *pdst,int *pdstLen) { assert(psrc != NULL && asrcLen > 0 && pdstLen != NULL && pdst != NULL); const unsigned char *src = (const unsigned char *)psrc; LzmaDataHead *head = (LzmaDataHead *)src; if(memcmp(head->flags, lzmaFlags, 7) != 0){ return NULL; } size_t srcLen = asrcLen - sizeof(LzmaDataHead); assert(*pdstLen == head->dataLen); size_t dstLen = (size_t)head->dataLen; //max 128M if(dstLen > 1024*1024*128 || dstLen <= 0){ return NULL; } int ret = LzmaUncompress((unsigned char *)pdst, &dstLen, src + sizeof(LzmaDataHead), &srcLen, head->props, LZMA_PROPS_SIZE); if(ret != SZ_OK){ return NULL; } *pdstLen = (int)dstLen; return (char *)pdst; }
int _tmain(int argc, _TCHAR* argv[]) { char* pTest = new char[1001]; char* pTmp = pTest; for (int i =0; i<1; ++i) { strcpy(pTmp, g_TestData); pTmp += sizeof(g_TestData); } char szBuf[3000] = {0}; size_t nDest = 3000; BYTE szProps[5] = {0}; size_t outPropsSize = 5; int nRc = LzmaCompress( (BYTE*)szBuf, &nDest, (BYTE*)pTest, 1, szProps, &outPropsSize, 5, 1<<24, 3,0,2,32,1); char szUnPackDest[3000] = {0}; size_t nUnPackDest = 3000; LzmaUncompress((BYTE*)szUnPackDest, &nUnPackDest, (BYTE*)szBuf, &nDest, szProps, outPropsSize); //CLzmaEncProps props; //LzmaEncProps_Init(&props); //props.level = 5; //props.dictSize = 1; //props.lc = 3; //props.lp = 0; //props.pb = 2; //props.fb = 32; //props.numThreads = 1; //MyLzmaEncode( // (BYTE*)szBuf, &nDest, (BYTE*)g_TestData, sizeof(g_TestData), // &props, &outPropsSize, NULL, 0, NULL, &g_Alloc, NULL); return 0; }
bool gkPak::openPakFile( const TCHAR* pszRelFilename, char** pData, size_t &size ) { // NORMALIZE THE FILENAME gkStdString finalpath(pszRelFilename); gkNormalizePath( finalpath ); // UNICODE SHOULD TRANSLATE #ifdef UNICODE char buffer[MAX_PATH]; WideCharToMultiByte(CP_ACP, 0, finalpath.c_str(), -1, buffer, MAX_PATH, NULL, NULL); uint32 crc32 = gkPak::s_crcGenerator.GetCRC32Lowercase( buffer ); #else uint32 crc32 = gkPak::s_crcGenerator.GetCRC32Lowercase( finalpath.c_str() ); #endif gkPakRecordMap::iterator it = m_pakMap.find( crc32 ); if ( it != m_pakMap.end() ) { // 如果size不为0, 这里就是读文件头 [3/24/2013 Kaiming] bool readHeader = true; if (size == 0) { readHeader = false; } if ( size == 0 || size > it->second.size) { size = it->second.size; } // read the data char* pTmp = new char[size]; ////////////////////////////////////////////////////////////////////////// // 文件操作,加锁 { gkAutoLock<gkCritcalSectionLock> lock(eLGID_global, eLID_file_seek ); // find it fseek(m_handle, m_pakHeader.m_data_offset + it->second.start, SEEK_SET); } size_t BytesRead = fread(pTmp, 1, size, m_handle); //fseek(m_handle, 0, SEEK_SET); ////////////////////////////////////////////////////////////////////////// if (BytesRead != size) { delete [] pTmp; size = 0; } else if (readHeader) { // 读文件头,直接返回了 *pData = pTmp; return true; } else { // 读取到了一个文件的数据,判断是否经过压缩 [3/7/2013 Kaiming] if (it->second.compressHeaderSize != 0) { float decompress_start = gEnv->pTimer->GetAsyncCurTime(); char* pTmpUnCompressed = new char[it->second.compressHeaderSize]; size_t unCompressedSize = it->second.compressHeaderSize - GKPAK_UNCOMPRESS_HEADER_SIZE; size_t realSize = size - LZMA_PROPS_SIZE - GKPAK_UNCOMPRESS_HEADER_SIZE; // 前1KB是不压缩的 // | UNCOMPRESS 1024 | HEADER | COMPRESSED memcpy( pTmpUnCompressed, pTmp, GKPAK_UNCOMPRESS_HEADER_SIZE); //ELzmaStatus status; //SRes res = LzmaDecode((unsigned char*)pTmpUnCompressed, &unCompressedSize, (unsigned char*)(pTmp + LZMA_PROPS_SIZE), &realSize, (unsigned char*)pTmp, LZMA_PROPS_SIZE, LZMA_FINISH_END, &status, &g_Alloc); SRes res = LzmaUncompress( (unsigned char*)pTmpUnCompressed + GKPAK_UNCOMPRESS_HEADER_SIZE, &unCompressedSize, (unsigned char*)(pTmp + LZMA_PROPS_SIZE + GKPAK_UNCOMPRESS_HEADER_SIZE), &realSize, (unsigned char*)pTmp + GKPAK_UNCOMPRESS_HEADER_SIZE, LZMA_PROPS_SIZE ); if (res == SZ_OK && (unCompressedSize + GKPAK_UNCOMPRESS_HEADER_SIZE) == it->second.compressHeaderSize) { *pData = pTmpUnCompressed; size = unCompressedSize + GKPAK_UNCOMPRESS_HEADER_SIZE; delete[] pTmp; } else { *pData = pTmp; delete[] pTmpUnCompressed; } decompress_start = gEnv->pTimer->GetAsyncCurTime() - decompress_start; #ifdef OS_WIN32 uint32 threadid = ::GetCurrentThreadId(); if ( threadid == gEnv->pSystemInfo->mainThreadId) { gkLogMessage( _T("thread[main] lzma-dec [%s] using %.2fms"), finalpath.c_str(), decompress_start * 1000); } else { gkLogMessage( _T("thread[%d] lzma-dec [%s] using %.2fms"), threadid, finalpath.c_str(), decompress_start * 1000); } #endif } else { *pData = pTmp; } return true; } } else { return false; } return false; }
void PsUpdateDownloader::unpackUpdate() { QByteArray packed; if (!outputFile.open(QIODevice::ReadOnly)) { LOG(("Update Error: cant read updates file!")); return fatalFail(); } #ifdef Q_OS_WIN // use Lzma SDK for win const int32 hSigLen = 128, hShaLen = 20, hPropsLen = LZMA_PROPS_SIZE, hOriginalSizeLen = sizeof(int32), hSize = hSigLen + hShaLen + hPropsLen + hOriginalSizeLen; // header #else const int32 hSigLen = 128, hShaLen = 20, hPropsLen = 0, hOriginalSizeLen = sizeof(int32), hSize = hSigLen + hShaLen + hOriginalSizeLen; // header #endif QByteArray compressed = outputFile.readAll(); int32 compressedLen = compressed.size() - hSize; if (compressedLen <= 0) { LOG(("Update Error: bad compressed size: %1").arg(compressed.size())); return fatalFail(); } outputFile.close(); QString tempDirPath = cWorkingDir() + qsl("tupdates/temp"), readyDirPath = cWorkingDir() + qsl("tupdates/ready"); deleteDir(tempDirPath); deleteDir(readyDirPath); QDir tempDir(tempDirPath), readyDir(readyDirPath); if (tempDir.exists() || readyDir.exists()) { LOG(("Update Error: cant clear tupdates/temp or tupdates/ready dir!")); return fatalFail(); } uchar sha1Buffer[20]; bool goodSha1 = !memcmp(compressed.constData() + hSigLen, hashSha1(compressed.constData() + hSigLen + hShaLen, compressedLen + hPropsLen + hOriginalSizeLen, sha1Buffer), hShaLen); if (!goodSha1) { LOG(("Update Error: bad SHA1 hash of update file!")); return fatalFail(); } RSA *pbKey = PEM_read_bio_RSAPublicKey(BIO_new_mem_buf(const_cast<char*>(UpdatesPublicKey), -1), 0, 0, 0); if (!pbKey) { LOG(("Update Error: cant read public rsa key!")); return fatalFail(); } if (RSA_verify(NID_sha1, (const uchar*)(compressed.constData() + hSigLen), hShaLen, (const uchar*)(compressed.constData()), hSigLen, pbKey) != 1) { // verify signature RSA_free(pbKey); LOG(("Update Error: bad RSA signature of update file!")); return fatalFail(); } RSA_free(pbKey); QByteArray uncompressed; int32 uncompressedLen; memcpy(&uncompressedLen, compressed.constData() + hSigLen + hShaLen + hPropsLen, hOriginalSizeLen); uncompressed.resize(uncompressedLen); size_t resultLen = uncompressed.size(); #ifdef Q_OS_WIN // use Lzma SDK for win SizeT srcLen = compressedLen; int uncompressRes = LzmaUncompress((uchar*)uncompressed.data(), &resultLen, (const uchar*)(compressed.constData() + hSize), &srcLen, (const uchar*)(compressed.constData() + hSigLen + hShaLen), LZMA_PROPS_SIZE); if (uncompressRes != SZ_OK) { LOG(("Update Error: could not uncompress lzma, code: %1").arg(uncompressRes)); return fatalFail(); } #else lzma_stream stream = LZMA_STREAM_INIT; lzma_ret ret = lzma_stream_decoder(&stream, UINT64_MAX, LZMA_CONCATENATED); if (ret != LZMA_OK) { const char *msg; switch (ret) { case LZMA_MEM_ERROR: msg = "Memory allocation failed"; break; case LZMA_OPTIONS_ERROR: msg = "Specified preset is not supported"; break; case LZMA_UNSUPPORTED_CHECK: msg = "Specified integrity check is not supported"; break; default: msg = "Unknown error, possibly a bug"; break; } LOG(("Error initializing the decoder: %1 (error code %2)").arg(msg).arg(ret)); return fatalFail(); } stream.avail_in = compressedLen; stream.next_in = (uint8_t*)(compressed.constData() + hSize); stream.avail_out = resultLen; stream.next_out = (uint8_t*)uncompressed.data(); lzma_ret res = lzma_code(&stream, LZMA_FINISH); if (stream.avail_in) { LOG(("Error in decompression, %1 bytes left in _in of %2 whole.").arg(stream.avail_in).arg(compressedLen)); return fatalFail(); } else if (stream.avail_out) { LOG(("Error in decompression, %1 bytes free left in _out of %2 whole.").arg(stream.avail_out).arg(resultLen)); return fatalFail(); } lzma_end(&stream); if (res != LZMA_OK && res != LZMA_STREAM_END) { const char *msg; switch (res) { case LZMA_MEM_ERROR: msg = "Memory allocation failed"; break; case LZMA_FORMAT_ERROR: msg = "The input data is not in the .xz format"; break; case LZMA_OPTIONS_ERROR: msg = "Unsupported compression options"; break; case LZMA_DATA_ERROR: msg = "Compressed file is corrupt"; break; case LZMA_BUF_ERROR: msg = "Compressed data is truncated or otherwise corrupt"; break; default: msg = "Unknown error, possibly a bug"; break; } LOG(("Error in decompression: %1 (error code %2)").arg(msg).arg(res)); return fatalFail(); } #endif tempDir.mkdir(tempDir.absolutePath()); quint32 version; { QBuffer buffer(&uncompressed); buffer.open(QIODevice::ReadOnly); QDataStream stream(&buffer); stream.setVersion(QDataStream::Qt_5_1); stream >> version; if (stream.status() != QDataStream::Ok) { LOG(("Update Error: cant read version from downloaded stream, status: %1").arg(stream.status())); return fatalFail(); } if (version <= AppVersion) { LOG(("Update Error: downloaded version %1 is not greater, than mine %2").arg(version).arg(AppVersion)); return fatalFail(); } quint32 filesCount; stream >> filesCount; if (stream.status() != QDataStream::Ok) { LOG(("Update Error: cant read files count from downloaded stream, status: %1").arg(stream.status())); return fatalFail(); } if (!filesCount) { LOG(("Update Error: update is empty!")); return fatalFail(); } for (uint32 i = 0; i < filesCount; ++i) { QString relativeName; quint32 fileSize; QByteArray fileInnerData; bool executable = false; stream >> relativeName >> fileSize >> fileInnerData; #if defined Q_OS_MAC || defined Q_OS_LINUX stream >> executable; #endif if (stream.status() != QDataStream::Ok) { LOG(("Update Error: cant read file from downloaded stream, status: %1").arg(stream.status())); return fatalFail(); } if (fileSize != quint32(fileInnerData.size())) { LOG(("Update Error: bad file size %1 not matching data size %2").arg(fileSize).arg(fileInnerData.size())); return fatalFail(); } QFile f(tempDirPath + '/' + relativeName); if (!QDir().mkpath(QFileInfo(f).absolutePath())) { LOG(("Update Error: cant mkpath for file '%1'").arg(tempDirPath + '/' + relativeName)); return fatalFail(); } if (!f.open(QIODevice::WriteOnly)) { LOG(("Update Error: cant open file '%1' for writing").arg(tempDirPath + '/' + relativeName)); return fatalFail(); } if (f.write(fileInnerData) != fileSize) { f.close(); LOG(("Update Error: cant write file '%1'").arg(tempDirPath + '/' + relativeName)); return fatalFail(); } f.close(); if (executable) { QFileDevice::Permissions p = f.permissions(); p |= QFileDevice::ExeOwner | QFileDevice::ExeUser | QFileDevice::ExeGroup | QFileDevice::ExeOther; f.setPermissions(p); } } // create tdata/version file tempDir.mkdir(QDir(tempDirPath + qsl("/tdata")).absolutePath()); std::wstring versionString = ((version % 1000) ? QString("%1.%2.%3").arg(int(version / 1000000)).arg(int((version % 1000000) / 1000)).arg(int(version % 1000)) : QString("%1.%2").arg(int(version / 1000000)).arg(int((version % 1000000) / 1000))).toStdWString(); VerInt versionNum = VerInt(version), versionLen = VerInt(versionString.size() * sizeof(VerChar)); VerChar versionStr[32]; memcpy(versionStr, versionString.c_str(), versionLen); QFile fVersion(tempDirPath + qsl("/tdata/version")); if (!fVersion.open(QIODevice::WriteOnly)) { LOG(("Update Error: cant write version file '%1'").arg(tempDirPath + qsl("/version"))); return fatalFail(); } fVersion.write((const char*)&versionNum, sizeof(VerInt)); fVersion.write((const char*)&versionLen, sizeof(VerInt)); fVersion.write((const char*)&versionStr[0], versionLen); fVersion.close(); } if (!tempDir.rename(tempDir.absolutePath(), readyDir.absolutePath())) { LOG(("Update Error: cant rename temp dir '%1' to ready dir '%2'").arg(tempDir.absolutePath()).arg(readyDir.absolutePath())); return fatalFail(); } deleteDir(tempDirPath); outputFile.remove(); emit App::app()->updateReady(); }
int main(int argc, char *argv[]) { QString workDir; #ifdef Q_OS_MAC if (QDir(QString()).absolutePath() == "/") { QString first = argc ? QString::fromLocal8Bit(argv[0]) : QString(); if (!first.isEmpty()) { QFileInfo info(first); if (info.exists()) { QDir result(info.absolutePath() + "/../../.."); workDir = result.absolutePath() + '/'; } } } #endif QString remove; int version = 0; QFileInfoList files; for (int i = 0; i < argc; ++i) { if (string("-path") == argv[i] && i + 1 < argc) { QString path = workDir + QString(argv[i + 1]); QFileInfo info(path); files.push_back(info); if (remove.isEmpty()) remove = info.canonicalPath() + "/"; } else if (string("-version") == argv[i] && i + 1 < argc) { version = QString(argv[i + 1]).toInt(); } else if (string("-dev") == argv[i]) { DevChannel = true; } else if (string("-beta") == argv[i] && i + 1 < argc) { BetaVersion = QString(argv[i + 1]).toULongLong(); if (BetaVersion > version * 1000ULL && BetaVersion < (version + 1) * 1000ULL) { DevChannel = false; BetaSignature = countBetaVersionSignature(BetaVersion); if (BetaSignature.isEmpty()) { return -1; } } else { cout << "Bad -beta param value passed, should be for the same version: " << version << ", beta: " << BetaVersion << "\n"; return -1; } } } if (files.isEmpty() || remove.isEmpty() || version <= 1016 || version > 999999999) { #ifdef Q_OS_WIN cout << "Usage: Packer.exe -path {file} -version {version} OR Packer.exe -path {dir} -version {version}\n"; #elif defined Q_OS_MAC cout << "Usage: Packer.app -path {file} -version {version} OR Packer.app -path {dir} -version {version}\n"; #else cout << "Usage: Packer -path {file} -version {version} OR Packer -path {dir} -version {version}\n"; #endif return -1; } bool hasDirs = true; while (hasDirs) { hasDirs = false; for (QFileInfoList::iterator i = files.begin(); i != files.end(); ++i) { QFileInfo info(*i); QString fullPath = info.canonicalFilePath(); if (info.isDir()) { hasDirs = true; files.erase(i); QDir d = QDir(info.absoluteFilePath()); QString fullDir = d.canonicalPath(); QStringList entries = d.entryList(QDir::Files | QDir::Dirs | QDir::NoSymLinks | QDir::NoDotAndDotDot); files.append(d.entryInfoList(QDir::Files | QDir::Dirs | QDir::NoSymLinks | QDir::NoDotAndDotDot)); break; } else if (!info.isReadable()) { cout << "Can't read: " << info.absoluteFilePath().toUtf8().constData() << "\n"; return -1; } else if (info.isHidden()) { hasDirs = true; files.erase(i); break; } } } for (QFileInfoList::iterator i = files.begin(); i != files.end(); ++i) { QFileInfo info(*i); if (!info.canonicalFilePath().startsWith(remove)) { cout << "Can't find '" << remove.toUtf8().constData() << "' in file '" << info.canonicalFilePath().toUtf8().constData() << "' :(\n"; return -1; } } QByteArray result; { QBuffer buffer(&result); buffer.open(QIODevice::WriteOnly); QDataStream stream(&buffer); stream.setVersion(QDataStream::Qt_5_1); if (BetaVersion) { stream << quint32(0x7FFFFFFF); stream << quint64(BetaVersion); } else { stream << quint32(version); } stream << quint32(files.size()); cout << "Found " << files.size() << " file" << (files.size() == 1 ? "" : "s") << "..\n"; for (QFileInfoList::iterator i = files.begin(); i != files.end(); ++i) { QFileInfo info(*i); QString fullName = info.canonicalFilePath(); QString name = fullName.mid(remove.length()); cout << name.toUtf8().constData() << " (" << info.size() << ")\n"; QFile f(fullName); if (!f.open(QIODevice::ReadOnly)) { cout << "Can't open '" << fullName.toUtf8().constData() << "' for read..\n"; return -1; } QByteArray inner = f.readAll(); stream << name << quint32(inner.size()) << inner; #if defined Q_OS_MAC || defined Q_OS_LINUX stream << (QFileInfo(fullName).isExecutable() ? true : false); #endif } if (stream.status() != QDataStream::Ok) { cout << "Stream status is bad: " << stream.status() << "\n"; return -1; } } int32 resultSize = result.size(); cout << "Compression start, size: " << resultSize << "\n"; QByteArray compressed, resultCheck; #ifdef Q_OS_WIN // use Lzma SDK for win const int32 hSigLen = 128, hShaLen = 20, hPropsLen = LZMA_PROPS_SIZE, hOriginalSizeLen = sizeof(int32), hSize = hSigLen + hShaLen + hPropsLen + hOriginalSizeLen; // header compressed.resize(hSize + resultSize + 1024 * 1024); // rsa signature + sha1 + lzma props + max compressed size size_t compressedLen = compressed.size() - hSize; size_t outPropsSize = LZMA_PROPS_SIZE; uchar *_dest = (uchar*)(compressed.data() + hSize); size_t *_destLen = &compressedLen; const uchar *_src = (const uchar*)(result.constData()); size_t _srcLen = result.size(); uchar *_outProps = (uchar*)(compressed.data() + hSigLen + hShaLen); int res = LzmaCompress(_dest, _destLen, _src, _srcLen, _outProps, &outPropsSize, 9, 64 * 1024 * 1024, 4, 0, 2, 273, 2); if (res != SZ_OK) { cout << "Error in compression: " << res << "\n"; return -1; } compressed.resize(int(hSize + compressedLen)); memcpy(compressed.data() + hSigLen + hShaLen + hPropsLen, &resultSize, hOriginalSizeLen); cout << "Compressed to size: " << compressedLen << "\n"; cout << "Checking uncompressed..\n"; int32 resultCheckLen; memcpy(&resultCheckLen, compressed.constData() + hSigLen + hShaLen + hPropsLen, hOriginalSizeLen); if (resultCheckLen <= 0 || resultCheckLen > 1024 * 1024 * 1024) { cout << "Bad result len: " << resultCheckLen << "\n"; return -1; } resultCheck.resize(resultCheckLen); size_t resultLen = resultCheck.size(); SizeT srcLen = compressedLen; int uncompressRes = LzmaUncompress((uchar*)resultCheck.data(), &resultLen, (const uchar*)(compressed.constData() + hSize), &srcLen, (const uchar*)(compressed.constData() + hSigLen + hShaLen), LZMA_PROPS_SIZE); if (uncompressRes != SZ_OK) { cout << "Uncompress failed: " << uncompressRes << "\n"; return -1; } if (resultLen != size_t(result.size())) { cout << "Uncompress bad size: " << resultLen << ", was: " << result.size() << "\n"; return -1; } #else // use liblzma for others const int32 hSigLen = 128, hShaLen = 20, hPropsLen = 0, hOriginalSizeLen = sizeof(int32), hSize = hSigLen + hShaLen + hOriginalSizeLen; // header compressed.resize(hSize + resultSize + 1024 * 1024); // rsa signature + sha1 + lzma props + max compressed size size_t compressedLen = compressed.size() - hSize; lzma_stream stream = LZMA_STREAM_INIT; int preset = 9 | LZMA_PRESET_EXTREME; lzma_ret ret = lzma_easy_encoder(&stream, preset, LZMA_CHECK_CRC64); if (ret != LZMA_OK) { const char *msg; switch (ret) { case LZMA_MEM_ERROR: msg = "Memory allocation failed"; break; case LZMA_OPTIONS_ERROR: msg = "Specified preset is not supported"; break; case LZMA_UNSUPPORTED_CHECK: msg = "Specified integrity check is not supported"; break; default: msg = "Unknown error, possibly a bug"; break; } cout << "Error initializing the encoder: " << msg << " (error code " << ret << ")\n"; return -1; } stream.avail_in = resultSize; stream.next_in = (uint8_t*)result.constData(); stream.avail_out = compressedLen; stream.next_out = (uint8_t*)(compressed.data() + hSize); lzma_ret res = lzma_code(&stream, LZMA_FINISH); compressedLen -= stream.avail_out; lzma_end(&stream); if (res != LZMA_OK && res != LZMA_STREAM_END) { const char *msg; switch (res) { case LZMA_MEM_ERROR: msg = "Memory allocation failed"; break; case LZMA_DATA_ERROR: msg = "File size limits exceeded"; break; default: msg = "Unknown error, possibly a bug"; break; } cout << "Error in compression: " << msg << " (error code " << res << ")\n"; return -1; } compressed.resize(int(hSize + compressedLen)); memcpy(compressed.data() + hSigLen + hShaLen, &resultSize, hOriginalSizeLen); cout << "Compressed to size: " << compressedLen << "\n"; cout << "Checking uncompressed..\n"; int32 resultCheckLen; memcpy(&resultCheckLen, compressed.constData() + hSigLen + hShaLen, hOriginalSizeLen); if (resultCheckLen <= 0 || resultCheckLen > 1024 * 1024 * 1024) { cout << "Bad result len: " << resultCheckLen << "\n"; return -1; } resultCheck.resize(resultCheckLen); size_t resultLen = resultCheck.size(); stream = LZMA_STREAM_INIT; ret = lzma_stream_decoder(&stream, UINT64_MAX, LZMA_CONCATENATED); if (ret != LZMA_OK) { const char *msg; switch (ret) { case LZMA_MEM_ERROR: msg = "Memory allocation failed"; break; case LZMA_OPTIONS_ERROR: msg = "Specified preset is not supported"; break; case LZMA_UNSUPPORTED_CHECK: msg = "Specified integrity check is not supported"; break; default: msg = "Unknown error, possibly a bug"; break; } cout << "Error initializing the decoder: " << msg << " (error code " << ret << ")\n"; return -1; } stream.avail_in = compressedLen; stream.next_in = (uint8_t*)(compressed.constData() + hSize); stream.avail_out = resultLen; stream.next_out = (uint8_t*)resultCheck.data(); res = lzma_code(&stream, LZMA_FINISH); if (stream.avail_in) { cout << "Error in decompression, " << stream.avail_in << " bytes left in _in of " << compressedLen << " whole.\n"; return -1; } else if (stream.avail_out) { cout << "Error in decompression, " << stream.avail_out << " bytes free left in _out of " << resultLen << " whole.\n"; return -1; } lzma_end(&stream); if (res != LZMA_OK && res != LZMA_STREAM_END) { const char *msg; switch (res) { case LZMA_MEM_ERROR: msg = "Memory allocation failed"; break; case LZMA_FORMAT_ERROR: msg = "The input data is not in the .xz format"; break; case LZMA_OPTIONS_ERROR: msg = "Unsupported compression options"; break; case LZMA_DATA_ERROR: msg = "Compressed file is corrupt"; break; case LZMA_BUF_ERROR: msg = "Compressed data is truncated or otherwise corrupt"; break; default: msg = "Unknown error, possibly a bug"; break; } cout << "Error in decompression: " << msg << " (error code " << res << ")\n"; return -1; } #endif if (memcmp(result.constData(), resultCheck.constData(), resultLen)) { cout << "Data differ :(\n"; return -1; } /**/ result = resultCheck = QByteArray(); cout << "Counting SHA1 hash..\n"; uchar sha1Buffer[20]; memcpy(compressed.data() + hSigLen, hashSha1(compressed.constData() + hSigLen + hShaLen, uint32(compressedLen + hPropsLen + hOriginalSizeLen), sha1Buffer), hShaLen); // count sha1 uint32 siglen = 0; cout << "Signing..\n"; RSA *prKey = PEM_read_bio_RSAPrivateKey(BIO_new_mem_buf(const_cast<char*>((DevChannel || BetaVersion) ? PrivateDevKey : PrivateKey), -1), 0, 0, 0); if (!prKey) { cout << "Could not read RSA private key!\n"; return -1; } if (RSA_size(prKey) != hSigLen) { cout << "Bad private key, size: " << RSA_size(prKey) << "\n"; RSA_free(prKey); return -1; } if (RSA_sign(NID_sha1, (const uchar*)(compressed.constData() + hSigLen), hShaLen, (uchar*)(compressed.data()), &siglen, prKey) != 1) { // count signature cout << "Signing failed!\n"; RSA_free(prKey); return -1; } RSA_free(prKey); if (siglen != hSigLen) { cout << "Bad signature length: " << siglen << "\n"; return -1; } cout << "Checking signature..\n"; RSA *pbKey = PEM_read_bio_RSAPublicKey(BIO_new_mem_buf(const_cast<char*>((DevChannel || BetaVersion) ? PublicDevKey : PublicKey), -1), 0, 0, 0); if (!pbKey) { cout << "Could not read RSA public key!\n"; return -1; } if (RSA_verify(NID_sha1, (const uchar*)(compressed.constData() + hSigLen), hShaLen, (const uchar*)(compressed.constData()), siglen, pbKey) != 1) { // verify signature RSA_free(pbKey); cout << "Signature verification failed!\n"; return -1; } cout << "Signature verified!\n"; RSA_free(pbKey); #ifdef Q_OS_WIN QString outName(QString("tupdate%1").arg(BetaVersion ? BetaVersion : version)); #elif defined Q_OS_MAC QString outName(QString("tmacupd%1").arg(BetaVersion ? BetaVersion : version)); #elif defined Q_OS_LINUX32 QString outName(QString("tlinux32upd%1").arg(BetaVersion ? BetaVersion : version)); #elif defined Q_OS_LINUX64 QString outName(QString("tlinuxupd%1").arg(BetaVersion ? BetaVersion : version)); #else #error Unknown platform! #endif if (BetaVersion) { outName += "_" + BetaSignature; } QFile out(outName); if (!out.open(QIODevice::WriteOnly)) { cout << "Can't open '" << outName.toUtf8().constData() << "' for write..\n"; return -1; } out.write(compressed); out.close(); if (BetaVersion) { QString keyName(QString("tbeta_%1_key").arg(BetaVersion)); QFile key(keyName); if (!key.open(QIODevice::WriteOnly)) { cout << "Can't open '" << keyName.toUtf8().constData() << "' for write..\n"; return -1; } key.write(BetaSignature.toUtf8()); key.close(); } cout << "Update file '" << outName.toUtf8().constData() << "' written successfully!\n"; return 0; }
void UpdateChecker::unpackUpdate() { QByteArray packed; if (!outputFile.open(QIODevice::ReadOnly)) { LOG(("Update Error: cant read updates file!")); return fatalFail(); } #ifdef Q_OS_WIN // use Lzma SDK for win const int32 hSigLen = 128, hShaLen = 20, hPropsLen = LZMA_PROPS_SIZE, hOriginalSizeLen = sizeof(int32), hSize = hSigLen + hShaLen + hPropsLen + hOriginalSizeLen; // header #else // Q_OS_WIN const int32 hSigLen = 128, hShaLen = 20, hPropsLen = 0, hOriginalSizeLen = sizeof(int32), hSize = hSigLen + hShaLen + hOriginalSizeLen; // header #endif // Q_OS_WIN QByteArray compressed = outputFile.readAll(); int32 compressedLen = compressed.size() - hSize; if (compressedLen <= 0) { LOG(("Update Error: bad compressed size: %1").arg(compressed.size())); return fatalFail(); } outputFile.close(); QString tempDirPath = cWorkingDir() + qsl("tupdates/temp"), readyFilePath = cWorkingDir() + qsl("tupdates/temp/ready"); psDeleteDir(tempDirPath); QDir tempDir(tempDirPath); if (tempDir.exists() || QFile(readyFilePath).exists()) { LOG(("Update Error: cant clear tupdates/temp dir!")); return fatalFail(); } uchar sha1Buffer[20]; bool goodSha1 = !memcmp(compressed.constData() + hSigLen, hashSha1(compressed.constData() + hSigLen + hShaLen, compressedLen + hPropsLen + hOriginalSizeLen, sha1Buffer), hShaLen); if (!goodSha1) { LOG(("Update Error: bad SHA1 hash of update file!")); return fatalFail(); } RSA *pbKey = PEM_read_bio_RSAPublicKey(BIO_new_mem_buf(const_cast<char*>(AppAlphaVersion ? UpdatesPublicAlphaKey : UpdatesPublicKey), -1), 0, 0, 0); if (!pbKey) { LOG(("Update Error: cant read public rsa key!")); return fatalFail(); } if (RSA_verify(NID_sha1, (const uchar*)(compressed.constData() + hSigLen), hShaLen, (const uchar*)(compressed.constData()), hSigLen, pbKey) != 1) { // verify signature RSA_free(pbKey); if (cAlphaVersion() || cBetaVersion()) { // try other public key, if we are in alpha or beta version pbKey = PEM_read_bio_RSAPublicKey(BIO_new_mem_buf(const_cast<char*>(AppAlphaVersion ? UpdatesPublicKey : UpdatesPublicAlphaKey), -1), 0, 0, 0); if (!pbKey) { LOG(("Update Error: cant read public rsa key!")); return fatalFail(); } if (RSA_verify(NID_sha1, (const uchar*)(compressed.constData() + hSigLen), hShaLen, (const uchar*)(compressed.constData()), hSigLen, pbKey) != 1) { // verify signature RSA_free(pbKey); LOG(("Update Error: bad RSA signature of update file!")); return fatalFail(); } } else { LOG(("Update Error: bad RSA signature of update file!")); return fatalFail(); } } RSA_free(pbKey); QByteArray uncompressed; int32 uncompressedLen; memcpy(&uncompressedLen, compressed.constData() + hSigLen + hShaLen + hPropsLen, hOriginalSizeLen); uncompressed.resize(uncompressedLen); size_t resultLen = uncompressed.size(); #ifdef Q_OS_WIN // use Lzma SDK for win SizeT srcLen = compressedLen; int uncompressRes = LzmaUncompress((uchar*)uncompressed.data(), &resultLen, (const uchar*)(compressed.constData() + hSize), &srcLen, (const uchar*)(compressed.constData() + hSigLen + hShaLen), LZMA_PROPS_SIZE); if (uncompressRes != SZ_OK) { LOG(("Update Error: could not uncompress lzma, code: %1").arg(uncompressRes)); return fatalFail(); } #else // Q_OS_WIN lzma_stream stream = LZMA_STREAM_INIT; lzma_ret ret = lzma_stream_decoder(&stream, UINT64_MAX, LZMA_CONCATENATED); if (ret != LZMA_OK) { const char *msg; switch (ret) { case LZMA_MEM_ERROR: msg = "Memory allocation failed"; break; case LZMA_OPTIONS_ERROR: msg = "Specified preset is not supported"; break; case LZMA_UNSUPPORTED_CHECK: msg = "Specified integrity check is not supported"; break; default: msg = "Unknown error, possibly a bug"; break; } LOG(("Error initializing the decoder: %1 (error code %2)").arg(msg).arg(ret)); return fatalFail(); } stream.avail_in = compressedLen; stream.next_in = (uint8_t*)(compressed.constData() + hSize); stream.avail_out = resultLen; stream.next_out = (uint8_t*)uncompressed.data(); lzma_ret res = lzma_code(&stream, LZMA_FINISH); if (stream.avail_in) { LOG(("Error in decompression, %1 bytes left in _in of %2 whole.").arg(stream.avail_in).arg(compressedLen)); return fatalFail(); } else if (stream.avail_out) { LOG(("Error in decompression, %1 bytes free left in _out of %2 whole.").arg(stream.avail_out).arg(resultLen)); return fatalFail(); } lzma_end(&stream); if (res != LZMA_OK && res != LZMA_STREAM_END) { const char *msg; switch (res) { case LZMA_MEM_ERROR: msg = "Memory allocation failed"; break; case LZMA_FORMAT_ERROR: msg = "The input data is not in the .xz format"; break; case LZMA_OPTIONS_ERROR: msg = "Unsupported compression options"; break; case LZMA_DATA_ERROR: msg = "Compressed file is corrupt"; break; case LZMA_BUF_ERROR: msg = "Compressed data is truncated or otherwise corrupt"; break; default: msg = "Unknown error, possibly a bug"; break; } LOG(("Error in decompression: %1 (error code %2)").arg(msg).arg(res)); return fatalFail(); } #endif // Q_OS_WIN tempDir.mkdir(tempDir.absolutePath()); quint32 version; { QBuffer buffer(&uncompressed); buffer.open(QIODevice::ReadOnly); QDataStream stream(&buffer); stream.setVersion(QDataStream::Qt_5_1); stream >> version; if (stream.status() != QDataStream::Ok) { LOG(("Update Error: cant read version from downloaded stream, status: %1").arg(stream.status())); return fatalFail(); } quint64 betaVersion = 0; if (version == 0x7FFFFFFF) { // beta version stream >> betaVersion; if (stream.status() != QDataStream::Ok) { LOG(("Update Error: cant read beta version from downloaded stream, status: %1").arg(stream.status())); return fatalFail(); } if (!cBetaVersion() || betaVersion <= cBetaVersion()) { LOG(("Update Error: downloaded beta version %1 is not greater, than mine %2").arg(betaVersion).arg(cBetaVersion())); return fatalFail(); } } else if (int32(version) <= AppVersion) {
bool LocateConverter::LocateUpdate(const wchar_t *locate, const wchar_t *patch, const wchar_t *path, bool compress/* = false */, OnProgress progress/* = NULL */) { LocateReader loc(locate); if ( !loc.IsAvailable() ) return false; const uint8_t *diff_buffer = 0; PDIFFHEADER diff_header = 0; HANDLE hfile = CreateFileW(patch, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(hfile!=INVALID_HANDLE_VALUE) { uint32_t file_length = GetFileSize(hfile, NULL); HANDLE hfilemap = CreateFileMapping(hfile, NULL, PAGE_READONLY, 0, 0, NULL); CloseHandle(hfile); diff_buffer = (const uint8_t*) MapViewOfFile(hfilemap, FILE_MAP_READ, 0, 0, 0); CloseHandle(hfilemap); diff_header = (PDIFFHEADER)diff_buffer; int data_size = file_length - sizeof(DIFFHEADER) - LZMA_PROPS_SIZE; if( data_size<0 || diff_header->magic != DIFF_MAGIC || CRC32_MEM(diff_buffer, sizeof(DIFFHEADER) - 4)!=diff_header->crc32 ) { UnmapViewOfFile((void*)diff_buffer); return false; } else { uint32_t lzma_buffer_len = diff_header->size; uint8_t *lzma_buffer = (uint8_t *)malloc(sizeof(DIFFHEADER) + lzma_buffer_len); if( LzmaUncompress(lzma_buffer + sizeof(DIFFHEADER), &lzma_buffer_len, (unsigned char*)diff_header->data + LZMA_PROPS_SIZE, (uint32_t*)&data_size, (unsigned char*)diff_header->data, LZMA_PROPS_SIZE)==SZ_OK ) { memcpy(lzma_buffer, diff_buffer, sizeof(DIFFHEADER)); UnmapViewOfFile((void*)diff_buffer); diff_buffer = lzma_buffer; diff_header = (PDIFFHEADER)diff_buffer; diff_header->table1 += (uint32_t)diff_buffer; diff_header->table2 += (uint32_t)diff_buffer; } else { free(lzma_buffer); UnmapViewOfFile((void*)diff_buffer); return false; } } } else { return false; } if ( loc.GetInfo()->count!=diff_header->total1 || loc.GetInfo()->time!=diff_header->time1 ) return false; PDIFFITEM diffitem = diff_header->data; LocateItem *Locate = (LocateItem *)malloc( diff_header->total2 * sizeof(LocateItem) ); uint32_t last_diff = ( diff_header->table1 - sizeof(DIFFHEADER) - (uint32_t)diff_buffer ) / sizeof(DIFFITEM) - 1; uint32_t last_line = diff_header->total2 - 1; uint32_t i = loc.GetInfo()->count; for(; i>0; i--) { LocateItem *item = loc.GetItem(i); if(i!=diffitem[last_diff].line) { Locate[last_line].begin_ip = item->begin_ip; Locate[last_line].region = item->region; Locate[last_line].address = item->address; last_line--; } else { switch(diffitem[last_diff].method) { case INSERT: //printf("INSERT %d %d\n", i, diffitem[last_diff-1].line); Locate[last_line].begin_ip = diffitem[last_diff].begin_ip; Locate[last_line].region = (const char*)( diffitem[last_diff].table1 + diff_header->table1 ); Locate[last_line].address = (const char*)( diffitem[last_diff].table2 + diff_header->table2 ); last_line--; i++; break; case REMOVE: //printf("REMOVE %d %d %d\n", i, diffitem[last_diff-1].line, diffitem[last_diff-2].line); break; case MODIFY: Locate[last_line].begin_ip = item->begin_ip; Locate[last_line].region = (const char*)( diffitem[last_diff].table1 + diff_header->table1 ); Locate[last_line].address = (const char*)( diffitem[last_diff].table2 + diff_header->table2 ); //printf("MODIFY %d %s %s\n", last_line+1, Locate[last_line].region, Locate[last_line].address); //getchar(); last_line--; break; } last_diff--; } } //printf("%d %d\n",last_diff,last_line); if ( last_diff!=-1 || last_line!=-1 ) return false; StringTable string_table1; StringTable string_table2; RecordTable record_table; Buffer buffer; uint32_t last_begin_ip = 0; for(i=last_line+1; i<diff_header->total2; i++) { LocateItem *item = &Locate[i]; LOCATE record; record.begin_ip = item->begin_ip; record.table1 = string_table1.Append(item->region); record.table2 = string_table2.Append(item->address); if ( i > 0 ) { uint32_t diff = record.begin_ip - last_begin_ip; if ( compress && isPowerOf2(diff) ) { record.begin_ip = LogBase2(diff); } } record_table.Append(&record); last_begin_ip = item->begin_ip; } free(Locate); //合并数据区 Buffer *record_table_buffer = record_table; Buffer *string_table1_buffer = string_table1; Buffer *string_table2_buffer = string_table2; std::copy(record_table_buffer->begin(), record_table_buffer->end(), std::back_inserter(buffer)); std::copy(string_table1_buffer->begin(), string_table1_buffer->end(), std::back_inserter(buffer)); std::copy(string_table2_buffer->begin(), string_table2_buffer->end(), std::back_inserter(buffer)); //生成文件头 HEADER header; header.magic = LOCATE_MAGIC; header.version = LOCATE_VERISON; header.compress = compress?1:0; header.total = diff_header->total2; header.time = diff_header->time2; header.table1 = sizeof(header) + record_table_buffer->size(); // 这里不加LZMA_PROPS_SIZE的原因是解压后,抛弃props信息 header.table2 = header.table1 + string_table1_buffer->size(); header.size = buffer.size(); header.crc32 = CRC32_MEM((uint8_t*)&header, sizeof(header) - 4); uint32_t lzma_buffer_len = buffer.size(); uint8_t *lzma_buffer = 0; size_t prop_size = LZMA_PROPS_SIZE; BYTE outProps[LZMA_PROPS_SIZE]; //准备压缩 if(compress) { lzma_buffer = (uint8_t *)malloc(lzma_buffer_len); ProgressCallback LzmaCompressProgress; LzmaCompressProgress.Progress = LzmaOnProgress; LzmaCompressProgress.totalInSize = buffer.size(); LzmaCompressProgress.progress = progress; LzmaCompress(lzma_buffer, &lzma_buffer_len, &buffer[0], buffer.size(), (ICompressProgress*)&LzmaCompressProgress, outProps, &prop_size, 5, 1<<27, 8, 0, 2, 64, 4); } //保存文件 FILE * out = _wfopen(path, L"wb"); fwrite(&header, 1, sizeof(header), out); if(compress) { fwrite(outProps, 1, sizeof(outProps), out); fwrite(lzma_buffer, 1, lzma_buffer_len, out); } else { fwrite(&buffer[0], 1, buffer.size(), out); } fclose(out); if(compress) { free(lzma_buffer); } free((void*)diff_buffer); return true; }
int UncompressLzma(char *dest, size_t *destLen, const char *src, size_t *srcLen, const unsigned char *props, size_t propsSize) { return LzmaUncompress((unsigned char*)dest , destLen , (unsigned char*)src , srcLen , props , propsSize); }