예제 #1
0
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;
}
예제 #2
0
파일: stream.c 프로젝트: epa/lrzip
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;
}
예제 #3
0
파일: decomp.cpp 프로젝트: wheein/MiHaJong
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;
}
예제 #4
0
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;
}
예제 #5
0
	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);
	}
예제 #6
0
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;
}
예제 #7
0
파일: lzmacdec.cpp 프로젝트: Jerryang/cdec
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;
}
예제 #8
0
    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;
    }
예제 #9
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;
	}
}
예제 #10
0
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;
}
예제 #11
0
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;
	}
}
예제 #12
0
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);

}
예제 #13
0
파일: lzma.c 프로젝트: caoyu0/cxEngine
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;
}
예제 #14
0
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;
}
예제 #15
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;
}
예제 #16
0
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();
}
예제 #17
0
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;
}
예제 #18
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) {
예제 #19
0
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;
}
예제 #20
0
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);
}