mirror of https://github.com/Cisco-Talos/clamav
parent
bd3d39858f
commit
81fded1131
@ -0,0 +1,130 @@ |
||||
/*
|
||||
* Copyright (C) 2009 Sourcefire, Inc. |
||||
* |
||||
* Authors: aCaB |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License version 2 as |
||||
* published by the Free Software Foundation. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
||||
* MA 02110-1301, USA. |
||||
*/ |
||||
|
||||
/* 7zip scanner */ |
||||
|
||||
#if HAVE_CONFIG_H |
||||
#include "clamav-config.h" |
||||
#endif |
||||
|
||||
#include <stdio.h> |
||||
#include <sys/types.h> |
||||
#include <sys/stat.h> |
||||
#include <fcntl.h> |
||||
|
||||
#include "others.h" |
||||
#include "lzma_iface.h" |
||||
#include "7z/7zFile.h" |
||||
#include "7z/7zCrc.h" |
||||
#include "7z/Archive/7z/7zIn.h" |
||||
#include "7z/Archive/7z/7zExtract.h" |
||||
|
||||
#ifndef O_BINARY |
||||
#define O_BINARY 0 |
||||
#endif |
||||
|
||||
static ISzAlloc allocImp = { __lzma_wrap_alloc, __lzma_wrap_free}, allocTempImp = { __lzma_wrap_alloc, __lzma_wrap_free}; |
||||
|
||||
int cli_7unz (int fd, cli_ctx *ctx) { |
||||
CFileInStream archiveStream; |
||||
CLookToRead lookStream; |
||||
CSzArEx db; |
||||
UInt32 blockIndex = 0xFFFFFFFF; |
||||
char *buf = NULL; |
||||
size_t bufsz = 0; |
||||
UInt32 i; |
||||
int dupfd, ret = CL_CLEAN; |
||||
|
||||
if((dupfd = dup(fd)) == -1) { |
||||
cli_errmsg("cli_7unz: dup() failed\n"); |
||||
return CL_EDUP; |
||||
} |
||||
FileInStream_CreateVTable(&archiveStream); |
||||
archiveStream.file.file = fdopen(dupfd, "rb"); |
||||
if(!archiveStream.file.file) { |
||||
cli_errmsg("cli_7unz: fdopen() failed\n"); |
||||
return CL_EOPEN; |
||||
} |
||||
LookToRead_CreateVTable(&lookStream, False); |
||||
lookStream.realStream = &archiveStream.s; |
||||
LookToRead_Init(&lookStream); |
||||
|
||||
CrcGenerateTable(); |
||||
|
||||
SzArEx_Init(&db); |
||||
if(SzArEx_Open(&db, &lookStream.s, &allocImp, &allocTempImp) != SZ_OK) { |
||||
SzArEx_Free(&db, &allocImp); |
||||
cli_dbgmsg("cli_7unz: possibly damaged archive\n"); |
||||
return CL_CLEAN; |
||||
} |
||||
for (i = 0; i < db.db.NumFiles; i++) { |
||||
CSzFileItem *f = db.db.Files + i; |
||||
size_t offset; |
||||
size_t usize; |
||||
|
||||
if(f->IsDir || !f->Size) continue; |
||||
if(ctx->engine->maxfilesize && f->Size > ctx->engine->maxfilesize) { |
||||
cli_dbgmsg("cli_7unz: skipping stream due to size limits (%lu vs %lu)\n", f->Size, ctx->engine->maxfilesize); |
||||
continue; |
||||
} |
||||
cli_dbgmsg("cli_7unz: Extracting file %s\n", f->Name); |
||||
if(SzAr_Extract(&db, &lookStream.s, i, &blockIndex, &buf, &bufsz, &offset, &usize, &allocImp, &allocTempImp) == SZ_OK) { |
||||
char *fname; |
||||
int ofd; |
||||
|
||||
if(!usize) { |
||||
cli_dbgmsg("cli_7unz: stream uncompressed to an empty file\n"); |
||||
continue; |
||||
} |
||||
if(!(fname = cli_gentemp(ctx->engine->tmpdir))) { |
||||
ret = CL_EMEM; |
||||
break; |
||||
} |
||||
if((ofd = open(fname, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IRUSR|S_IWUSR)) < 0) { |
||||
cli_errmsg("cli_7unz: failed to create file %s\n", fname); |
||||
free(fname); |
||||
ret = CL_ECREAT; |
||||
break; |
||||
} |
||||
if(cli_writen(ofd, buf, usize) <= 0) { |
||||
close(ofd); |
||||
if(cli_unlink(fname)) ret = CL_EUNLINK; |
||||
else ret = CL_EWRITE; |
||||
free(fname); |
||||
break; |
||||
} |
||||
cli_dbgmsg("cli_7unz: extracted to %s\n", fname); |
||||
lseek(ofd, 0, SEEK_SET); |
||||
ret = cli_magic_scandesc(ofd, ctx); |
||||
close(ofd); |
||||
if(!ctx->engine->keeptmp) |
||||
if(cli_unlink(fname)) ret = CL_EUNLINK; |
||||
free(fname); |
||||
if(ret == CL_EUNLINK || ret == CL_VIRUS) |
||||
break; |
||||
} else { |
||||
cli_dbgmsg("cli_7unz: decompression failed\n"); |
||||
} |
||||
} |
||||
if(buf) free(buf); |
||||
SzArEx_Free(&db, &allocImp); |
||||
fclose(archiveStream.file.file); |
||||
return ret; |
||||
} |
||||
@ -0,0 +1,32 @@ |
||||
/*
|
||||
* Copyright (C) 2009 Sourcefire, Inc. |
||||
* |
||||
* Authors: aCaB |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License version 2 as |
||||
* published by the Free Software Foundation. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
||||
* MA 02110-1301, USA. |
||||
*/ |
||||
|
||||
#ifndef __7Z_H |
||||
#define __7Z_H |
||||
|
||||
#if HAVE_CONFIG_H |
||||
#include "clamav-config.h" |
||||
#endif |
||||
|
||||
#include "others.h" |
||||
|
||||
int cli_7unz (int, cli_ctx *); |
||||
|
||||
#endif |
||||
@ -0,0 +1,36 @@ |
||||
/* 7zBuf.c -- Byte Buffer
|
||||
2008-03-28 |
||||
Igor Pavlov |
||||
Public domain */ |
||||
|
||||
#include "7zBuf.h" |
||||
|
||||
void Buf_Init(CBuf *p) |
||||
{ |
||||
p->data = 0; |
||||
p->size = 0; |
||||
} |
||||
|
||||
int Buf_Create(CBuf *p, size_t size, ISzAlloc *alloc) |
||||
{ |
||||
p->size = 0; |
||||
if (size == 0) |
||||
{ |
||||
p->data = 0; |
||||
return 1; |
||||
} |
||||
p->data = (Byte *)alloc->Alloc(alloc, size); |
||||
if (p->data != 0) |
||||
{ |
||||
p->size = size; |
||||
return 1; |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
void Buf_Free(CBuf *p, ISzAlloc *alloc) |
||||
{ |
||||
alloc->Free(alloc, p->data); |
||||
p->data = 0; |
||||
p->size = 0; |
||||
} |
||||
@ -0,0 +1,31 @@ |
||||
/* 7zBuf.h -- Byte Buffer
|
||||
2008-10-04 : Igor Pavlov : Public domain */ |
||||
|
||||
#ifndef __7Z_BUF_H |
||||
#define __7Z_BUF_H |
||||
|
||||
#include "Types.h" |
||||
|
||||
typedef struct |
||||
{ |
||||
Byte *data; |
||||
size_t size; |
||||
} CBuf; |
||||
|
||||
void Buf_Init(CBuf *p); |
||||
int Buf_Create(CBuf *p, size_t size, ISzAlloc *alloc); |
||||
void Buf_Free(CBuf *p, ISzAlloc *alloc); |
||||
|
||||
typedef struct |
||||
{ |
||||
Byte *data; |
||||
size_t size; |
||||
size_t pos; |
||||
} CDynBuf; |
||||
|
||||
void DynBuf_Construct(CDynBuf *p); |
||||
void DynBuf_SeekToBeg(CDynBuf *p); |
||||
int DynBuf_Write(CDynBuf *p, const Byte *buf, size_t size, ISzAlloc *alloc); |
||||
void DynBuf_Free(CDynBuf *p, ISzAlloc *alloc); |
||||
|
||||
#endif |
||||
@ -0,0 +1,35 @@ |
||||
/* 7zCrc.c -- CRC32 calculation
|
||||
2008-08-05 |
||||
Igor Pavlov |
||||
Public domain */ |
||||
|
||||
#include "7zCrc.h" |
||||
|
||||
#define kCrcPoly 0xEDB88320 |
||||
UInt32 g_CrcTable[256]; |
||||
|
||||
void MY_FAST_CALL CrcGenerateTable(void) |
||||
{ |
||||
UInt32 i; |
||||
for (i = 0; i < 256; i++) |
||||
{ |
||||
UInt32 r = i; |
||||
int j; |
||||
for (j = 0; j < 8; j++) |
||||
r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1)); |
||||
g_CrcTable[i] = r; |
||||
} |
||||
} |
||||
|
||||
UInt32 MY_FAST_CALL CrcUpdate(UInt32 v, const void *data, size_t size) |
||||
{ |
||||
const Byte *p = (const Byte *)data; |
||||
for (; size > 0 ; size--, p++) |
||||
v = CRC_UPDATE_BYTE(v, *p); |
||||
return v; |
||||
} |
||||
|
||||
UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size) |
||||
{ |
||||
return CrcUpdate(CRC_INIT_VAL, data, size) ^ 0xFFFFFFFF; |
||||
} |
||||
@ -0,0 +1,24 @@ |
||||
/* 7zCrc.h -- CRC32 calculation
|
||||
2008-03-13 |
||||
Igor Pavlov |
||||
Public domain */ |
||||
|
||||
#ifndef __7Z_CRC_H |
||||
#define __7Z_CRC_H |
||||
|
||||
#include <stddef.h> |
||||
|
||||
#include "Types.h" |
||||
|
||||
extern UInt32 g_CrcTable[]; |
||||
|
||||
void MY_FAST_CALL CrcGenerateTable(void); |
||||
|
||||
#define CRC_INIT_VAL 0xFFFFFFFF |
||||
#define CRC_GET_DIGEST(crc) ((crc) ^ 0xFFFFFFFF) |
||||
#define CRC_UPDATE_BYTE(crc, b) (g_CrcTable[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) |
||||
|
||||
UInt32 MY_FAST_CALL CrcUpdate(UInt32 crc, const void *data, size_t size); |
||||
UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size); |
||||
|
||||
#endif |
||||
@ -0,0 +1,263 @@ |
||||
/* 7zFile.c -- File IO
|
||||
2008-11-22 : Igor Pavlov : Public domain */ |
||||
|
||||
#include "7zFile.h" |
||||
|
||||
#ifndef USE_WINDOWS_FILE |
||||
|
||||
#include <errno.h> |
||||
|
||||
#endif |
||||
|
||||
#ifdef USE_WINDOWS_FILE |
||||
|
||||
/*
|
||||
ReadFile and WriteFile functions in Windows have BUG: |
||||
If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1) |
||||
from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES |
||||
(Insufficient system resources exist to complete the requested service). |
||||
Probably in some version of Windows there are problems with other sizes: |
||||
for 32 MB (maybe also for 16 MB). |
||||
And message can be "Network connection was lost" |
||||
*/ |
||||
|
||||
#define kChunkSizeMax (1 << 22) |
||||
|
||||
#endif |
||||
|
||||
void File_Construct(CSzFile *p) |
||||
{ |
||||
#ifdef USE_WINDOWS_FILE |
||||
p->handle = INVALID_HANDLE_VALUE; |
||||
#else |
||||
p->file = NULL; |
||||
#endif |
||||
} |
||||
|
||||
static WRes File_Open(CSzFile *p, const char *name, int writeMode) |
||||
{ |
||||
#ifdef USE_WINDOWS_FILE |
||||
p->handle = CreateFileA(name, |
||||
writeMode ? GENERIC_WRITE : GENERIC_READ, |
||||
FILE_SHARE_READ, NULL, |
||||
writeMode ? CREATE_ALWAYS : OPEN_EXISTING, |
||||
FILE_ATTRIBUTE_NORMAL, NULL); |
||||
return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError(); |
||||
#else |
||||
p->file = fopen(name, writeMode ? "wb+" : "rb"); |
||||
return (p->file != 0) ? 0 : errno; |
||||
#endif |
||||
} |
||||
|
||||
WRes InFile_Open(CSzFile *p, const char *name) { return File_Open(p, name, 0); } |
||||
WRes OutFile_Open(CSzFile *p, const char *name) { return File_Open(p, name, 1); } |
||||
|
||||
WRes File_Close(CSzFile *p) |
||||
{ |
||||
#ifdef USE_WINDOWS_FILE |
||||
if (p->handle != INVALID_HANDLE_VALUE) |
||||
{ |
||||
if (!CloseHandle(p->handle)) |
||||
return GetLastError(); |
||||
p->handle = INVALID_HANDLE_VALUE; |
||||
} |
||||
#else |
||||
if (p->file != NULL) |
||||
{ |
||||
int res = fclose(p->file); |
||||
if (res != 0) |
||||
return res; |
||||
p->file = NULL; |
||||
} |
||||
#endif |
||||
return 0; |
||||
} |
||||
|
||||
WRes File_Read(CSzFile *p, void *data, size_t *size) |
||||
{ |
||||
size_t originalSize = *size; |
||||
if (originalSize == 0) |
||||
return 0; |
||||
|
||||
#ifdef USE_WINDOWS_FILE |
||||
|
||||
*size = 0; |
||||
do |
||||
{ |
||||
DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize; |
||||
DWORD processed = 0; |
||||
BOOL res = ReadFile(p->handle, data, curSize, &processed, NULL); |
||||
data = (void *)((Byte *)data + processed); |
||||
originalSize -= processed; |
||||
*size += processed; |
||||
if (!res) |
||||
return GetLastError(); |
||||
if (processed == 0) |
||||
break; |
||||
} |
||||
while (originalSize > 0); |
||||
return 0; |
||||
|
||||
#else |
||||
|
||||
*size = fread(data, 1, originalSize, p->file); |
||||
if (*size == originalSize) |
||||
return 0; |
||||
return ferror(p->file); |
||||
|
||||
#endif |
||||
} |
||||
|
||||
WRes File_Write(CSzFile *p, const void *data, size_t *size) |
||||
{ |
||||
size_t originalSize = *size; |
||||
if (originalSize == 0) |
||||
return 0; |
||||
|
||||
#ifdef USE_WINDOWS_FILE |
||||
|
||||
*size = 0; |
||||
do |
||||
{ |
||||
DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize; |
||||
DWORD processed = 0; |
||||
BOOL res = WriteFile(p->handle, data, curSize, &processed, NULL); |
||||
data = (void *)((Byte *)data + processed); |
||||
originalSize -= processed; |
||||
*size += processed; |
||||
if (!res) |
||||
return GetLastError(); |
||||
if (processed == 0) |
||||
break; |
||||
} |
||||
while (originalSize > 0); |
||||
return 0; |
||||
|
||||
#else |
||||
|
||||
*size = fwrite(data, 1, originalSize, p->file); |
||||
if (*size == originalSize) |
||||
return 0; |
||||
return ferror(p->file); |
||||
|
||||
#endif |
||||
} |
||||
|
||||
WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin) |
||||
{ |
||||
#ifdef USE_WINDOWS_FILE |
||||
|
||||
LARGE_INTEGER value; |
||||
DWORD moveMethod; |
||||
value.LowPart = (DWORD)*pos; |
||||
value.HighPart = (LONG)((UInt64)*pos >> 16 >> 16); /* for case when UInt64 is 32-bit only */ |
||||
switch (origin) |
||||
{ |
||||
case SZ_SEEK_SET: moveMethod = FILE_BEGIN; break; |
||||
case SZ_SEEK_CUR: moveMethod = FILE_CURRENT; break; |
||||
case SZ_SEEK_END: moveMethod = FILE_END; break; |
||||
default: return ERROR_INVALID_PARAMETER; |
||||
} |
||||
value.LowPart = SetFilePointer(p->handle, value.LowPart, &value.HighPart, moveMethod); |
||||
if (value.LowPart == 0xFFFFFFFF) |
||||
{ |
||||
WRes res = GetLastError(); |
||||
if (res != NO_ERROR) |
||||
return res; |
||||
} |
||||
*pos = ((Int64)value.HighPart << 32) | value.LowPart; |
||||
return 0; |
||||
|
||||
#else |
||||
|
||||
int moveMethod; |
||||
int res; |
||||
switch (origin) |
||||
{ |
||||
case SZ_SEEK_SET: moveMethod = SEEK_SET; break; |
||||
case SZ_SEEK_CUR: moveMethod = SEEK_CUR; break; |
||||
case SZ_SEEK_END: moveMethod = SEEK_END; break; |
||||
default: return 1; |
||||
} |
||||
res = fseek(p->file, (long)*pos, moveMethod); |
||||
*pos = ftell(p->file); |
||||
return res; |
||||
|
||||
#endif |
||||
} |
||||
|
||||
WRes File_GetLength(CSzFile *p, UInt64 *length) |
||||
{ |
||||
#ifdef USE_WINDOWS_FILE |
||||
|
||||
DWORD sizeHigh; |
||||
DWORD sizeLow = GetFileSize(p->handle, &sizeHigh); |
||||
if (sizeLow == 0xFFFFFFFF) |
||||
{ |
||||
DWORD res = GetLastError(); |
||||
if (res != NO_ERROR) |
||||
return res; |
||||
} |
||||
*length = (((UInt64)sizeHigh) << 32) + sizeLow; |
||||
return 0; |
||||
|
||||
#else |
||||
|
||||
long pos = ftell(p->file); |
||||
int res = fseek(p->file, 0, SEEK_END); |
||||
*length = ftell(p->file); |
||||
fseek(p->file, pos, SEEK_SET); |
||||
return res; |
||||
|
||||
#endif |
||||
} |
||||
|
||||
|
||||
/* ---------- FileSeqInStream ---------- */ |
||||
|
||||
static SRes FileSeqInStream_Read(void *pp, void *buf, size_t *size) |
||||
{ |
||||
CFileSeqInStream *p = (CFileSeqInStream *)pp; |
||||
return File_Read(&p->file, buf, size) == 0 ? SZ_OK : SZ_ERROR_READ; |
||||
} |
||||
|
||||
void FileSeqInStream_CreateVTable(CFileSeqInStream *p) |
||||
{ |
||||
p->s.Read = FileSeqInStream_Read; |
||||
} |
||||
|
||||
|
||||
/* ---------- FileInStream ---------- */ |
||||
|
||||
static SRes FileInStream_Read(void *pp, void *buf, size_t *size) |
||||
{ |
||||
CFileInStream *p = (CFileInStream *)pp; |
||||
return (File_Read(&p->file, buf, size) == 0) ? SZ_OK : SZ_ERROR_READ; |
||||
} |
||||
|
||||
static SRes FileInStream_Seek(void *pp, Int64 *pos, ESzSeek origin) |
||||
{ |
||||
CFileInStream *p = (CFileInStream *)pp; |
||||
return File_Seek(&p->file, pos, origin); |
||||
} |
||||
|
||||
void FileInStream_CreateVTable(CFileInStream *p) |
||||
{ |
||||
p->s.Read = FileInStream_Read; |
||||
p->s.Seek = FileInStream_Seek; |
||||
} |
||||
|
||||
|
||||
/* ---------- FileOutStream ---------- */ |
||||
|
||||
static size_t FileOutStream_Write(void *pp, const void *data, size_t size) |
||||
{ |
||||
CFileOutStream *p = (CFileOutStream *)pp; |
||||
File_Write(&p->file, data, &size); |
||||
return size; |
||||
} |
||||
|
||||
void FileOutStream_CreateVTable(CFileOutStream *p) |
||||
{ |
||||
p->s.Write = FileOutStream_Write; |
||||
} |
||||
@ -0,0 +1,74 @@ |
||||
/* 7zFile.h -- File IO
|
||||
2008-11-22 : Igor Pavlov : Public domain */ |
||||
|
||||
#ifndef __7Z_FILE_H |
||||
#define __7Z_FILE_H |
||||
|
||||
#ifdef _WIN32 |
||||
#define USE_WINDOWS_FILE |
||||
#endif |
||||
|
||||
#ifdef USE_WINDOWS_FILE |
||||
#include <windows.h> |
||||
#else |
||||
#include <stdio.h> |
||||
#endif |
||||
|
||||
#include "Types.h" |
||||
|
||||
|
||||
/* ---------- File ---------- */ |
||||
|
||||
typedef struct |
||||
{ |
||||
#ifdef USE_WINDOWS_FILE |
||||
HANDLE handle; |
||||
#else |
||||
FILE *file; |
||||
#endif |
||||
} CSzFile; |
||||
|
||||
void File_Construct(CSzFile *p); |
||||
WRes InFile_Open(CSzFile *p, const char *name); |
||||
WRes OutFile_Open(CSzFile *p, const char *name); |
||||
WRes File_Close(CSzFile *p); |
||||
|
||||
/* reads max(*size, remain file's size) bytes */ |
||||
WRes File_Read(CSzFile *p, void *data, size_t *size); |
||||
|
||||
/* writes *size bytes */ |
||||
WRes File_Write(CSzFile *p, const void *data, size_t *size); |
||||
|
||||
WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin); |
||||
WRes File_GetLength(CSzFile *p, UInt64 *length); |
||||
|
||||
|
||||
/* ---------- FileInStream ---------- */ |
||||
|
||||
typedef struct |
||||
{ |
||||
ISeqInStream s; |
||||
CSzFile file; |
||||
} CFileSeqInStream; |
||||
|
||||
void FileSeqInStream_CreateVTable(CFileSeqInStream *p); |
||||
|
||||
|
||||
typedef struct |
||||
{ |
||||
ISeekInStream s; |
||||
CSzFile file; |
||||
} CFileInStream; |
||||
|
||||
void FileInStream_CreateVTable(CFileInStream *p); |
||||
|
||||
|
||||
typedef struct |
||||
{ |
||||
ISeqOutStream s; |
||||
CSzFile file; |
||||
} CFileOutStream; |
||||
|
||||
void FileOutStream_CreateVTable(CFileOutStream *p); |
||||
|
||||
#endif |
||||
@ -0,0 +1,169 @@ |
||||
/* 7zStream.c -- 7z Stream functions
|
||||
2008-11-23 : Igor Pavlov : Public domain */ |
||||
|
||||
#include <string.h> |
||||
|
||||
#include "Types.h" |
||||
|
||||
SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType) |
||||
{ |
||||
while (size != 0) |
||||
{ |
||||
size_t processed = size; |
||||
RINOK(stream->Read(stream, buf, &processed)); |
||||
if (processed == 0) |
||||
return errorType; |
||||
buf = (void *)((Byte *)buf + processed); |
||||
size -= processed; |
||||
} |
||||
return SZ_OK; |
||||
} |
||||
|
||||
SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size) |
||||
{ |
||||
return SeqInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF); |
||||
} |
||||
|
||||
SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf) |
||||
{ |
||||
size_t processed = 1; |
||||
RINOK(stream->Read(stream, buf, &processed)); |
||||
return (processed == 1) ? SZ_OK : SZ_ERROR_INPUT_EOF; |
||||
} |
||||
|
||||
SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset) |
||||
{ |
||||
Int64 t = offset; |
||||
return stream->Seek(stream, &t, SZ_SEEK_SET); |
||||
} |
||||
|
||||
SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size) |
||||
{ |
||||
void *lookBuf; |
||||
if (*size == 0) |
||||
return SZ_OK; |
||||
RINOK(stream->Look(stream, &lookBuf, size)); |
||||
memcpy(buf, lookBuf, *size); |
||||
return stream->Skip(stream, *size); |
||||
} |
||||
|
||||
SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType) |
||||
{ |
||||
while (size != 0) |
||||
{ |
||||
size_t processed = size; |
||||
RINOK(stream->Read(stream, buf, &processed)); |
||||
if (processed == 0) |
||||
return errorType; |
||||
buf = (void *)((Byte *)buf + processed); |
||||
size -= processed; |
||||
} |
||||
return SZ_OK; |
||||
} |
||||
|
||||
SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size) |
||||
{ |
||||
return LookInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF); |
||||
} |
||||
|
||||
static SRes LookToRead_Look_Lookahead(void *pp, void **buf, size_t *size) |
||||
{ |
||||
SRes res = SZ_OK; |
||||
CLookToRead *p = (CLookToRead *)pp; |
||||
size_t size2 = p->size - p->pos; |
||||
if (size2 == 0 && *size > 0) |
||||
{ |
||||
p->pos = 0; |
||||
size2 = LookToRead_BUF_SIZE; |
||||
res = p->realStream->Read(p->realStream, p->buf, &size2); |
||||
p->size = size2; |
||||
} |
||||
if (size2 < *size) |
||||
*size = size2; |
||||
*buf = p->buf + p->pos; |
||||
return res; |
||||
} |
||||
|
||||
static SRes LookToRead_Look_Exact(void *pp, void **buf, size_t *size) |
||||
{ |
||||
SRes res = SZ_OK; |
||||
CLookToRead *p = (CLookToRead *)pp; |
||||
size_t size2 = p->size - p->pos; |
||||
if (size2 == 0 && *size > 0) |
||||
{ |
||||
p->pos = 0; |
||||
if (*size > LookToRead_BUF_SIZE) |
||||
*size = LookToRead_BUF_SIZE; |
||||
res = p->realStream->Read(p->realStream, p->buf, size); |
||||
size2 = p->size = *size; |
||||
} |
||||
if (size2 < *size) |
||||
*size = size2; |
||||
*buf = p->buf + p->pos; |
||||
return res; |
||||
} |
||||
|
||||
static SRes LookToRead_Skip(void *pp, size_t offset) |
||||
{ |
||||
CLookToRead *p = (CLookToRead *)pp; |
||||
p->pos += offset; |
||||
return SZ_OK; |
||||
} |
||||
|
||||
static SRes LookToRead_Read(void *pp, void *buf, size_t *size) |
||||
{ |
||||
CLookToRead *p = (CLookToRead *)pp; |
||||
size_t rem = p->size - p->pos; |
||||
if (rem == 0) |
||||
return p->realStream->Read(p->realStream, buf, size); |
||||
if (rem > *size) |
||||
rem = *size; |
||||
memcpy(buf, p->buf + p->pos, rem); |
||||
p->pos += rem; |
||||
*size = rem; |
||||
return SZ_OK; |
||||
} |
||||
|
||||
static SRes LookToRead_Seek(void *pp, Int64 *pos, ESzSeek origin) |
||||
{ |
||||
CLookToRead *p = (CLookToRead *)pp; |
||||
p->pos = p->size = 0; |
||||
return p->realStream->Seek(p->realStream, pos, origin); |
||||
} |
||||
|
||||
void LookToRead_CreateVTable(CLookToRead *p, int lookahead) |
||||
{ |
||||
p->s.Look = lookahead ? |
||||
LookToRead_Look_Lookahead : |
||||
LookToRead_Look_Exact; |
||||
p->s.Skip = LookToRead_Skip; |
||||
p->s.Read = LookToRead_Read; |
||||
p->s.Seek = LookToRead_Seek; |
||||
} |
||||
|
||||
void LookToRead_Init(CLookToRead *p) |
||||
{ |
||||
p->pos = p->size = 0; |
||||
} |
||||
|
||||
static SRes SecToLook_Read(void *pp, void *buf, size_t *size) |
||||
{ |
||||
CSecToLook *p = (CSecToLook *)pp; |
||||
return LookInStream_LookRead(p->realStream, buf, size); |
||||
} |
||||
|
||||
void SecToLook_CreateVTable(CSecToLook *p) |
||||
{ |
||||
p->s.Read = SecToLook_Read; |
||||
} |
||||
|
||||
static SRes SecToRead_Read(void *pp, void *buf, size_t *size) |
||||
{ |
||||
CSecToRead *p = (CSecToRead *)pp; |
||||
return p->realStream->Read(p->realStream, buf, size); |
||||
} |
||||
|
||||
void SecToRead_CreateVTable(CSecToRead *p) |
||||
{ |
||||
p->s.Read = SecToRead_Read; |
||||
} |
||||
@ -0,0 +1,254 @@ |
||||
/* 7zDecode.c -- Decoding from 7z folder
|
||||
2008-11-23 : Igor Pavlov : Public domain */ |
||||
|
||||
#include <string.h> |
||||
|
||||
#include "../../Bcj2.h" |
||||
#include "../../Bra.h" |
||||
#include "../../LzmaDec.h" |
||||
#include "7zDecode.h" |
||||
|
||||
#define k_Copy 0 |
||||
#define k_LZMA 0x30101 |
||||
#define k_BCJ 0x03030103 |
||||
#define k_BCJ2 0x0303011B |
||||
|
||||
static SRes SzDecodeLzma(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inStream, |
||||
Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain) |
||||
{ |
||||
CLzmaDec state; |
||||
SRes res = SZ_OK; |
||||
|
||||
LzmaDec_Construct(&state); |
||||
RINOK(LzmaDec_AllocateProbs(&state, coder->Props.data, (unsigned)coder->Props.size, allocMain)); |
||||
state.dic = outBuffer; |
||||
state.dicBufSize = outSize; |
||||
LzmaDec_Init(&state); |
||||
|
||||
for (;;) |
||||
{ |
||||
Byte *inBuf = NULL; |
||||
size_t lookahead = (1 << 18); |
||||
if (lookahead > inSize) |
||||
lookahead = (size_t)inSize; |
||||
res = inStream->Look((void *)inStream, (void **)&inBuf, &lookahead); |
||||
if (res != SZ_OK) |
||||
break; |
||||
|
||||
{ |
||||
SizeT inProcessed = (SizeT)lookahead, dicPos = state.dicPos; |
||||
ELzmaStatus status; |
||||
res = LzmaDec_DecodeToDic(&state, outSize, inBuf, &inProcessed, LZMA_FINISH_END, &status); |
||||
lookahead -= inProcessed; |
||||
inSize -= inProcessed; |
||||
if (res != SZ_OK) |
||||
break; |
||||
if (state.dicPos == state.dicBufSize || (inProcessed == 0 && dicPos == state.dicPos)) |
||||
{ |
||||
if (state.dicBufSize != outSize || lookahead != 0 || |
||||
(status != LZMA_STATUS_FINISHED_WITH_MARK && |
||||
status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)) |
||||
res = SZ_ERROR_DATA; |
||||
break; |
||||
} |
||||
res = inStream->Skip((void *)inStream, inProcessed); |
||||
if (res != SZ_OK) |
||||
break; |
||||
} |
||||
} |
||||
|
||||
LzmaDec_FreeProbs(&state, allocMain); |
||||
return res; |
||||
} |
||||
|
||||
static SRes SzDecodeCopy(UInt64 inSize, ILookInStream *inStream, Byte *outBuffer) |
||||
{ |
||||
while (inSize > 0) |
||||
{ |
||||
void *inBuf; |
||||
size_t curSize = (1 << 18); |
||||
if (curSize > inSize) |
||||
curSize = (size_t)inSize; |
||||
RINOK(inStream->Look((void *)inStream, (void **)&inBuf, &curSize)); |
||||
if (curSize == 0) |
||||
return SZ_ERROR_INPUT_EOF; |
||||
memcpy(outBuffer, inBuf, curSize); |
||||
outBuffer += curSize; |
||||
inSize -= curSize; |
||||
RINOK(inStream->Skip((void *)inStream, curSize)); |
||||
} |
||||
return SZ_OK; |
||||
} |
||||
|
||||
#define IS_UNSUPPORTED_METHOD(m) ((m) != k_Copy && (m) != k_LZMA) |
||||
#define IS_UNSUPPORTED_CODER(c) (IS_UNSUPPORTED_METHOD(c.MethodID) || c.NumInStreams != 1 || c.NumOutStreams != 1) |
||||
#define IS_NO_BCJ(c) (c.MethodID != k_BCJ || c.NumInStreams != 1 || c.NumOutStreams != 1) |
||||
#define IS_NO_BCJ2(c) (c.MethodID != k_BCJ2 || c.NumInStreams != 4 || c.NumOutStreams != 1) |
||||
|
||||
SRes CheckSupportedFolder(const CSzFolder *f) |
||||
{ |
||||
if (f->NumCoders < 1 || f->NumCoders > 4) |
||||
return SZ_ERROR_UNSUPPORTED; |
||||
if (IS_UNSUPPORTED_CODER(f->Coders[0])) |
||||
return SZ_ERROR_UNSUPPORTED; |
||||
if (f->NumCoders == 1) |
||||
{ |
||||
if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBindPairs != 0) |
||||
return SZ_ERROR_UNSUPPORTED; |
||||
return SZ_OK; |
||||
} |
||||
if (f->NumCoders == 2) |
||||
{ |
||||
if (IS_NO_BCJ(f->Coders[1]) || |
||||
f->NumPackStreams != 1 || f->PackStreams[0] != 0 || |
||||
f->NumBindPairs != 1 || |
||||
f->BindPairs[0].InIndex != 1 || f->BindPairs[0].OutIndex != 0) |
||||
return SZ_ERROR_UNSUPPORTED; |
||||
return SZ_OK; |
||||
} |
||||
if (f->NumCoders == 4) |
||||
{ |
||||
if (IS_UNSUPPORTED_CODER(f->Coders[1]) || |
||||
IS_UNSUPPORTED_CODER(f->Coders[2]) || |
||||
IS_NO_BCJ2(f->Coders[3])) |
||||
return SZ_ERROR_UNSUPPORTED; |
||||
if (f->NumPackStreams != 4 || |
||||
f->PackStreams[0] != 2 || |
||||
f->PackStreams[1] != 6 || |
||||
f->PackStreams[2] != 1 || |
||||
f->PackStreams[3] != 0 || |
||||
f->NumBindPairs != 3 || |
||||
f->BindPairs[0].InIndex != 5 || f->BindPairs[0].OutIndex != 0 || |
||||
f->BindPairs[1].InIndex != 4 || f->BindPairs[1].OutIndex != 1 || |
||||
f->BindPairs[2].InIndex != 3 || f->BindPairs[2].OutIndex != 2) |
||||
return SZ_ERROR_UNSUPPORTED; |
||||
return SZ_OK; |
||||
} |
||||
return SZ_ERROR_UNSUPPORTED; |
||||
} |
||||
|
||||
UInt64 GetSum(const UInt64 *values, UInt32 index) |
||||
{ |
||||
UInt64 sum = 0; |
||||
UInt32 i; |
||||
for (i = 0; i < index; i++) |
||||
sum += values[i]; |
||||
return sum; |
||||
} |
||||
|
||||
SRes SzDecode2(const UInt64 *packSizes, const CSzFolder *folder, |
||||
ILookInStream *inStream, UInt64 startPos, |
||||
Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain, |
||||
Byte *tempBuf[]) |
||||
{ |
||||
UInt32 ci; |
||||
SizeT tempSizes[3] = { 0, 0, 0}; |
||||
SizeT tempSize3 = 0; |
||||
Byte *tempBuf3 = 0; |
||||
|
||||
RINOK(CheckSupportedFolder(folder)); |
||||
|
||||
for (ci = 0; ci < folder->NumCoders; ci++) |
||||
{ |
||||
CSzCoderInfo *coder = &folder->Coders[ci]; |
||||
|
||||
if (coder->MethodID == k_Copy || coder->MethodID == k_LZMA) |
||||
{ |
||||
UInt32 si = 0; |
||||
UInt64 offset; |
||||
UInt64 inSize; |
||||
Byte *outBufCur = outBuffer; |
||||
SizeT outSizeCur = outSize; |
||||
if (folder->NumCoders == 4) |
||||
{ |
||||
UInt32 indices[] = { 3, 2, 0 }; |
||||
UInt64 unpackSize = folder->UnpackSizes[ci]; |
||||
si = indices[ci]; |
||||
if (ci < 2) |
||||
{ |
||||
Byte *temp; |
||||
outSizeCur = (SizeT)unpackSize; |
||||
if (outSizeCur != unpackSize) |
||||
return SZ_ERROR_MEM; |
||||
temp = (Byte *)IAlloc_Alloc(allocMain, outSizeCur); |
||||
if (temp == 0 && outSizeCur != 0) |
||||
return SZ_ERROR_MEM; |
||||
outBufCur = tempBuf[1 - ci] = temp; |
||||
tempSizes[1 - ci] = outSizeCur; |
||||
} |
||||
else if (ci == 2) |
||||
{ |
||||
if (unpackSize > outSize) /* check it */ |
||||
return SZ_ERROR_PARAM; |
||||
tempBuf3 = outBufCur = outBuffer + (outSize - (size_t)unpackSize); |
||||
tempSize3 = outSizeCur = (SizeT)unpackSize; |
||||
} |
||||
else |
||||
return SZ_ERROR_UNSUPPORTED; |
||||
} |
||||
offset = GetSum(packSizes, si); |
||||
inSize = packSizes[si]; |
||||
RINOK(LookInStream_SeekTo(inStream, startPos + offset)); |
||||
|
||||
if (coder->MethodID == k_Copy) |
||||
{ |
||||
if (inSize != outSizeCur) /* check it */ |
||||
return SZ_ERROR_DATA; |
||||
RINOK(SzDecodeCopy(inSize, inStream, outBufCur)); |
||||
} |
||||
else |
||||
{ |
||||
RINOK(SzDecodeLzma(coder, inSize, inStream, outBufCur, outSizeCur, allocMain)); |
||||
} |
||||
} |
||||
else if (coder->MethodID == k_BCJ) |
||||
{ |
||||
UInt32 state; |
||||
if (ci != 1) |
||||
return SZ_ERROR_UNSUPPORTED; |
||||
x86_Convert_Init(state); |
||||
x86_Convert(outBuffer, outSize, 0, &state, 0); |
||||
} |
||||
else if (coder->MethodID == k_BCJ2) |
||||
{ |
||||
UInt64 offset = GetSum(packSizes, 1); |
||||
UInt64 s3Size = packSizes[1]; |
||||
SRes res; |
||||
if (ci != 3) |
||||
return SZ_ERROR_UNSUPPORTED; |
||||
RINOK(LookInStream_SeekTo(inStream, startPos + offset)); |
||||
tempSizes[2] = (SizeT)s3Size; |
||||
if (tempSizes[2] != s3Size) |
||||
return SZ_ERROR_MEM; |
||||
tempBuf[2] = (Byte *)IAlloc_Alloc(allocMain, tempSizes[2]); |
||||
if (tempBuf[2] == 0 && tempSizes[2] != 0) |
||||
return SZ_ERROR_MEM; |
||||
res = SzDecodeCopy(s3Size, inStream, tempBuf[2]); |
||||
RINOK(res) |
||||
|
||||
res = Bcj2_Decode( |
||||
tempBuf3, tempSize3, |
||||
tempBuf[0], tempSizes[0], |
||||
tempBuf[1], tempSizes[1], |
||||
tempBuf[2], tempSizes[2], |
||||
outBuffer, outSize); |
||||
RINOK(res) |
||||
} |
||||
else |
||||
return SZ_ERROR_UNSUPPORTED; |
||||
} |
||||
return SZ_OK; |
||||
} |
||||
|
||||
SRes SzDecode(const UInt64 *packSizes, const CSzFolder *folder, |
||||
ILookInStream *inStream, UInt64 startPos, |
||||
Byte *outBuffer, size_t outSize, ISzAlloc *allocMain) |
||||
{ |
||||
Byte *tempBuf[3] = { 0, 0, 0}; |
||||
int i; |
||||
SRes res = SzDecode2(packSizes, folder, inStream, startPos, |
||||
outBuffer, (SizeT)outSize, allocMain, tempBuf); |
||||
for (i = 0; i < 3; i++) |
||||
IAlloc_Free(allocMain, tempBuf[i]); |
||||
return res; |
||||
} |
||||
@ -0,0 +1,13 @@ |
||||
/* 7zDecode.h -- Decoding from 7z folder
|
||||
2008-11-23 : Igor Pavlov : Public domain */ |
||||
|
||||
#ifndef __7Z_DECODE_H |
||||
#define __7Z_DECODE_H |
||||
|
||||
#include "7zItem.h" |
||||
|
||||
SRes SzDecode(const UInt64 *packSizes, const CSzFolder *folder, |
||||
ILookInStream *stream, UInt64 startPos, |
||||
Byte *outBuffer, size_t outSize, ISzAlloc *allocMain); |
||||
|
||||
#endif |
||||
@ -0,0 +1,93 @@ |
||||
/* 7zExtract.c -- Extracting from 7z archive
|
||||
2008-11-23 : Igor Pavlov : Public domain */ |
||||
|
||||
#include "../../7zCrc.h" |
||||
#include "7zDecode.h" |
||||
#include "7zExtract.h" |
||||
|
||||
SRes SzAr_Extract( |
||||
const CSzArEx *p, |
||||
ILookInStream *inStream, |
||||
UInt32 fileIndex, |
||||
UInt32 *blockIndex, |
||||
Byte **outBuffer, |
||||
size_t *outBufferSize, |
||||
size_t *offset, |
||||
size_t *outSizeProcessed, |
||||
ISzAlloc *allocMain, |
||||
ISzAlloc *allocTemp) |
||||
{ |
||||
UInt32 folderIndex = p->FileIndexToFolderIndexMap[fileIndex]; |
||||
SRes res = SZ_OK; |
||||
*offset = 0; |
||||
*outSizeProcessed = 0; |
||||
if (folderIndex == (UInt32)-1) |
||||
{ |
||||
IAlloc_Free(allocMain, *outBuffer); |
||||
*blockIndex = folderIndex; |
||||
*outBuffer = 0; |
||||
*outBufferSize = 0; |
||||
return SZ_OK; |
||||
} |
||||
|
||||
if (*outBuffer == 0 || *blockIndex != folderIndex) |
||||
{ |
||||
CSzFolder *folder = p->db.Folders + folderIndex; |
||||
UInt64 unpackSizeSpec = SzFolder_GetUnpackSize(folder); |
||||
size_t unpackSize = (size_t)unpackSizeSpec; |
||||
UInt64 startOffset = SzArEx_GetFolderStreamPos(p, folderIndex, 0); |
||||
|
||||
if (unpackSize != unpackSizeSpec) |
||||
return SZ_ERROR_MEM; |
||||
*blockIndex = folderIndex; |
||||
IAlloc_Free(allocMain, *outBuffer); |
||||
*outBuffer = 0; |
||||
|
||||
RINOK(LookInStream_SeekTo(inStream, startOffset)); |
||||
|
||||
if (res == SZ_OK) |
||||
{ |
||||
*outBufferSize = unpackSize; |
||||
if (unpackSize != 0) |
||||
{ |
||||
*outBuffer = (Byte *)IAlloc_Alloc(allocMain, unpackSize); |
||||
if (*outBuffer == 0) |
||||
res = SZ_ERROR_MEM; |
||||
} |
||||
if (res == SZ_OK) |
||||
{ |
||||
res = SzDecode(p->db.PackSizes + |
||||
p->FolderStartPackStreamIndex[folderIndex], folder, |
||||
inStream, startOffset, |
||||
*outBuffer, unpackSize, allocTemp); |
||||
if (res == SZ_OK) |
||||
{ |
||||
if (folder->UnpackCRCDefined) |
||||
{ |
||||
if (CrcCalc(*outBuffer, unpackSize) != folder->UnpackCRC) |
||||
res = SZ_ERROR_CRC; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
if (res == SZ_OK) |
||||
{ |
||||
UInt32 i; |
||||
CSzFileItem *fileItem = p->db.Files + fileIndex; |
||||
*offset = 0; |
||||
for (i = p->FolderStartFileIndex[folderIndex]; i < fileIndex; i++) |
||||
*offset += (UInt32)p->db.Files[i].Size; |
||||
*outSizeProcessed = (size_t)fileItem->Size; |
||||
if (*offset + *outSizeProcessed > *outBufferSize) |
||||
return SZ_ERROR_FAIL; |
||||
{ |
||||
if (fileItem->FileCRCDefined) |
||||
{ |
||||
if (CrcCalc(*outBuffer + *offset, *outSizeProcessed) != fileItem->FileCRC) |
||||
res = SZ_ERROR_CRC; |
||||
} |
||||
} |
||||
} |
||||
return res; |
||||
} |
||||
@ -0,0 +1,41 @@ |
||||
/* 7zExtract.h -- Extracting from 7z archive
|
||||
2008-11-23 : Igor Pavlov : Public domain */ |
||||
|
||||
#ifndef __7Z_EXTRACT_H |
||||
#define __7Z_EXTRACT_H |
||||
|
||||
#include "7zIn.h" |
||||
|
||||
/*
|
||||
SzExtract extracts file from archive |
||||
|
||||
*outBuffer must be 0 before first call for each new archive. |
||||
|
||||
Extracting cache: |
||||
If you need to decompress more than one file, you can send |
||||
these values from previous call: |
||||
*blockIndex, |
||||
*outBuffer, |
||||
*outBufferSize |
||||
You can consider "*outBuffer" as cache of solid block. If your archive is solid, |
||||
it will increase decompression speed. |
||||
|
||||
If you use external function, you can declare these 3 cache variables |
||||
(blockIndex, outBuffer, outBufferSize) as static in that external function. |
||||
|
||||
Free *outBuffer and set *outBuffer to 0, if you want to flush cache. |
||||
*/ |
||||
|
||||
SRes SzAr_Extract( |
||||
const CSzArEx *db, |
||||
ILookInStream *inStream, |
||||
UInt32 fileIndex, /* index of file */ |
||||
UInt32 *blockIndex, /* index of solid block */ |
||||
Byte **outBuffer, /* pointer to pointer to output buffer (allocated with allocMain) */ |
||||
size_t *outBufferSize, /* buffer size for output buffer */ |
||||
size_t *offset, /* offset of stream for required file in *outBuffer */ |
||||
size_t *outSizeProcessed, /* size of file in *outBuffer */ |
||||
ISzAlloc *allocMain, |
||||
ISzAlloc *allocTemp); |
||||
|
||||
#endif |
||||
@ -0,0 +1,6 @@ |
||||
/* 7zHeader.c -- 7z Headers
|
||||
2008-10-04 : Igor Pavlov : Public domain */ |
||||
|
||||
#include "7zHeader.h" |
||||
|
||||
Byte k7zSignature[k7zSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C}; |
||||
@ -0,0 +1,57 @@ |
||||
/* 7zHeader.h -- 7z Headers
|
||||
2008-10-04 : Igor Pavlov : Public domain */ |
||||
|
||||
#ifndef __7Z_HEADER_H |
||||
#define __7Z_HEADER_H |
||||
|
||||
#include "../../Types.h" |
||||
|
||||
#define k7zSignatureSize 6 |
||||
extern Byte k7zSignature[k7zSignatureSize]; |
||||
|
||||
#define k7zMajorVersion 0 |
||||
|
||||
#define k7zStartHeaderSize 0x20 |
||||
|
||||
enum EIdEnum |
||||
{ |
||||
k7zIdEnd, |
||||
|
||||
k7zIdHeader, |
||||
|
||||
k7zIdArchiveProperties, |
||||
|
||||
k7zIdAdditionalStreamsInfo, |
||||
k7zIdMainStreamsInfo, |
||||
k7zIdFilesInfo, |
||||
|
||||
k7zIdPackInfo, |
||||
k7zIdUnpackInfo, |
||||
k7zIdSubStreamsInfo, |
||||
|
||||
k7zIdSize, |
||||
k7zIdCRC, |
||||
|
||||
k7zIdFolder, |
||||
|
||||
k7zIdCodersUnpackSize, |
||||
k7zIdNumUnpackStream, |
||||
|
||||
k7zIdEmptyStream, |
||||
k7zIdEmptyFile, |
||||
k7zIdAnti, |
||||
|
||||
k7zIdName, |
||||
k7zIdCTime, |
||||
k7zIdATime, |
||||
k7zIdMTime, |
||||
k7zIdWinAttributes, |
||||
k7zIdComment, |
||||
|
||||
k7zIdEncodedHeader, |
||||
|
||||
k7zIdStartPos, |
||||
k7zIdDummy |
||||
}; |
||||
|
||||
#endif |
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,41 @@ |
||||
/* 7zIn.h -- 7z Input functions
|
||||
2008-11-23 : Igor Pavlov : Public domain */ |
||||
|
||||
#ifndef __7Z_IN_H |
||||
#define __7Z_IN_H |
||||
|
||||
#include "7zHeader.h" |
||||
#include "7zItem.h" |
||||
|
||||
typedef struct |
||||
{ |
||||
CSzAr db; |
||||
|
||||
UInt64 startPosAfterHeader; |
||||
UInt64 dataPos; |
||||
|
||||
UInt32 *FolderStartPackStreamIndex; |
||||
UInt64 *PackStreamStartPositions; |
||||
UInt32 *FolderStartFileIndex; |
||||
UInt32 *FileIndexToFolderIndexMap; |
||||
} CSzArEx; |
||||
|
||||
void SzArEx_Init(CSzArEx *p); |
||||
void SzArEx_Free(CSzArEx *p, ISzAlloc *alloc); |
||||
UInt64 SzArEx_GetFolderStreamPos(const CSzArEx *p, UInt32 folderIndex, UInt32 indexInFolder); |
||||
int SzArEx_GetFolderFullPackSize(const CSzArEx *p, UInt32 folderIndex, UInt64 *resSize); |
||||
|
||||
/*
|
||||
Errors: |
||||
SZ_ERROR_NO_ARCHIVE |
||||
SZ_ERROR_ARCHIVE |
||||
SZ_ERROR_UNSUPPORTED |
||||
SZ_ERROR_MEM |
||||
SZ_ERROR_CRC |
||||
SZ_ERROR_INPUT_EOF |
||||
SZ_ERROR_FAIL |
||||
*/ |
||||
|
||||
SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream, ISzAlloc *allocMain, ISzAlloc *allocTemp); |
||||
|
||||
#endif |
||||
@ -0,0 +1,127 @@ |
||||
/* 7zItem.c -- 7z Items
|
||||
2008-10-04 : Igor Pavlov : Public domain */ |
||||
|
||||
#include "7zItem.h" |
||||
|
||||
void SzCoderInfo_Init(CSzCoderInfo *p) |
||||
{ |
||||
Buf_Init(&p->Props); |
||||
} |
||||
|
||||
void SzCoderInfo_Free(CSzCoderInfo *p, ISzAlloc *alloc) |
||||
{ |
||||
Buf_Free(&p->Props, alloc); |
||||
SzCoderInfo_Init(p); |
||||
} |
||||
|
||||
void SzFolder_Init(CSzFolder *p) |
||||
{ |
||||
p->Coders = 0; |
||||
p->BindPairs = 0; |
||||
p->PackStreams = 0; |
||||
p->UnpackSizes = 0; |
||||
p->NumCoders = 0; |
||||
p->NumBindPairs = 0; |
||||
p->NumPackStreams = 0; |
||||
p->UnpackCRCDefined = 0; |
||||
p->UnpackCRC = 0; |
||||
p->NumUnpackStreams = 0; |
||||
} |
||||
|
||||
void SzFolder_Free(CSzFolder *p, ISzAlloc *alloc) |
||||
{ |
||||
UInt32 i; |
||||
if (p->Coders) |
||||
for (i = 0; i < p->NumCoders; i++) |
||||
SzCoderInfo_Free(&p->Coders[i], alloc); |
||||
IAlloc_Free(alloc, p->Coders); |
||||
IAlloc_Free(alloc, p->BindPairs); |
||||
IAlloc_Free(alloc, p->PackStreams); |
||||
IAlloc_Free(alloc, p->UnpackSizes); |
||||
SzFolder_Init(p); |
||||
} |
||||
|
||||
UInt32 SzFolder_GetNumOutStreams(CSzFolder *p) |
||||
{ |
||||
UInt32 result = 0; |
||||
UInt32 i; |
||||
for (i = 0; i < p->NumCoders; i++) |
||||
result += p->Coders[i].NumOutStreams; |
||||
return result; |
||||
} |
||||
|
||||
int SzFolder_FindBindPairForInStream(CSzFolder *p, UInt32 inStreamIndex) |
||||
{ |
||||
UInt32 i; |
||||
for (i = 0; i < p->NumBindPairs; i++) |
||||
if (p->BindPairs[i].InIndex == inStreamIndex) |
||||
return i; |
||||
return -1; |
||||
} |
||||
|
||||
|
||||
int SzFolder_FindBindPairForOutStream(CSzFolder *p, UInt32 outStreamIndex) |
||||
{ |
||||
UInt32 i; |
||||
for (i = 0; i < p->NumBindPairs; i++) |
||||
if (p->BindPairs[i].OutIndex == outStreamIndex) |
||||
return i; |
||||
return -1; |
||||
} |
||||
|
||||
UInt64 SzFolder_GetUnpackSize(CSzFolder *p) |
||||
{ |
||||
int i = (int)SzFolder_GetNumOutStreams(p); |
||||
if (i == 0) |
||||
return 0; |
||||
for (i--; i >= 0; i--) |
||||
if (SzFolder_FindBindPairForOutStream(p, i) < 0) |
||||
return p->UnpackSizes[i]; |
||||
/* throw 1; */ |
||||
return 0; |
||||
} |
||||
|
||||
void SzFile_Init(CSzFileItem *p) |
||||
{ |
||||
p->HasStream = 1; |
||||
p->IsDir = 0; |
||||
p->IsAnti = 0; |
||||
p->FileCRCDefined = 0; |
||||
p->MTimeDefined = 0; |
||||
p->Name = 0; |
||||
} |
||||
|
||||
static void SzFile_Free(CSzFileItem *p, ISzAlloc *alloc) |
||||
{ |
||||
IAlloc_Free(alloc, p->Name); |
||||
SzFile_Init(p); |
||||
} |
||||
|
||||
void SzAr_Init(CSzAr *p) |
||||
{ |
||||
p->PackSizes = 0; |
||||
p->PackCRCsDefined = 0; |
||||
p->PackCRCs = 0; |
||||
p->Folders = 0; |
||||
p->Files = 0; |
||||
p->NumPackStreams = 0; |
||||
p->NumFolders = 0; |
||||
p->NumFiles = 0; |
||||
} |
||||
|
||||
void SzAr_Free(CSzAr *p, ISzAlloc *alloc) |
||||
{ |
||||
UInt32 i; |
||||
if (p->Folders) |
||||
for (i = 0; i < p->NumFolders; i++) |
||||
SzFolder_Free(&p->Folders[i], alloc); |
||||
if (p->Files) |
||||
for (i = 0; i < p->NumFiles; i++) |
||||
SzFile_Free(&p->Files[i], alloc); |
||||
IAlloc_Free(alloc, p->PackSizes); |
||||
IAlloc_Free(alloc, p->PackCRCsDefined); |
||||
IAlloc_Free(alloc, p->PackCRCs); |
||||
IAlloc_Free(alloc, p->Folders); |
||||
IAlloc_Free(alloc, p->Files); |
||||
SzAr_Init(p); |
||||
} |
||||
@ -0,0 +1,84 @@ |
||||
/* 7zItem.h -- 7z Items
|
||||
2008-10-04 : Igor Pavlov : Public domain */ |
||||
|
||||
#ifndef __7Z_ITEM_H |
||||
#define __7Z_ITEM_H |
||||
|
||||
#include "../../7zBuf.h" |
||||
|
||||
typedef struct |
||||
{ |
||||
UInt32 NumInStreams; |
||||
UInt32 NumOutStreams; |
||||
UInt64 MethodID; |
||||
CBuf Props; |
||||
} CSzCoderInfo; |
||||
|
||||
void SzCoderInfo_Init(CSzCoderInfo *p); |
||||
void SzCoderInfo_Free(CSzCoderInfo *p, ISzAlloc *alloc); |
||||
|
||||
typedef struct |
||||
{ |
||||
UInt32 InIndex; |
||||
UInt32 OutIndex; |
||||
} CBindPair; |
||||
|
||||
typedef struct |
||||
{ |
||||
CSzCoderInfo *Coders; |
||||
CBindPair *BindPairs; |
||||
UInt32 *PackStreams; |
||||
UInt64 *UnpackSizes; |
||||
UInt32 NumCoders; |
||||
UInt32 NumBindPairs; |
||||
UInt32 NumPackStreams; |
||||
int UnpackCRCDefined; |
||||
UInt32 UnpackCRC; |
||||
|
||||
UInt32 NumUnpackStreams; |
||||
} CSzFolder; |
||||
|
||||
void SzFolder_Init(CSzFolder *p); |
||||
UInt64 SzFolder_GetUnpackSize(CSzFolder *p); |
||||
int SzFolder_FindBindPairForInStream(CSzFolder *p, UInt32 inStreamIndex); |
||||
UInt32 SzFolder_GetNumOutStreams(CSzFolder *p); |
||||
UInt64 SzFolder_GetUnpackSize(CSzFolder *p); |
||||
|
||||
typedef struct |
||||
{ |
||||
UInt32 Low; |
||||
UInt32 High; |
||||
} CNtfsFileTime; |
||||
|
||||
typedef struct |
||||
{ |
||||
CNtfsFileTime MTime; |
||||
UInt64 Size; |
||||
char *Name; |
||||
UInt32 FileCRC; |
||||
|
||||
Byte HasStream; |
||||
Byte IsDir; |
||||
Byte IsAnti; |
||||
Byte FileCRCDefined; |
||||
Byte MTimeDefined; |
||||
} CSzFileItem; |
||||
|
||||
void SzFile_Init(CSzFileItem *p); |
||||
|
||||
typedef struct |
||||
{ |
||||
UInt64 *PackSizes; |
||||
Byte *PackCRCsDefined; |
||||
UInt32 *PackCRCs; |
||||
CSzFolder *Folders; |
||||
CSzFileItem *Files; |
||||
UInt32 NumPackStreams; |
||||
UInt32 NumFolders; |
||||
UInt32 NumFiles; |
||||
} CSzAr; |
||||
|
||||
void SzAr_Init(CSzAr *p); |
||||
void SzAr_Free(CSzAr *p, ISzAlloc *alloc); |
||||
|
||||
#endif |
||||
@ -0,0 +1,132 @@ |
||||
/* Bcj2.c -- Converter for x86 code (BCJ2)
|
||||
2008-10-04 : Igor Pavlov : Public domain */ |
||||
|
||||
#include "Bcj2.h" |
||||
|
||||
#ifdef _LZMA_PROB32 |
||||
#define CProb UInt32 |
||||
#else |
||||
#define CProb UInt16 |
||||
#endif |
||||
|
||||
#define IsJcc(b0, b1) ((b0) == 0x0F && ((b1) & 0xF0) == 0x80) |
||||
#define IsJ(b0, b1) ((b1 & 0xFE) == 0xE8 || IsJcc(b0, b1)) |
||||
|
||||
#define kNumTopBits 24 |
||||
#define kTopValue ((UInt32)1 << kNumTopBits) |
||||
|
||||
#define kNumBitModelTotalBits 11 |
||||
#define kBitModelTotal (1 << kNumBitModelTotalBits) |
||||
#define kNumMoveBits 5 |
||||
|
||||
#define RC_READ_BYTE (*buffer++) |
||||
#define RC_TEST { if (buffer == bufferLim) return SZ_ERROR_DATA; } |
||||
#define RC_INIT2 code = 0; range = 0xFFFFFFFF; \ |
||||
{ int i; for (i = 0; i < 5; i++) { RC_TEST; code = (code << 8) | RC_READ_BYTE; }} |
||||
|
||||
#define NORMALIZE if (range < kTopValue) { RC_TEST; range <<= 8; code = (code << 8) | RC_READ_BYTE; } |
||||
|
||||
#define IF_BIT_0(p) ttt = *(p); bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) |
||||
#define UPDATE_0(p) range = bound; *(p) = (CProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); NORMALIZE; |
||||
#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CProb)(ttt - (ttt >> kNumMoveBits)); NORMALIZE; |
||||
|
||||
int Bcj2_Decode( |
||||
const Byte *buf0, SizeT size0, |
||||
const Byte *buf1, SizeT size1, |
||||
const Byte *buf2, SizeT size2, |
||||
const Byte *buf3, SizeT size3, |
||||
Byte *outBuf, SizeT outSize) |
||||
{ |
||||
CProb p[256 + 2]; |
||||
SizeT inPos = 0, outPos = 0; |
||||
|
||||
const Byte *buffer, *bufferLim; |
||||
UInt32 range, code; |
||||
Byte prevByte = 0; |
||||
|
||||
unsigned int i; |
||||
for (i = 0; i < sizeof(p) / sizeof(p[0]); i++) |
||||
p[i] = kBitModelTotal >> 1; |
||||
|
||||
buffer = buf3; |
||||
bufferLim = buffer + size3; |
||||
RC_INIT2 |
||||
|
||||
if (outSize == 0) |
||||
return SZ_OK; |
||||
|
||||
for (;;) |
||||
{ |
||||
Byte b; |
||||
CProb *prob; |
||||
UInt32 bound; |
||||
UInt32 ttt; |
||||
|
||||
SizeT limit = size0 - inPos; |
||||
if (outSize - outPos < limit) |
||||
limit = outSize - outPos; |
||||
while (limit != 0) |
||||
{ |
||||
Byte b = buf0[inPos]; |
||||
outBuf[outPos++] = b; |
||||
if (IsJ(prevByte, b)) |
||||
break; |
||||
inPos++; |
||||
prevByte = b; |
||||
limit--; |
||||
} |
||||
|
||||
if (limit == 0 || outPos == outSize) |
||||
break; |
||||
|
||||
b = buf0[inPos++]; |
||||
|
||||
if (b == 0xE8) |
||||
prob = p + prevByte; |
||||
else if (b == 0xE9) |
||||
prob = p + 256; |
||||
else |
||||
prob = p + 257; |
||||
|
||||
IF_BIT_0(prob) |
||||
{ |
||||
UPDATE_0(prob) |
||||
prevByte = b; |
||||
} |
||||
else |
||||
{ |
||||
UInt32 dest; |
||||
const Byte *v; |
||||
UPDATE_1(prob) |
||||
if (b == 0xE8) |
||||
{ |
||||
v = buf1; |
||||
if (size1 < 4) |
||||
return SZ_ERROR_DATA; |
||||
buf1 += 4; |
||||
size1 -= 4; |
||||
} |
||||
else |
||||
{ |
||||
v = buf2; |
||||
if (size2 < 4) |
||||
return SZ_ERROR_DATA; |
||||
buf2 += 4; |
||||
size2 -= 4; |
||||
} |
||||
dest = (((UInt32)v[0] << 24) | ((UInt32)v[1] << 16) | |
||||
((UInt32)v[2] << 8) | ((UInt32)v[3])) - ((UInt32)outPos + 4); |
||||
outBuf[outPos++] = (Byte)dest; |
||||
if (outPos == outSize) |
||||
break; |
||||
outBuf[outPos++] = (Byte)(dest >> 8); |
||||
if (outPos == outSize) |
||||
break; |
||||
outBuf[outPos++] = (Byte)(dest >> 16); |
||||
if (outPos == outSize) |
||||
break; |
||||
outBuf[outPos++] = prevByte = (Byte)(dest >> 24); |
||||
} |
||||
} |
||||
return (outPos == outSize) ? SZ_OK : SZ_ERROR_DATA; |
||||
} |
||||
@ -0,0 +1,30 @@ |
||||
/* Bcj2.h -- Converter for x86 code (BCJ2)
|
||||
2008-10-04 : Igor Pavlov : Public domain */ |
||||
|
||||
#ifndef __BCJ2_H |
||||
#define __BCJ2_H |
||||
|
||||
#include "Types.h" |
||||
|
||||
/*
|
||||
Conditions: |
||||
outSize <= FullOutputSize, |
||||
where FullOutputSize is full size of output stream of x86_2 filter. |
||||
|
||||
If buf0 overlaps outBuf, there are two required conditions: |
||||
1) (buf0 >= outBuf) |
||||
2) (buf0 + size0 >= outBuf + FullOutputSize). |
||||
|
||||
Returns: |
||||
SZ_OK |
||||
SZ_ERROR_DATA - Data error |
||||
*/ |
||||
|
||||
int Bcj2_Decode( |
||||
const Byte *buf0, SizeT size0, |
||||
const Byte *buf1, SizeT size1, |
||||
const Byte *buf2, SizeT size2, |
||||
const Byte *buf3, SizeT size3, |
||||
Byte *outBuf, SizeT outSize); |
||||
|
||||
#endif |
||||
@ -0,0 +1,133 @@ |
||||
/* Bra.c -- Converters for RISC code
|
||||
2008-10-04 : Igor Pavlov : Public domain */ |
||||
|
||||
#include "Bra.h" |
||||
|
||||
SizeT ARM_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) |
||||
{ |
||||
SizeT i; |
||||
if (size < 4) |
||||
return 0; |
||||
size -= 4; |
||||
ip += 8; |
||||
for (i = 0; i <= size; i += 4) |
||||
{ |
||||
if (data[i + 3] == 0xEB) |
||||
{ |
||||
UInt32 dest; |
||||
UInt32 src = ((UInt32)data[i + 2] << 16) | ((UInt32)data[i + 1] << 8) | (data[i + 0]); |
||||
src <<= 2; |
||||
if (encoding) |
||||
dest = ip + (UInt32)i + src; |
||||
else |
||||
dest = src - (ip + (UInt32)i); |
||||
dest >>= 2; |
||||
data[i + 2] = (Byte)(dest >> 16); |
||||
data[i + 1] = (Byte)(dest >> 8); |
||||
data[i + 0] = (Byte)dest; |
||||
} |
||||
} |
||||
return i; |
||||
} |
||||
|
||||
SizeT ARMT_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) |
||||
{ |
||||
SizeT i; |
||||
if (size < 4) |
||||
return 0; |
||||
size -= 4; |
||||
ip += 4; |
||||
for (i = 0; i <= size; i += 2) |
||||
{ |
||||
if ((data[i + 1] & 0xF8) == 0xF0 && |
||||
(data[i + 3] & 0xF8) == 0xF8) |
||||
{ |
||||
UInt32 dest; |
||||
UInt32 src = |
||||
(((UInt32)data[i + 1] & 0x7) << 19) | |
||||
((UInt32)data[i + 0] << 11) | |
||||
(((UInt32)data[i + 3] & 0x7) << 8) | |
||||
(data[i + 2]); |
||||
|
||||
src <<= 1; |
||||
if (encoding) |
||||
dest = ip + (UInt32)i + src; |
||||
else |
||||
dest = src - (ip + (UInt32)i); |
||||
dest >>= 1; |
||||
|
||||
data[i + 1] = (Byte)(0xF0 | ((dest >> 19) & 0x7)); |
||||
data[i + 0] = (Byte)(dest >> 11); |
||||
data[i + 3] = (Byte)(0xF8 | ((dest >> 8) & 0x7)); |
||||
data[i + 2] = (Byte)dest; |
||||
i += 2; |
||||
} |
||||
} |
||||
return i; |
||||
} |
||||
|
||||
SizeT PPC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) |
||||
{ |
||||
SizeT i; |
||||
if (size < 4) |
||||
return 0; |
||||
size -= 4; |
||||
for (i = 0; i <= size; i += 4) |
||||
{ |
||||
if ((data[i] >> 2) == 0x12 && (data[i + 3] & 3) == 1) |
||||
{ |
||||
UInt32 src = ((UInt32)(data[i + 0] & 3) << 24) | |
||||
((UInt32)data[i + 1] << 16) | |
||||
((UInt32)data[i + 2] << 8) | |
||||
((UInt32)data[i + 3] & (~3)); |
||||
|
||||
UInt32 dest; |
||||
if (encoding) |
||||
dest = ip + (UInt32)i + src; |
||||
else |
||||
dest = src - (ip + (UInt32)i); |
||||
data[i + 0] = (Byte)(0x48 | ((dest >> 24) & 0x3)); |
||||
data[i + 1] = (Byte)(dest >> 16); |
||||
data[i + 2] = (Byte)(dest >> 8); |
||||
data[i + 3] &= 0x3; |
||||
data[i + 3] |= dest; |
||||
} |
||||
} |
||||
return i; |
||||
} |
||||
|
||||
SizeT SPARC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) |
||||
{ |
||||
UInt32 i; |
||||
if (size < 4) |
||||
return 0; |
||||
size -= 4; |
||||
for (i = 0; i <= size; i += 4) |
||||
{ |
||||
if (data[i] == 0x40 && (data[i + 1] & 0xC0) == 0x00 || |
||||
data[i] == 0x7F && (data[i + 1] & 0xC0) == 0xC0) |
||||
{ |
||||
UInt32 src = |
||||
((UInt32)data[i + 0] << 24) | |
||||
((UInt32)data[i + 1] << 16) | |
||||
((UInt32)data[i + 2] << 8) | |
||||
((UInt32)data[i + 3]); |
||||
UInt32 dest; |
||||
|
||||
src <<= 2; |
||||
if (encoding) |
||||
dest = ip + i + src; |
||||
else |
||||
dest = src - (ip + i); |
||||
dest >>= 2; |
||||
|
||||
dest = (((0 - ((dest >> 22) & 1)) << 22) & 0x3FFFFFFF) | (dest & 0x3FFFFF) | 0x40000000; |
||||
|
||||
data[i + 0] = (Byte)(dest >> 24); |
||||
data[i + 1] = (Byte)(dest >> 16); |
||||
data[i + 2] = (Byte)(dest >> 8); |
||||
data[i + 3] = (Byte)dest; |
||||
} |
||||
} |
||||
return i; |
||||
} |
||||
@ -0,0 +1,60 @@ |
||||
/* Bra.h -- Branch converters for executables
|
||||
2008-10-04 : Igor Pavlov : Public domain */ |
||||
|
||||
#ifndef __BRA_H |
||||
#define __BRA_H |
||||
|
||||
#include "Types.h" |
||||
|
||||
/*
|
||||
These functions convert relative addresses to absolute addresses |
||||
in CALL instructions to increase the compression ratio. |
||||
|
||||
In: |
||||
data - data buffer |
||||
size - size of data |
||||
ip - current virtual Instruction Pinter (IP) value |
||||
state - state variable for x86 converter |
||||
encoding - 0 (for decoding), 1 (for encoding) |
||||
|
||||
Out: |
||||
state - state variable for x86 converter |
||||
|
||||
Returns: |
||||
The number of processed bytes. If you call these functions with multiple calls, |
||||
you must start next call with first byte after block of processed bytes. |
||||
|
||||
Type Endian Alignment LookAhead |
||||
|
||||
x86 little 1 4 |
||||
ARMT little 2 2 |
||||
ARM little 4 0 |
||||
PPC big 4 0 |
||||
SPARC big 4 0 |
||||
IA64 little 16 0 |
||||
|
||||
size must be >= Alignment + LookAhead, if it's not last block. |
||||
If (size < Alignment + LookAhead), converter returns 0. |
||||
|
||||
Example: |
||||
|
||||
UInt32 ip = 0; |
||||
for () |
||||
{ |
||||
; size must be >= Alignment + LookAhead, if it's not last block |
||||
SizeT processed = Convert(data, size, ip, 1); |
||||
data += processed; |
||||
size -= processed; |
||||
ip += processed; |
||||
} |
||||
*/ |
||||
|
||||
#define x86_Convert_Init(state) { state = 0; } |
||||
SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding); |
||||
SizeT ARM_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); |
||||
SizeT ARMT_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); |
||||
SizeT PPC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); |
||||
SizeT SPARC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); |
||||
SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); |
||||
|
||||
#endif |
||||
@ -0,0 +1,85 @@ |
||||
/* Bra86.c -- Converter for x86 code (BCJ)
|
||||
2008-10-04 : Igor Pavlov : Public domain */ |
||||
|
||||
#include "Bra.h" |
||||
|
||||
#define Test86MSByte(b) ((b) == 0 || (b) == 0xFF) |
||||
|
||||
const Byte kMaskToAllowedStatus[8] = {1, 1, 1, 0, 1, 0, 0, 0}; |
||||
const Byte kMaskToBitNumber[8] = {0, 1, 2, 2, 3, 3, 3, 3}; |
||||
|
||||
SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding) |
||||
{ |
||||
SizeT bufferPos = 0, prevPosT; |
||||
UInt32 prevMask = *state & 0x7; |
||||
if (size < 5) |
||||
return 0; |
||||
ip += 5; |
||||
prevPosT = (SizeT)0 - 1; |
||||
|
||||
for (;;) |
||||
{ |
||||
Byte *p = data + bufferPos; |
||||
Byte *limit = data + size - 4; |
||||
for (; p < limit; p++) |
||||
if ((*p & 0xFE) == 0xE8) |
||||
break; |
||||
bufferPos = (SizeT)(p - data); |
||||
if (p >= limit) |
||||
break; |
||||
prevPosT = bufferPos - prevPosT; |
||||
if (prevPosT > 3) |
||||
prevMask = 0; |
||||
else |
||||
{ |
||||
prevMask = (prevMask << ((int)prevPosT - 1)) & 0x7; |
||||
if (prevMask != 0) |
||||
{ |
||||
Byte b = p[4 - kMaskToBitNumber[prevMask]]; |
||||
if (!kMaskToAllowedStatus[prevMask] || Test86MSByte(b)) |
||||
{ |
||||
prevPosT = bufferPos; |
||||
prevMask = ((prevMask << 1) & 0x7) | 1; |
||||
bufferPos++; |
||||
continue; |
||||
} |
||||
} |
||||
} |
||||
prevPosT = bufferPos; |
||||
|
||||
if (Test86MSByte(p[4])) |
||||
{ |
||||
UInt32 src = ((UInt32)p[4] << 24) | ((UInt32)p[3] << 16) | ((UInt32)p[2] << 8) | ((UInt32)p[1]); |
||||
UInt32 dest; |
||||
for (;;) |
||||
{ |
||||
Byte b; |
||||
int index; |
||||
if (encoding) |
||||
dest = (ip + (UInt32)bufferPos) + src; |
||||
else |
||||
dest = src - (ip + (UInt32)bufferPos); |
||||
if (prevMask == 0) |
||||
break; |
||||
index = kMaskToBitNumber[prevMask] * 8; |
||||
b = (Byte)(dest >> (24 - index)); |
||||
if (!Test86MSByte(b)) |
||||
break; |
||||
src = dest ^ ((1 << (32 - index)) - 1); |
||||
} |
||||
p[4] = (Byte)(~(((dest >> 24) & 1) - 1)); |
||||
p[3] = (Byte)(dest >> 16); |
||||
p[2] = (Byte)(dest >> 8); |
||||
p[1] = (Byte)dest; |
||||
bufferPos += 5; |
||||
} |
||||
else |
||||
{ |
||||
prevMask = ((prevMask << 1) & 0x7) | 1; |
||||
bufferPos++; |
||||
} |
||||
} |
||||
prevPosT = bufferPos - prevPosT; |
||||
*state = ((prevPosT > 3) ? 0 : ((prevMask << ((int)prevPosT - 1)) & 0x7)); |
||||
return bufferPos; |
||||
} |
||||
@ -0,0 +1,67 @@ |
||||
/* BraIA64.c -- Converter for IA-64 code
|
||||
2008-10-04 : Igor Pavlov : Public domain */ |
||||
|
||||
#include "Bra.h" |
||||
|
||||
static const Byte kBranchTable[32] = |
||||
{ |
||||
0, 0, 0, 0, 0, 0, 0, 0, |
||||
0, 0, 0, 0, 0, 0, 0, 0, |
||||
4, 4, 6, 6, 0, 0, 7, 7, |
||||
4, 4, 0, 0, 4, 4, 0, 0 |
||||
}; |
||||
|
||||
SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) |
||||
{ |
||||
SizeT i; |
||||
if (size < 16) |
||||
return 0; |
||||
size -= 16; |
||||
for (i = 0; i <= size; i += 16) |
||||
{ |
||||
UInt32 instrTemplate = data[i] & 0x1F; |
||||
UInt32 mask = kBranchTable[instrTemplate]; |
||||
UInt32 bitPos = 5; |
||||
int slot; |
||||
for (slot = 0; slot < 3; slot++, bitPos += 41) |
||||
{ |
||||
UInt32 bytePos, bitRes; |
||||
UInt64 instruction, instNorm; |
||||
int j; |
||||
if (((mask >> slot) & 1) == 0) |
||||
continue; |
||||
bytePos = (bitPos >> 3); |
||||
bitRes = bitPos & 0x7; |
||||
instruction = 0; |
||||
for (j = 0; j < 6; j++) |
||||
instruction += (UInt64)data[i + j + bytePos] << (8 * j); |
||||
|
||||
instNorm = instruction >> bitRes; |
||||
if (((instNorm >> 37) & 0xF) == 0x5 && ((instNorm >> 9) & 0x7) == 0) |
||||
{ |
||||
UInt32 src = (UInt32)((instNorm >> 13) & 0xFFFFF); |
||||
UInt32 dest; |
||||
src |= ((UInt32)(instNorm >> 36) & 1) << 20; |
||||
|
||||
src <<= 4; |
||||
|
||||
if (encoding) |
||||
dest = ip + (UInt32)i + src; |
||||
else |
||||
dest = src - (ip + (UInt32)i); |
||||
|
||||
dest >>= 4; |
||||
|
||||
instNorm &= ~((UInt64)(0x8FFFFF) << 13); |
||||
instNorm |= ((UInt64)(dest & 0xFFFFF) << 13); |
||||
instNorm |= ((UInt64)(dest & 0x100000) << (36 - 20)); |
||||
|
||||
instruction &= (1 << bitRes) - 1; |
||||
instruction |= (instNorm << bitRes); |
||||
for (j = 0; j < 6; j++) |
||||
data[i + j + bytePos] = (Byte)(instruction >> (8 * j)); |
||||
} |
||||
} |
||||
} |
||||
return i; |
||||
} |
||||
@ -0,0 +1,69 @@ |
||||
/* CpuArch.h
|
||||
2008-08-05 |
||||
Igor Pavlov |
||||
Public domain */ |
||||
|
||||
#ifndef __CPUARCH_H |
||||
#define __CPUARCH_H |
||||
|
||||
/*
|
||||
LITTLE_ENDIAN_UNALIGN means: |
||||
1) CPU is LITTLE_ENDIAN |
||||
2) it's allowed to make unaligned memory accesses |
||||
if LITTLE_ENDIAN_UNALIGN is not defined, it means that we don't know |
||||
about these properties of platform. |
||||
*/ |
||||
|
||||
#if defined(_M_IX86) || defined(_M_X64) || defined(_M_AMD64) || defined(__i386__) || defined(__x86_64__) |
||||
#define LITTLE_ENDIAN_UNALIGN |
||||
#endif |
||||
|
||||
#ifdef LITTLE_ENDIAN_UNALIGN |
||||
|
||||
#define GetUi16(p) (*(const UInt16 *)(p)) |
||||
#define GetUi32(p) (*(const UInt32 *)(p)) |
||||
#define GetUi64(p) (*(const UInt64 *)(p)) |
||||
#define SetUi32(p, d) *(UInt32 *)(p) = (d); |
||||
|
||||
#else |
||||
|
||||
#define GetUi16(p) (((const Byte *)(p))[0] | ((UInt16)((const Byte *)(p))[1] << 8)) |
||||
|
||||
#define GetUi32(p) ( \ |
||||
((const Byte *)(p))[0] | \
|
||||
((UInt32)((const Byte *)(p))[1] << 8) | \
|
||||
((UInt32)((const Byte *)(p))[2] << 16) | \
|
||||
((UInt32)((const Byte *)(p))[3] << 24)) |
||||
|
||||
#define GetUi64(p) (GetUi32(p) | ((UInt64)GetUi32(((const Byte *)(p)) + 4) << 32)) |
||||
|
||||
#define SetUi32(p, d) { UInt32 _x_ = (d); \ |
||||
((Byte *)(p))[0] = (Byte)_x_; \
|
||||
((Byte *)(p))[1] = (Byte)(_x_ >> 8); \
|
||||
((Byte *)(p))[2] = (Byte)(_x_ >> 16); \
|
||||
((Byte *)(p))[3] = (Byte)(_x_ >> 24); } |
||||
|
||||
#endif |
||||
|
||||
#if defined(LITTLE_ENDIAN_UNALIGN) && defined(_WIN64) && (_MSC_VER >= 1300) |
||||
|
||||
#pragma intrinsic(_byteswap_ulong) |
||||
#pragma intrinsic(_byteswap_uint64) |
||||
#define GetBe32(p) _byteswap_ulong(*(const UInt32 *)(const Byte *)(p)) |
||||
#define GetBe64(p) _byteswap_uint64(*(const UInt64 *)(const Byte *)(p)) |
||||
|
||||
#else |
||||
|
||||
#define GetBe32(p) ( \ |
||||
((UInt32)((const Byte *)(p))[0] << 24) | \
|
||||
((UInt32)((const Byte *)(p))[1] << 16) | \
|
||||
((UInt32)((const Byte *)(p))[2] << 8) | \
|
||||
((const Byte *)(p))[3] ) |
||||
|
||||
#define GetBe64(p) (((UInt64)GetBe32(p) << 32) | GetBe32(((const Byte *)(p)) + 4)) |
||||
|
||||
#endif |
||||
|
||||
#define GetBe16(p) (((UInt16)((const Byte *)(p))[0] << 8) | ((const Byte *)(p))[1]) |
||||
|
||||
#endif |
||||
Loading…
Reference in new issue