- Added support for 7z archives.

SVN r1545 (trunk)
This commit is contained in:
Randy Heit 2009-04-15 03:58:10 +00:00
parent 9040710e62
commit 7e7429e3d2
27 changed files with 3155 additions and 177 deletions

View File

@ -1,4 +1,7 @@
April 13, 2009 (Changes by Graf Zahl)
April 14, 2009
- Added support for 7z archives.
April 13, 2009 (Changes by Graf Zahl)
- Added -noautoload option.
- Added default Raven automap colors set. Needs to be tested because I can't
compare against the DOS version myself.

36
lzma/C/7zBuf.c Normal file
View File

@ -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;
}

31
lzma/C/7zBuf.h Normal file
View File

@ -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

35
lzma/C/7zCrc.c Normal file
View File

@ -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;
}

24
lzma/C/7zCrc.h Normal file
View File

@ -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

169
lzma/C/7zStream.c Normal file
View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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};

View File

@ -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

1204
lzma/C/Archive/7z/7zIn.c Normal file

File diff suppressed because it is too large Load Diff

41
lzma/C/Archive/7z/7zIn.h Normal file
View File

@ -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

127
lzma/C/Archive/7z/7zItem.c Normal file
View File

@ -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);
}

View File

@ -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 CNtfsFileTime
{
UInt32 Low;
UInt32 High;
} CNtfsFileTime;
typedef struct CSzFileItem
{
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 CSzAr
{
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

132
lzma/C/Bcj2.c Normal file
View File

@ -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;
}

30
lzma/C/Bcj2.h Normal file
View File

@ -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

60
lzma/C/Bra.h Normal file
View File

@ -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

85
lzma/C/Bra86.c Normal file
View File

@ -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;
}

69
lzma/C/CpuArch.h Normal file
View File

@ -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

View File

@ -6,6 +6,10 @@
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
#define SZ_OK 0
#define SZ_ERROR_DATA 1
@ -197,4 +201,8 @@ typedef struct
#define IAlloc_Alloc(p, size) (p)->Alloc((p), size)
#define IAlloc_Free(p, a) (p)->Free((p), a)
#ifdef __cplusplus
}
#endif
#endif

View File

@ -5,7 +5,17 @@ if( CMAKE_COMPILER_IS_GNUC )
endif( CMAKE_COMPILER_IS_GNUC )
set( LZMA_FILES
C/Archive/7z/7zDecode.c
C/Archive/7z/7zExtract.c
C/Archive/7z/7zHeader.c
C/Archive/7z/7zIn.c
C/Archive/7z/7zItem.c
C/7zBuf.c
C/7zCrc.c
C/7zStream.c
C/Alloc.c
C/Bcj2.c
C/Bra86.c
C/LzFind.c
C/LzFindMt.c
C/LzmaDec.c

View File

@ -286,10 +286,30 @@
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath=".\C\7zBuf.c"
>
</File>
<File
RelativePath=".\C\7zCrc.c"
>
</File>
<File
RelativePath=".\C\7zStream.c"
>
</File>
<File
RelativePath=".\C\Alloc.c"
>
</File>
<File
RelativePath=".\C\Bcj2.c"
>
</File>
<File
RelativePath=".\C\Bra86.c"
>
</File>
<File
RelativePath=".\C\LzFind.c"
>
@ -320,6 +340,14 @@
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath=".\C\7zBuf.h"
>
</File>
<File
RelativePath=".\C\7zCrc.h"
>
</File>
<File
RelativePath=".\C\7zVersion.h"
>
@ -328,6 +356,18 @@
RelativePath=".\C\Alloc.h"
>
</File>
<File
RelativePath=".\C\Bcj2.h"
>
</File>
<File
RelativePath=".\C\Bra.h"
>
</File>
<File
RelativePath=".\C\CpuArch.h"
>
</File>
<File
RelativePath=".\C\LzFind.h"
>
@ -361,6 +401,50 @@
>
</File>
</Filter>
<Filter
Name="7z"
>
<File
RelativePath=".\C\Archive\7z\7zDecode.c"
>
</File>
<File
RelativePath=".\C\Archive\7z\7zDecode.h"
>
</File>
<File
RelativePath=".\C\Archive\7z\7zExtract.c"
>
</File>
<File
RelativePath=".\C\Archive\7z\7zExtract.h"
>
</File>
<File
RelativePath=".\C\Archive\7z\7zHeader.c"
>
</File>
<File
RelativePath=".\C\Archive\7z\7zHeader.h"
>
</File>
<File
RelativePath=".\C\Archive\7z\7zIn.c"
>
</File>
<File
RelativePath=".\C\Archive\7z\7zIn.h"
>
</File>
<File
RelativePath=".\C\Archive\7z\7zItem.c"
>
</File>
<File
RelativePath=".\C\Archive\7z\7zItem.h"
>
</File>
</Filter>
<File
RelativePath=".\CMakeLists.txt"
>

View File

@ -364,7 +364,7 @@ extern "C" void bz_internal_error (int errcode)
static void *SzAlloc(void *p, size_t size) { p = p; return malloc(size); }
static void SzFree(void *p, void *address) { p = p; free(address); }
static ISzAlloc g_Alloc = { SzAlloc, SzFree };
ISzAlloc g_Alloc = { SzAlloc, SzFree };
FileReaderLZMA::FileReaderLZMA (FileReader &file, size_t uncompressed_size, bool zip)
: File(file), SawEOF(false)

View File

@ -30,10 +30,21 @@
#include "templates.h"
#include "gi.h"
extern "C" {
#include "Archive/7z/7zHeader.h"
#include "Archive/7z/7zExtract.h"
#include "Archive/7z/7zIn.h"
#include "7zCrc.h"
}
// MACROS ------------------------------------------------------------------
#define NULL_INDEX (0xffff)
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
extern ISzAlloc g_Alloc;
// TYPES -------------------------------------------------------------------
struct rffinfo_t
@ -81,6 +92,7 @@ union MergedHeader
wadinfo_t wad;
rffinfo_t rff;
grpinfo_t grp;
BYTE sevenzip[k7zSignatureSize];
};
@ -92,32 +104,149 @@ struct FWadCollection::LumpRecord
char * fullname; // only valid for files loaded from a .zip file
char name[9];
BYTE method; // zip compression method
BYTE flags;
short wadnum;
WORD flags;
int position;
int size;
int namespc;
int compressedsize;
void ZipNameSetup(char *name);
};
struct CZDFileInStream
{
ISeekInStream s;
FileReader *File;
CZDFileInStream(FileReader *_file)
{
s.Read = Read;
s.Seek = Seek;
File = _file;
}
static SRes Read(void *pp, void *buf, size_t *size)
{
CZDFileInStream *p = (CZDFileInStream *)pp;
long numread = p->File->Read(buf, (long)*size);
if (numread < 0)
{
*size = 0;
return SZ_ERROR_READ;
}
*size = numread;
return SZ_OK;
}
static SRes Seek(void *pp, Int64 *pos, ESzSeek origin)
{
CZDFileInStream *p = (CZDFileInStream *)pp;
int move_method;
int res;
if (origin == SZ_SEEK_SET)
{
move_method = SEEK_SET;
}
else if (origin == SZ_SEEK_CUR)
{
move_method = SEEK_CUR;
}
else if (origin == SZ_SEEK_END)
{
move_method = SEEK_END;
}
else
{
return 1;
}
res = p->File->Seek((long)*pos, move_method);
*pos = p->File->Tell();
return res;
}
};
struct C7zArchive
{
CSzArEx DB;
CZDFileInStream ArchiveStream;
CLookToRead LookStream;
UInt32 BlockIndex;
Byte *OutBuffer;
size_t OutBufferSize;
C7zArchive(FileReader *file) : ArchiveStream(file)
{
if (g_CrcTable[1] == 0)
{
CrcGenerateTable();
}
file->Seek(0, SEEK_SET);
LookToRead_CreateVTable(&LookStream, false);
LookStream.realStream = &ArchiveStream.s;
LookToRead_Init(&LookStream);
SzArEx_Init(&DB);
BlockIndex = 0xFFFFFFFF;
OutBuffer = NULL;
OutBufferSize = 0;
}
~C7zArchive()
{
if (OutBuffer != NULL)
{
IAlloc_Free(&g_Alloc, OutBuffer);
}
SzArEx_Free(&DB, &g_Alloc);
}
SRes Open()
{
return SzArEx_Open(&DB, &LookStream.s, &g_Alloc, &g_Alloc);
}
SRes Extract(UInt32 file_index, char *buffer)
{
size_t offset, out_size_processed;
SRes res = SzAr_Extract(&DB, &LookStream.s, file_index,
&BlockIndex, &OutBuffer, &OutBufferSize,
&offset, &out_size_processed,
&g_Alloc, &g_Alloc);
if (res == SZ_OK)
{
memcpy(buffer, OutBuffer + offset, out_size_processed);
}
return res;
}
};
class FWadCollection::WadFileRecord : public FileReader
{
public:
WadFileRecord (FILE *file);
WadFileRecord (const char * buffer, int length);
WadFileRecord (const char *buffer, int length);
~WadFileRecord ();
long Seek (long offset, int origin);
long Read (void *buffer, long len);
const char * MemoryData;
const char *MemoryData;
C7zArchive *Archive;
char *Name;
FString Name;
DWORD FirstLump;
DWORD LastLump;
};
struct FEmbeddedWAD
{
union
{
C7zArchive *Archive;
FZipCentralDirectoryInfo *Zip;
};
int Position;
};
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
@ -129,8 +258,6 @@ void W_SysWadInit ();
static void PrintLastError ();
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
// PUBLIC DATA DEFINITIONS -------------------------------------------------
FWadCollection Wads;
@ -285,7 +412,7 @@ int FWadCollection::AddExternalFile(const char *filename)
lump.fullname = copystring(filename);
memset(lump.name, 0, sizeof(lump.name));
lump.wadnum=-1;
lump.wadnum = -1;
lump.flags = LUMPF_EXTERNAL;
lump.position = 0;
lump.namespc = ns_global;
@ -365,7 +492,7 @@ int STACK_ARGS FWadCollection::lumpcmp(const void * a, const void * b)
}
void FWadCollection::AddFile (const char *filename, const char * data, int length)
void FWadCollection::AddFile (const char *filename, const char *data, int length)
{
WadFileRecord *wadinfo;
MergedHeader header;
@ -375,10 +502,10 @@ void FWadCollection::AddFile (const char *filename, const char * data, int lengt
int startlump;
wadlump_t* fileinfo = NULL, *fileinfo2free = NULL;
wadlump_t singleinfo;
TArray<FZipCentralDirectoryInfo *> EmbeddedWADs;
void * directory = NULL;
TArray<FEmbeddedWAD> EmbeddedWADs;
void *directory = NULL;
if (length==-1)
if (length == -1)
{
// open the file and add to directory
handle = fopen (filename, "rb");
@ -409,7 +536,7 @@ void FWadCollection::AddFile (const char *filename, const char * data, int lengt
return;
}
wadinfo->Name = copystring (filename);
wadinfo->Name = filename;
if (header.magic[0] == IWAD_ID || header.magic[0] == PWAD_ID)
{ // This is a WAD file
@ -516,6 +643,7 @@ void FWadCollection::AddFile (const char *filename, const char * data, int lengt
if (centraldir == 0)
{
Printf("\n%s: ZIP file corrupt!\n", filename);
delete wadinfo;
return;
}
@ -528,6 +656,7 @@ void FWadCollection::AddFile (const char *filename, const char * data, int lengt
info.FirstDisk != 0 || info.DiskNumber != 0)
{
Printf("\n%s: Multipart Zip files are not supported.\n", filename);
delete wadinfo;
return;
}
@ -546,7 +675,6 @@ void FWadCollection::AddFile (const char *filename, const char * data, int lengt
FZipCentralDirectoryInfo *zip_fh = (FZipCentralDirectoryInfo *)dirptr;
char name[256];
char base[256];
int len = LittleShort(zip_fh->NameLength);
strncpy(name, dirptr + sizeof(FZipCentralDirectoryInfo), MIN<int>(len, 255));
@ -589,68 +717,24 @@ void FWadCollection::AddFile (const char *filename, const char * data, int lengt
// They must be extracted and added separately to the lump list.
// WADs in subdirectories are added to the lump directory.
// Embedded .zips are ignored for now. But they should be allowed later!
char * c = strstr(name, ".wad");
if (c && strlen(c)==4 && !strchr(name, '/'))
char *c = strstr(name, ".wad");
if (c && strlen(c) == 4 && !strchr(name, '/'))
{
EmbeddedWADs.Push(zip_fh);
FEmbeddedWAD embed;
embed.Zip = zip_fh;
embed.Position = -1;
EmbeddedWADs.Push(embed);
skipped++;
continue;
}
//ExtractFileBase(name, base);
char *lname = strrchr(name,'/');
if (!lname) lname = name;
else lname++;
strcpy(base, lname);
char *dot = strrchr(base, '.');
if (dot) *dot = 0;
uppercopy(lump_p->name, base);
lump_p->name[8] = 0;
lump_p->fullname = copystring(name);
lump_p->ZipNameSetup(name);
lump_p->size = LittleLong(zip_fh->UncompressedSize);
// Map some directories to WAD namespaces.
// Note that some of these namespaces don't exist in WADS.
// CheckNumForName will handle any request for these namespaces accordingly.
lump_p->namespc = !strncmp(name, "flats/", 6) ? ns_flats :
!strncmp(name, "textures/", 9) ? ns_newtextures :
!strncmp(name, "hires/", 6) ? ns_hires :
!strncmp(name, "sprites/", 8) ? ns_sprites :
!strncmp(name, "colormaps/", 10) ? ns_colormaps :
!strncmp(name, "acs/", 4) ? ns_acslibrary :
!strncmp(name, "voices/", 7) ? ns_strifevoices :
!strncmp(name, "patches/", 8) ? ns_patches :
!strncmp(name, "graphics/", 9) ? ns_graphics :
!strncmp(name, "sounds/", 7) ? ns_sounds :
!strncmp(name, "music/", 6) ? ns_music :
!strchr(name, '/') ? ns_global : -1;
// Anything that is not in one of these subdirectories or the main directory
// should not be accessible through the standard WAD functions but only through
// the ones which look for the full name.
if (lump_p->namespc == -1)
{
memset(lump_p->name, 0, 8);
}
lump_p->wadnum = (WORD)Wads.Size();
lump_p->flags = (zip_fh->Method != METHOD_STORED) ? LUMPF_COMPRESSED|LUMPF_ZIPFILE : LUMPF_ZIPFILE;
lump_p->method = zip_fh->Method;
lump_p->compressedsize = LittleLong(zip_fh->CompressedSize);
// Since '\' can't be used as a file name's part inside a ZIP
// we have to work around this for sprites because it is a valid
// frame character.
if (lump_p->namespc == ns_sprites)
{
char * c;
while ((c = (char*)memchr(lump_p->name, '^', 8)))
{
*c = '\\';
}
}
// The start of the file will be determined the first time it is accessed.
lump_p->flags |= LUMPF_NEEDFILESTART;
lump_p->position = LittleLong(zip_fh->LocalHeaderOffset);
@ -659,10 +743,91 @@ void FWadCollection::AddFile (const char *filename, const char * data, int lengt
// Resize the lump record array to its actual size
NumLumps -= skipped;
LumpInfo.Resize(NumLumps);
Printf (" (%d files)", LittleShort(info.NumEntries) - skipped);
// Entries in Zips are sorted alphabetically.
qsort(&LumpInfo[startlump], NumLumps - startlump, sizeof(LumpRecord), lumpcmp);
}
else if (memcmp(header.sevenzip, k7zSignature, k7zSignatureSize) == 0)
{
C7zArchive *arc = new C7zArchive(wadinfo);
int skipped = 0;
SRes res;
res = arc->Open();
if (res != SZ_OK)
{
delete arc;
delete wadinfo;
Printf("\n%s: ", filename);
if (res == SZ_ERROR_UNSUPPORTED)
{
Printf("Decoder does not support this archive\n");
}
else if (res == SZ_ERROR_MEM)
{
Printf("Cannot allocate memory\n");
}
else if (res == SZ_ERROR_CRC)
{
Printf("CRC error\n");
}
else
{
Printf("error #%d\n", res);
}
return;
}
wadinfo->Archive = arc;
NumLumps += arc->DB.db.NumFiles;
LumpInfo.Resize(NumLumps);
lump_p = &LumpInfo[startlump];
for (int i = 0; i < arc->DB.db.NumFiles; ++i)
{
CSzFileItem *file = &arc->DB.db.Files[i];
char name[256];
// skip Directories
if (file->IsDir)
{
skipped++;
continue;
}
strncpy(name, file->Name, countof(name)-1);
name[countof(name)-1] = 0;
FixPathSeperator(name);
strlwr(name);
// Check for embedded WADs in the root directory.
char *c = strstr(name, ".wad");
if (c && strlen(c) == 4 && !strchr(name, '/'))
{
FEmbeddedWAD embed;
embed.Archive = arc;
embed.Position = i;
EmbeddedWADs.Push(embed);
skipped++;
continue;
}
lump_p->ZipNameSetup(name);
lump_p->size = file->Size;
lump_p->wadnum = (WORD)Wads.Size();
lump_p->flags = LUMPF_7ZFILE;
lump_p->position = i;
lump_p->compressedsize = -1;
lump_p++;
}
// Resize the lump record array to its actual size
NumLumps -= skipped;
LumpInfo.Resize(NumLumps);
Printf (" (%u files)", arc->DB.db.NumFiles - skipped);
// Entries in archives are sorted alphabetically
qsort(&LumpInfo[startlump], NumLumps - startlump, sizeof(LumpRecord), lumpcmp);
}
else
{ // This is just a single lump file
fileinfo2free = NULL;
@ -678,7 +843,8 @@ void FWadCollection::AddFile (const char *filename, const char * data, int lengt
// Fill in lumpinfo
if (header.magic[0] != RFF_ID &&
header.magic[0] != ZIP_ID &&
(header.magic[0] != GRP_ID_0 || header.magic[1] != GRP_ID_1 || header.magic[2] != GRP_ID_2))
(header.magic[0] != GRP_ID_0 || header.magic[1] != GRP_ID_1 || header.magic[2] != GRP_ID_2) &&
memcmp(header.sevenzip, k7zSignature, k7zSignatureSize))
{
LumpInfo.Resize(NumLumps);
lump_p = &LumpInfo[startlump];
@ -717,54 +883,147 @@ void FWadCollection::AddFile (const char *filename, const char * data, int lengt
if (EmbeddedWADs.Size())
{
char path[256];
size_t len;
char *buffer;
mysnprintf(path, countof(path), "%s:", filename);
char * wadstr = path+strlen(path);
char *wadstr = path + strlen(path);
for(unsigned int i = 0; i < EmbeddedWADs.Size(); i++)
{
FZipCentralDirectoryInfo *zip_fh = EmbeddedWADs[i];
FZipLocalFileHeader localHeader;
FEmbeddedWAD *embed = &EmbeddedWADs[i];
*wadstr = 0;
size_t len = LittleShort(zip_fh->NameLength);
if (len + strlen(path) > 255) len = 255 - strlen(path);
strncpy(wadstr, ((char*)zip_fh) + sizeof(FZipCentralDirectoryInfo), len);
wadstr[len] = 0;
DWORD size = LittleLong(zip_fh->UncompressedSize);
char *buffer = new char[size];
int position = LittleLong(zip_fh->LocalHeaderOffset) ;
wadinfo->Seek(position, SEEK_SET);
wadinfo->Read(&localHeader, sizeof(localHeader));
position += sizeof(FZipLocalFileHeader) + LittleShort(localHeader.ExtraLength) + LittleShort(zip_fh->NameLength);
wadinfo->Seek(position, SEEK_SET);
if (LittleShort(zip_fh->Method) == METHOD_DEFLATE)
if (embed->Position == -1)
{
FileReaderZ frz(*wadinfo, true);
frz.Read(buffer, size);
}
else if (LittleShort(zip_fh->Method) == METHOD_LZMA)
{
FileReaderLZMA frz(*wadinfo, size, true);
frz.Read(buffer, size);
}
else if (LittleShort(zip_fh->Method) == METHOD_BZIP2)
{
FileReaderBZ2 frz(*wadinfo);
frz.Read(buffer, size);
FZipCentralDirectoryInfo *zip_fh = embed->Zip;
FZipLocalFileHeader localHeader;
*wadstr = 0;
len = LittleShort(zip_fh->NameLength);
if (len + strlen(path) > 255)
{
len = 255 - strlen(path);
}
strncpy(wadstr, ((char*)zip_fh) + sizeof(FZipCentralDirectoryInfo), len);
wadstr[len] = 0;
DWORD size = LittleLong(zip_fh->UncompressedSize);
buffer = new char[size];
int position = LittleLong(zip_fh->LocalHeaderOffset);
wadinfo->Seek(position, SEEK_SET);
wadinfo->Read(&localHeader, sizeof(localHeader));
position += sizeof(FZipLocalFileHeader) + LittleShort(localHeader.ExtraLength) + LittleShort(zip_fh->NameLength);
wadinfo->Seek(position, SEEK_SET);
if (LittleShort(zip_fh->Method) == METHOD_DEFLATE)
{
FileReaderZ frz(*wadinfo, true);
frz.Read(buffer, size);
}
else if (LittleShort(zip_fh->Method) == METHOD_LZMA)
{
FileReaderLZMA frz(*wadinfo, size, true);
frz.Read(buffer, size);
}
else if (LittleShort(zip_fh->Method) == METHOD_BZIP2)
{
FileReaderBZ2 frz(*wadinfo);
frz.Read(buffer, size);
}
else
{
wadinfo->Read(buffer, size);
}
AddFile(path, buffer, size);
}
else
{
wadinfo->Read(buffer, size);
CSzFileItem *file = &embed->Archive->DB.db.Files[embed->Position];
len = strlen(file->Name);
if (len + strlen(path) > 255)
{
len = 255 - strlen(path);
}
strncpy(wadstr, file->Name, len);
wadstr[len] = 0;
buffer = new char[file->Size];
if (embed->Archive->Extract(embed->Position, buffer) == SZ_OK)
{
AddFile(path, buffer, file->Size);
}
}
AddFile(path, buffer, size);
}
}
if (directory != NULL) free(directory);
if (directory != NULL)
{
free(directory);
}
}
//==========================================================================
//
// FWadCollection :: LumpRecord :: ZipNameSetup
//
// For lumps from an archive, determine this lump's wad-compatible name,
// namespace, and set the fullname.
//
//==========================================================================
void FWadCollection::LumpRecord::ZipNameSetup(char *iname)
{
char base[256];
char *lname = strrchr(iname,'/');
lname = (lname == NULL) ? iname : lname + 1;
strcpy(base, lname);
char *dot = strrchr(base, '.');
if (dot != NULL)
{
*dot = 0;
}
uppercopy(name, base);
name[8] = 0;
fullname = copystring(iname);
// Map some directories to WAD namespaces.
// Note that some of these namespaces don't exist in WADS.
// CheckNumForName will handle any request for these namespaces accordingly.
namespc = !strncmp(iname, "flats/", 6) ? ns_flats :
!strncmp(iname, "textures/", 9) ? ns_newtextures :
!strncmp(iname, "hires/", 6) ? ns_hires :
!strncmp(iname, "sprites/", 8) ? ns_sprites :
!strncmp(iname, "colormaps/", 10) ? ns_colormaps :
!strncmp(iname, "acs/", 4) ? ns_acslibrary :
!strncmp(iname, "voices/", 7) ? ns_strifevoices :
!strncmp(iname, "patches/", 8) ? ns_patches :
!strncmp(iname, "graphics/", 9) ? ns_graphics :
!strncmp(iname, "sounds/", 7) ? ns_sounds :
!strncmp(iname, "music/", 6) ? ns_music :
!strchr(iname, '/') ? ns_global :
-1;
// Anything that is not in one of these subdirectories or the main directory
// should not be accessible through the standard WAD functions but only through
// the ones which look for the full name.
if (namespc == -1)
{
memset(name, 0, 8);
}
// Since '\' can't be used as a file name's part inside a ZIP
// we have to work around this for sprites because it is a valid
// frame character.
else if (namespc == ns_sprites)
{
char *c;
while ((c = (char*)memchr(name, '^', 8)))
{
*c = '\\';
}
}
}
//==========================================================================
@ -1797,39 +2056,29 @@ FWadLump FWadCollection::OpenLumpNum (int lump)
}
l = &LumpInfo[lump];
wad = l->wadnum >= 0? Wads[l->wadnum] : NULL;
wad = l->wadnum >= 0 ? Wads[l->wadnum] : NULL;
if (l->flags & LUMPF_NEEDFILESTART)
{
SetLumpAddress(l);
}
if (wad != NULL) wad->Seek (l->position, SEEK_SET);
if (l->flags & LUMPF_7ZFILE)
{
// An entry in a .7z file
char *buffer = new char[l->size + 1]; // the last byte is used as a reference counter
if (l->flags & LUMPF_COMPRESSED)
}
if (wad != NULL)
{
wad->Seek (l->position, SEEK_SET);
}
if (l->flags & (LUMPF_COMPRESSED | LUMPF_7ZFILE))
{
// A compressed entry in a .zip file
char *buffer = new char[l->size + 1]; // the last byte is used as a reference counter
buffer[l->size] = 0;
if (l->method == METHOD_DEFLATE)
{
FileReaderZ frz(*wad, true);
frz.Read(buffer, l->size);
}
else if (l->method == METHOD_LZMA)
{
FileReaderLZMA frz(*wad, l->size, true);
frz.Read(buffer, l->size);
}
else if (l->method == METHOD_BZIP2)
{
FileReaderBZ2 frz(*wad);
frz.Read(buffer, l->size);
}
else
{
assert(0); // Should not get here
}
char *buffer = ReadZipLump(l);
return FWadLump(buffer, l->size, true);
}
else if (l->flags & LUMPF_EXTERNAL)
@ -1841,7 +2090,7 @@ FWadLump FWadCollection::OpenLumpNum (int lump)
{
FString name;
name.Format("%s/%s", wad->Name, l->fullname);
name << wad->Name << '/' << l->fullname;
f = fopen(name, "rb");
}
else
@ -1898,38 +2147,18 @@ FWadLump *FWadCollection::ReopenLumpNum (int lump)
}
l = &LumpInfo[lump];
wad = l->wadnum >= 0? Wads[l->wadnum] : NULL;
wad = l->wadnum >= 0 ? Wads[l->wadnum] : NULL;
if (l->flags & LUMPF_NEEDFILESTART)
{
SetLumpAddress(l);
}
if (l->flags & LUMPF_COMPRESSED)
if (l->flags & (LUMPF_COMPRESSED | LUMPF_7ZFILE))
{
// A compressed entry in a .zip file
int address = wad->Tell(); // read from the existing WadFileRecord without reopening
char *buffer = new char[l->size + 1]; // the last byte is used as a reference counter
wad->Seek(l->position, SEEK_SET);
if (l->method == METHOD_DEFLATE)
{
FileReaderZ frz(*wad, true);
frz.Read(buffer, l->size);
}
else if (l->method == METHOD_LZMA)
{
FileReaderLZMA frz(*wad, l->size, true);
frz.Read(buffer, l->size);
}
else if (l->method == METHOD_BZIP2)
{
FileReaderBZ2 frz(*wad);
frz.Read(buffer, l->size);
}
else
{
assert(0); // Should not get here
}
char *buffer = ReadZipLump(l);
wad->Seek(address, SEEK_SET);
return new FWadLump(buffer, l->size, true); //... but restore the file pointer afterward!
}
@ -1942,7 +2171,7 @@ FWadLump *FWadCollection::ReopenLumpNum (int lump)
{
FString name;
name.Format("%s/%s", wad->Name, l->fullname);
name << wad->Name << '/' << l->fullname;
f = fopen(name, "rb");
}
else
@ -1977,7 +2206,7 @@ FWadLump *FWadCollection::ReopenLumpNum (int lump)
f = fopen (wad->Name, "rb");
if (f == NULL)
{
I_Error ("Could not reopen %s\n", wad->Name);
I_Error ("Could not reopen %s\n", wad->Name.GetChars());
}
fseek (f, l->position, SEEK_SET);
@ -1986,6 +2215,50 @@ FWadLump *FWadCollection::ReopenLumpNum (int lump)
}
//==========================================================================
//
// FWadCollection :: ReadZipLump
//
// Extracts a compressed file from a zip into memory.
//
//==========================================================================
char *FWadCollection::ReadZipLump(LumpRecord *l)
{
WadFileRecord *wad = Wads[l->wadnum];
char *buffer = new char[l->size + 1]; // the last byte is used as a reference counter
buffer[l->size] = 0;
if (!(l->flags & LUMPF_7ZFILE))
{
wad->Seek(l->position, SEEK_SET);
if (l->method == METHOD_DEFLATE)
{
FileReaderZ frz(*wad, true);
frz.Read(buffer, l->size);
}
else if (l->method == METHOD_LZMA)
{
FileReaderLZMA frz(*wad, l->size, true);
frz.Read(buffer, l->size);
}
else if (l->method == METHOD_BZIP2)
{
FileReaderBZ2 frz(*wad);
frz.Read(buffer, l->size);
}
else
{
assert(0); // Should not get here
}
}
else
{
wad->Archive->Extract(l->position, buffer);
}
return buffer;
}
//==========================================================================
//
// GetFileReader
@ -2142,7 +2415,7 @@ void FWadCollection::SkinHack (int baselump)
"The maps in %s will not be loaded because it has a skin.\n"
TEXTCOLOR_BLUE
"You should remove the skin from the wad to play these maps.\n",
Wads[LumpInfo[baselump].wadnum]->Name);
Wads[LumpInfo[baselump].wadnum]->Name.GetChars());
}
}
@ -2165,13 +2438,12 @@ void BloodCrypt (void *data, int key, int len)
// WadFileRecord ------------------------------------------------------------
FWadCollection::WadFileRecord::WadFileRecord (FILE *file)
: FileReader(file), Name(NULL), FirstLump(0), LastLump(0)
: FileReader(file), MemoryData(NULL), Archive(NULL), FirstLump(0), LastLump(0)
{
MemoryData=NULL;
}
FWadCollection::WadFileRecord::WadFileRecord (const char * mem, int len)
: FileReader(), MemoryData(mem), Name(NULL), FirstLump(0), LastLump(0)
FWadCollection::WadFileRecord::WadFileRecord (const char *mem, int len)
: FileReader(), MemoryData(mem), Archive(NULL), FirstLump(0), LastLump(0)
{
Length = len;
FilePos = StartPos = 0;
@ -2179,55 +2451,62 @@ FWadCollection::WadFileRecord::WadFileRecord (const char * mem, int len)
FWadCollection::WadFileRecord::~WadFileRecord ()
{
if (Name != NULL)
{
delete[] Name;
}
if (MemoryData != NULL)
{
delete [] MemoryData;
delete[] MemoryData;
}
if (Archive != NULL)
{
delete Archive;
}
}
long FWadCollection::WadFileRecord::Seek (long offset, int origin)
{
if (MemoryData==NULL) return FileReader::Seek(offset, origin);
if (MemoryData == NULL)
{
return FileReader::Seek(offset, origin);
}
else
{
switch (origin)
{
case SEEK_CUR:
offset+=FilePos;
offset += FilePos;
break;
case SEEK_END:
offset+=Length;
offset += Length;
break;
default:
break;
}
if (offset<0) offset=0;
else if (offset>Length) offset=Length;
FilePos=offset;
FilePos = clamp<long>(offset, 0, Length);
return 0;
}
}
long FWadCollection::WadFileRecord::Read (void *buffer, long len)
{
if (MemoryData==NULL) return FileReader::Read(buffer, len);
if (MemoryData == NULL)
{
return FileReader::Read(buffer, len);
}
else
{
if (FilePos+len>Length) len=Length-FilePos;
memcpy(buffer, MemoryData+FilePos, len);
FilePos+=len;
if (FilePos + len > Length)
{
len = Length - FilePos;
}
memcpy(buffer, MemoryData + FilePos, len);
FilePos += len;
return len;
}
}
// FWadLump -----------------------------------------------------------------
// FWadLump -----------------------------------------------------------------
FWadLump::FWadLump ()
: FileReader(), SourceData(NULL), DestroySource(false), Encrypted(false)
{

View File

@ -69,6 +69,7 @@ enum
LUMPF_ZIPFILE = 4, // Inside a Zip file - used to enforce use of special directories insize Zips
LUMPF_NEEDFILESTART = 8, // Still need to process local file header to find file start inside a zip
LUMPF_EXTERNAL = 16, // Lump is from an external file that won't be kept open permanently
LUMPF_7ZFILE = 32, // Inside a 7z archive; position is its index in the archive
};
@ -168,7 +169,7 @@ public:
enum { IWAD_FILENUM = 1 };
void InitMultipleFiles (wadlist_t **filenames);
void AddFile (const char *filename, const char * data=NULL,int length=-1);
void AddFile (const char *filename, const char *data=NULL, int length=-1);
int CheckIfWadLoaded (const char *name);
const char *GetWadName (int wadnum) const;
@ -235,7 +236,7 @@ protected:
TArray<LumpRecord> LumpInfo;
TArray<WadFileRecord *>Wads;
TArray<WadFileRecord *> Wads;
DWORD NumLumps; // Not necessarily the same as LumpInfo.Size()
DWORD NumWads;
@ -247,6 +248,8 @@ protected:
bool IsMarker (const LumpRecord *lump, const char *marker) const;
void FindStrifeTeaserVoices ();
char *ReadZipLump(LumpRecord *l);
private:
static int STACK_ARGS lumpcmp(const void * a, const void * b);
void ScanForFlatHack (int startlump);