ALL: Apply standard SVN properties to recently added files. Motly to avoid file with mixed line ending.
This commit is contained in:
parent
4795fde374
commit
ce952db2ec
406
fex/7z_C/7z.h
406
fex/7z_C/7z.h
|
@ -1,203 +1,203 @@
|
|||
/* 7z.h -- 7z interface
|
||||
2010-03-11 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __7Z_H
|
||||
#define __7Z_H
|
||||
|
||||
#include "7zBuf.h"
|
||||
|
||||
EXTERN_C_BEGIN
|
||||
|
||||
#define k7zStartHeaderSize 0x20
|
||||
#define k7zSignatureSize 6
|
||||
extern Byte k7zSignature[k7zSignatureSize];
|
||||
#define k7zMajorVersion 0
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
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;
|
||||
} CSzBindPair;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CSzCoderInfo *Coders;
|
||||
CSzBindPair *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);
|
||||
|
||||
SRes SzFolder_Decode(const CSzFolder *folder, const UInt64 *packSizes,
|
||||
ILookInStream *stream, UInt64 startPos,
|
||||
Byte *outBuffer, size_t outSize, ISzAlloc *allocMain);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UInt32 Low;
|
||||
UInt32 High;
|
||||
} CNtfsFileTime;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CNtfsFileTime MTime;
|
||||
UInt64 Size;
|
||||
UInt32 Crc;
|
||||
UInt32 Attrib;
|
||||
Byte HasStream;
|
||||
Byte IsDir;
|
||||
Byte IsAnti;
|
||||
Byte CrcDefined;
|
||||
Byte MTimeDefined;
|
||||
Byte AttribDefined;
|
||||
} 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);
|
||||
|
||||
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CSzAr db;
|
||||
|
||||
UInt64 startPosAfterHeader;
|
||||
UInt64 dataPos;
|
||||
|
||||
UInt32 *FolderStartPackStreamIndex;
|
||||
UInt64 *PackStreamStartPositions;
|
||||
UInt32 *FolderStartFileIndex;
|
||||
UInt32 *FileIndexToFolderIndexMap;
|
||||
|
||||
size_t *FileNameOffsets; /* in 2-byte steps */
|
||||
CBuf FileNames; /* UTF-16-LE */
|
||||
} 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);
|
||||
|
||||
/*
|
||||
if dest == NULL, the return value specifies the required size of the buffer,
|
||||
in 16-bit characters, including the null-terminating character.
|
||||
if dest != NULL, the return value specifies the number of 16-bit characters that
|
||||
are written to the dest, including the null-terminating character. */
|
||||
|
||||
size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest);
|
||||
|
||||
SRes SzArEx_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);
|
||||
|
||||
|
||||
/*
|
||||
SzArEx_Open 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);
|
||||
|
||||
EXTERN_C_END
|
||||
|
||||
#endif
|
||||
/* 7z.h -- 7z interface
|
||||
2010-03-11 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __7Z_H
|
||||
#define __7Z_H
|
||||
|
||||
#include "7zBuf.h"
|
||||
|
||||
EXTERN_C_BEGIN
|
||||
|
||||
#define k7zStartHeaderSize 0x20
|
||||
#define k7zSignatureSize 6
|
||||
extern Byte k7zSignature[k7zSignatureSize];
|
||||
#define k7zMajorVersion 0
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
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;
|
||||
} CSzBindPair;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CSzCoderInfo *Coders;
|
||||
CSzBindPair *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);
|
||||
|
||||
SRes SzFolder_Decode(const CSzFolder *folder, const UInt64 *packSizes,
|
||||
ILookInStream *stream, UInt64 startPos,
|
||||
Byte *outBuffer, size_t outSize, ISzAlloc *allocMain);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UInt32 Low;
|
||||
UInt32 High;
|
||||
} CNtfsFileTime;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CNtfsFileTime MTime;
|
||||
UInt64 Size;
|
||||
UInt32 Crc;
|
||||
UInt32 Attrib;
|
||||
Byte HasStream;
|
||||
Byte IsDir;
|
||||
Byte IsAnti;
|
||||
Byte CrcDefined;
|
||||
Byte MTimeDefined;
|
||||
Byte AttribDefined;
|
||||
} 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);
|
||||
|
||||
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CSzAr db;
|
||||
|
||||
UInt64 startPosAfterHeader;
|
||||
UInt64 dataPos;
|
||||
|
||||
UInt32 *FolderStartPackStreamIndex;
|
||||
UInt64 *PackStreamStartPositions;
|
||||
UInt32 *FolderStartFileIndex;
|
||||
UInt32 *FileIndexToFolderIndexMap;
|
||||
|
||||
size_t *FileNameOffsets; /* in 2-byte steps */
|
||||
CBuf FileNames; /* UTF-16-LE */
|
||||
} 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);
|
||||
|
||||
/*
|
||||
if dest == NULL, the return value specifies the required size of the buffer,
|
||||
in 16-bit characters, including the null-terminating character.
|
||||
if dest != NULL, the return value specifies the number of 16-bit characters that
|
||||
are written to the dest, including the null-terminating character. */
|
||||
|
||||
size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest);
|
||||
|
||||
SRes SzArEx_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);
|
||||
|
||||
|
||||
/*
|
||||
SzArEx_Open 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);
|
||||
|
||||
EXTERN_C_END
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,76 +1,76 @@
|
|||
/* 7zAlloc.c -- Allocation functions
|
||||
2010-10-29 : Igor Pavlov : Public domain */
|
||||
|
||||
#include "7zAlloc.h"
|
||||
|
||||
/* #define _SZ_ALLOC_DEBUG */
|
||||
/* use _SZ_ALLOC_DEBUG to debug alloc/free operations */
|
||||
|
||||
#ifdef _SZ_ALLOC_DEBUG
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
int g_allocCount = 0;
|
||||
int g_allocCountTemp = 0;
|
||||
|
||||
#endif
|
||||
|
||||
void *SzAlloc(void *p, size_t size)
|
||||
{
|
||||
p = p;
|
||||
if (size == 0)
|
||||
return 0;
|
||||
#ifdef _SZ_ALLOC_DEBUG
|
||||
fprintf(stderr, "\nAlloc %10d bytes; count = %10d", size, g_allocCount);
|
||||
g_allocCount++;
|
||||
#endif
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void SzFree(void *p, void *address)
|
||||
{
|
||||
p = p;
|
||||
#ifdef _SZ_ALLOC_DEBUG
|
||||
if (address != 0)
|
||||
{
|
||||
g_allocCount--;
|
||||
fprintf(stderr, "\nFree; count = %10d", g_allocCount);
|
||||
}
|
||||
#endif
|
||||
free(address);
|
||||
}
|
||||
|
||||
void *SzAllocTemp(void *p, size_t size)
|
||||
{
|
||||
p = p;
|
||||
if (size == 0)
|
||||
return 0;
|
||||
#ifdef _SZ_ALLOC_DEBUG
|
||||
fprintf(stderr, "\nAlloc_temp %10d bytes; count = %10d", size, g_allocCountTemp);
|
||||
g_allocCountTemp++;
|
||||
#ifdef _WIN32
|
||||
return HeapAlloc(GetProcessHeap(), 0, size);
|
||||
#endif
|
||||
#endif
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void SzFreeTemp(void *p, void *address)
|
||||
{
|
||||
p = p;
|
||||
#ifdef _SZ_ALLOC_DEBUG
|
||||
if (address != 0)
|
||||
{
|
||||
g_allocCountTemp--;
|
||||
fprintf(stderr, "\nFree_temp; count = %10d", g_allocCountTemp);
|
||||
}
|
||||
#ifdef _WIN32
|
||||
HeapFree(GetProcessHeap(), 0, address);
|
||||
return;
|
||||
#endif
|
||||
#endif
|
||||
free(address);
|
||||
}
|
||||
/* 7zAlloc.c -- Allocation functions
|
||||
2010-10-29 : Igor Pavlov : Public domain */
|
||||
|
||||
#include "7zAlloc.h"
|
||||
|
||||
/* #define _SZ_ALLOC_DEBUG */
|
||||
/* use _SZ_ALLOC_DEBUG to debug alloc/free operations */
|
||||
|
||||
#ifdef _SZ_ALLOC_DEBUG
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
int g_allocCount = 0;
|
||||
int g_allocCountTemp = 0;
|
||||
|
||||
#endif
|
||||
|
||||
void *SzAlloc(void *p, size_t size)
|
||||
{
|
||||
p = p;
|
||||
if (size == 0)
|
||||
return 0;
|
||||
#ifdef _SZ_ALLOC_DEBUG
|
||||
fprintf(stderr, "\nAlloc %10d bytes; count = %10d", size, g_allocCount);
|
||||
g_allocCount++;
|
||||
#endif
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void SzFree(void *p, void *address)
|
||||
{
|
||||
p = p;
|
||||
#ifdef _SZ_ALLOC_DEBUG
|
||||
if (address != 0)
|
||||
{
|
||||
g_allocCount--;
|
||||
fprintf(stderr, "\nFree; count = %10d", g_allocCount);
|
||||
}
|
||||
#endif
|
||||
free(address);
|
||||
}
|
||||
|
||||
void *SzAllocTemp(void *p, size_t size)
|
||||
{
|
||||
p = p;
|
||||
if (size == 0)
|
||||
return 0;
|
||||
#ifdef _SZ_ALLOC_DEBUG
|
||||
fprintf(stderr, "\nAlloc_temp %10d bytes; count = %10d", size, g_allocCountTemp);
|
||||
g_allocCountTemp++;
|
||||
#ifdef _WIN32
|
||||
return HeapAlloc(GetProcessHeap(), 0, size);
|
||||
#endif
|
||||
#endif
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void SzFreeTemp(void *p, void *address)
|
||||
{
|
||||
p = p;
|
||||
#ifdef _SZ_ALLOC_DEBUG
|
||||
if (address != 0)
|
||||
{
|
||||
g_allocCountTemp--;
|
||||
fprintf(stderr, "\nFree_temp; count = %10d", g_allocCountTemp);
|
||||
}
|
||||
#ifdef _WIN32
|
||||
HeapFree(GetProcessHeap(), 0, address);
|
||||
return;
|
||||
#endif
|
||||
#endif
|
||||
free(address);
|
||||
}
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
/* 7zAlloc.h -- Allocation functions
|
||||
2010-10-29 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __7Z_ALLOC_H
|
||||
#define __7Z_ALLOC_H
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
void *SzAlloc(void *p, size_t size);
|
||||
void SzFree(void *p, void *address);
|
||||
|
||||
void *SzAllocTemp(void *p, size_t size);
|
||||
void SzFreeTemp(void *p, void *address);
|
||||
|
||||
#endif
|
||||
/* 7zAlloc.h -- Allocation functions
|
||||
2010-10-29 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __7Z_ALLOC_H
|
||||
#define __7Z_ALLOC_H
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
void *SzAlloc(void *p, size_t size);
|
||||
void SzFree(void *p, void *address);
|
||||
|
||||
void *SzAllocTemp(void *p, size_t size);
|
||||
void SzFreeTemp(void *p, void *address);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,36 +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;
|
||||
}
|
||||
/* 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;
|
||||
}
|
||||
|
|
|
@ -1,39 +1,39 @@
|
|||
/* 7zBuf.h -- Byte Buffer
|
||||
2009-02-07 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __7Z_BUF_H
|
||||
#define __7Z_BUF_H
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/* 7zBuf.h -- Byte Buffer
|
||||
2009-02-07 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __7Z_BUF_H
|
||||
#define __7Z_BUF_H
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
388
fex/7z_C/7zC.txt
388
fex/7z_C/7zC.txt
|
@ -1,194 +1,194 @@
|
|||
7z ANSI-C Decoder 4.62
|
||||
----------------------
|
||||
|
||||
7z ANSI-C provides 7z/LZMA decoding.
|
||||
7z ANSI-C version is simplified version ported from C++ code.
|
||||
|
||||
LZMA is default and general compression method of 7z format
|
||||
in 7-Zip compression program (www.7-zip.org). LZMA provides high
|
||||
compression ratio and very fast decompression.
|
||||
|
||||
|
||||
LICENSE
|
||||
-------
|
||||
|
||||
7z ANSI-C Decoder is part of the LZMA SDK.
|
||||
LZMA SDK is written and placed in the public domain by Igor Pavlov.
|
||||
|
||||
Files
|
||||
---------------------
|
||||
|
||||
7zDecode.* - Low level 7z decoding
|
||||
7zExtract.* - High level 7z decoding
|
||||
7zHeader.* - .7z format constants
|
||||
7zIn.* - .7z archive opening
|
||||
7zItem.* - .7z structures
|
||||
7zMain.c - Test application
|
||||
|
||||
|
||||
How To Use
|
||||
----------
|
||||
|
||||
You must download 7-Zip program from www.7-zip.org.
|
||||
|
||||
You can create .7z archive with 7z.exe or 7za.exe:
|
||||
|
||||
7za.exe a archive.7z *.htm -r -mx -m0fb=255
|
||||
|
||||
If you have big number of files in archive, and you need fast extracting,
|
||||
you can use partly-solid archives:
|
||||
|
||||
7za.exe a archive.7z *.htm -ms=512K -r -mx -m0fb=255 -m0d=512K
|
||||
|
||||
In that example 7-Zip will use 512KB solid blocks. So it needs to decompress only
|
||||
512KB for extracting one file from such archive.
|
||||
|
||||
|
||||
Limitations of current version of 7z ANSI-C Decoder
|
||||
---------------------------------------------------
|
||||
|
||||
- It reads only "FileName", "Size", "LastWriteTime" and "CRC" information for each file in archive.
|
||||
- It supports only LZMA and Copy (no compression) methods with BCJ or BCJ2 filters.
|
||||
- It converts original UTF-16 Unicode file names to UTF-8 Unicode file names.
|
||||
|
||||
These limitations will be fixed in future versions.
|
||||
|
||||
|
||||
Using 7z ANSI-C Decoder Test application:
|
||||
-----------------------------------------
|
||||
|
||||
Usage: 7zDec <command> <archive_name>
|
||||
|
||||
<Command>:
|
||||
e: Extract files from archive
|
||||
l: List contents of archive
|
||||
t: Test integrity of archive
|
||||
|
||||
Example:
|
||||
|
||||
7zDec l archive.7z
|
||||
|
||||
lists contents of archive.7z
|
||||
|
||||
7zDec e archive.7z
|
||||
|
||||
extracts files from archive.7z to current folder.
|
||||
|
||||
|
||||
How to use .7z Decoder
|
||||
----------------------
|
||||
|
||||
Memory allocation
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
7z Decoder uses two memory pools:
|
||||
1) Temporary pool
|
||||
2) Main pool
|
||||
Such scheme can allow you to avoid fragmentation of allocated blocks.
|
||||
|
||||
|
||||
Steps for using 7z decoder
|
||||
--------------------------
|
||||
|
||||
Use code at 7zMain.c as example.
|
||||
|
||||
1) Declare variables:
|
||||
inStream /* implements ILookInStream interface */
|
||||
CSzArEx db; /* 7z archive database structure */
|
||||
ISzAlloc allocImp; /* memory functions for main pool */
|
||||
ISzAlloc allocTempImp; /* memory functions for temporary pool */
|
||||
|
||||
2) call CrcGenerateTable(); function to initialize CRC structures.
|
||||
|
||||
3) call SzArEx_Init(&db); function to initialize db structures.
|
||||
|
||||
4) call SzArEx_Open(&db, inStream, &allocMain, &allocTemp) to open archive
|
||||
|
||||
This function opens archive "inStream" and reads headers to "db".
|
||||
All items in "db" will be allocated with "allocMain" functions.
|
||||
SzArEx_Open function allocates and frees temporary structures by "allocTemp" functions.
|
||||
|
||||
5) List items or Extract items
|
||||
|
||||
Listing code:
|
||||
~~~~~~~~~~~~~
|
||||
{
|
||||
UInt32 i;
|
||||
for (i = 0; i < db.db.NumFiles; i++)
|
||||
{
|
||||
CFileItem *f = db.db.Files + i;
|
||||
printf("%10d %s\n", (int)f->Size, f->Name);
|
||||
}
|
||||
}
|
||||
|
||||
Extracting code:
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
SZ_RESULT SzAr_Extract(
|
||||
CArchiveDatabaseEx *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);
|
||||
|
||||
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.
|
||||
|
||||
After decompressing you must free "outBuffer":
|
||||
allocImp.Free(outBuffer);
|
||||
|
||||
6) call SzArEx_Free(&db, allocImp.Free) to free allocated items in "db".
|
||||
|
||||
|
||||
|
||||
|
||||
Memory requirements for .7z decoding
|
||||
------------------------------------
|
||||
|
||||
Memory usage for Archive opening:
|
||||
- Temporary pool:
|
||||
- Memory for uncompressed .7z headers
|
||||
- some other temporary blocks
|
||||
- Main pool:
|
||||
- Memory for database:
|
||||
Estimated size of one file structures in solid archive:
|
||||
- Size (4 or 8 Bytes)
|
||||
- CRC32 (4 bytes)
|
||||
- LastWriteTime (8 bytes)
|
||||
- Some file information (4 bytes)
|
||||
- File Name (variable length) + pointer + allocation structures
|
||||
|
||||
Memory usage for archive Decompressing:
|
||||
- Temporary pool:
|
||||
- Memory for LZMA decompressing structures
|
||||
- Main pool:
|
||||
- Memory for decompressed solid block
|
||||
- Memory for temprorary buffers, if BCJ2 fileter is used. Usually these
|
||||
temprorary buffers can be about 15% of solid block size.
|
||||
|
||||
|
||||
7z Decoder doesn't allocate memory for compressed blocks.
|
||||
Instead of this, you must allocate buffer with desired
|
||||
size before calling 7z Decoder. Use 7zMain.c as example.
|
||||
|
||||
|
||||
Defines
|
||||
-------
|
||||
|
||||
_SZ_ALLOC_DEBUG - define it if you want to debug alloc/free operations to stderr.
|
||||
|
||||
|
||||
---
|
||||
|
||||
http://www.7-zip.org
|
||||
http://www.7-zip.org/sdk.html
|
||||
http://www.7-zip.org/support.html
|
||||
7z ANSI-C Decoder 4.62
|
||||
----------------------
|
||||
|
||||
7z ANSI-C provides 7z/LZMA decoding.
|
||||
7z ANSI-C version is simplified version ported from C++ code.
|
||||
|
||||
LZMA is default and general compression method of 7z format
|
||||
in 7-Zip compression program (www.7-zip.org). LZMA provides high
|
||||
compression ratio and very fast decompression.
|
||||
|
||||
|
||||
LICENSE
|
||||
-------
|
||||
|
||||
7z ANSI-C Decoder is part of the LZMA SDK.
|
||||
LZMA SDK is written and placed in the public domain by Igor Pavlov.
|
||||
|
||||
Files
|
||||
---------------------
|
||||
|
||||
7zDecode.* - Low level 7z decoding
|
||||
7zExtract.* - High level 7z decoding
|
||||
7zHeader.* - .7z format constants
|
||||
7zIn.* - .7z archive opening
|
||||
7zItem.* - .7z structures
|
||||
7zMain.c - Test application
|
||||
|
||||
|
||||
How To Use
|
||||
----------
|
||||
|
||||
You must download 7-Zip program from www.7-zip.org.
|
||||
|
||||
You can create .7z archive with 7z.exe or 7za.exe:
|
||||
|
||||
7za.exe a archive.7z *.htm -r -mx -m0fb=255
|
||||
|
||||
If you have big number of files in archive, and you need fast extracting,
|
||||
you can use partly-solid archives:
|
||||
|
||||
7za.exe a archive.7z *.htm -ms=512K -r -mx -m0fb=255 -m0d=512K
|
||||
|
||||
In that example 7-Zip will use 512KB solid blocks. So it needs to decompress only
|
||||
512KB for extracting one file from such archive.
|
||||
|
||||
|
||||
Limitations of current version of 7z ANSI-C Decoder
|
||||
---------------------------------------------------
|
||||
|
||||
- It reads only "FileName", "Size", "LastWriteTime" and "CRC" information for each file in archive.
|
||||
- It supports only LZMA and Copy (no compression) methods with BCJ or BCJ2 filters.
|
||||
- It converts original UTF-16 Unicode file names to UTF-8 Unicode file names.
|
||||
|
||||
These limitations will be fixed in future versions.
|
||||
|
||||
|
||||
Using 7z ANSI-C Decoder Test application:
|
||||
-----------------------------------------
|
||||
|
||||
Usage: 7zDec <command> <archive_name>
|
||||
|
||||
<Command>:
|
||||
e: Extract files from archive
|
||||
l: List contents of archive
|
||||
t: Test integrity of archive
|
||||
|
||||
Example:
|
||||
|
||||
7zDec l archive.7z
|
||||
|
||||
lists contents of archive.7z
|
||||
|
||||
7zDec e archive.7z
|
||||
|
||||
extracts files from archive.7z to current folder.
|
||||
|
||||
|
||||
How to use .7z Decoder
|
||||
----------------------
|
||||
|
||||
Memory allocation
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
7z Decoder uses two memory pools:
|
||||
1) Temporary pool
|
||||
2) Main pool
|
||||
Such scheme can allow you to avoid fragmentation of allocated blocks.
|
||||
|
||||
|
||||
Steps for using 7z decoder
|
||||
--------------------------
|
||||
|
||||
Use code at 7zMain.c as example.
|
||||
|
||||
1) Declare variables:
|
||||
inStream /* implements ILookInStream interface */
|
||||
CSzArEx db; /* 7z archive database structure */
|
||||
ISzAlloc allocImp; /* memory functions for main pool */
|
||||
ISzAlloc allocTempImp; /* memory functions for temporary pool */
|
||||
|
||||
2) call CrcGenerateTable(); function to initialize CRC structures.
|
||||
|
||||
3) call SzArEx_Init(&db); function to initialize db structures.
|
||||
|
||||
4) call SzArEx_Open(&db, inStream, &allocMain, &allocTemp) to open archive
|
||||
|
||||
This function opens archive "inStream" and reads headers to "db".
|
||||
All items in "db" will be allocated with "allocMain" functions.
|
||||
SzArEx_Open function allocates and frees temporary structures by "allocTemp" functions.
|
||||
|
||||
5) List items or Extract items
|
||||
|
||||
Listing code:
|
||||
~~~~~~~~~~~~~
|
||||
{
|
||||
UInt32 i;
|
||||
for (i = 0; i < db.db.NumFiles; i++)
|
||||
{
|
||||
CFileItem *f = db.db.Files + i;
|
||||
printf("%10d %s\n", (int)f->Size, f->Name);
|
||||
}
|
||||
}
|
||||
|
||||
Extracting code:
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
SZ_RESULT SzAr_Extract(
|
||||
CArchiveDatabaseEx *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);
|
||||
|
||||
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.
|
||||
|
||||
After decompressing you must free "outBuffer":
|
||||
allocImp.Free(outBuffer);
|
||||
|
||||
6) call SzArEx_Free(&db, allocImp.Free) to free allocated items in "db".
|
||||
|
||||
|
||||
|
||||
|
||||
Memory requirements for .7z decoding
|
||||
------------------------------------
|
||||
|
||||
Memory usage for Archive opening:
|
||||
- Temporary pool:
|
||||
- Memory for uncompressed .7z headers
|
||||
- some other temporary blocks
|
||||
- Main pool:
|
||||
- Memory for database:
|
||||
Estimated size of one file structures in solid archive:
|
||||
- Size (4 or 8 Bytes)
|
||||
- CRC32 (4 bytes)
|
||||
- LastWriteTime (8 bytes)
|
||||
- Some file information (4 bytes)
|
||||
- File Name (variable length) + pointer + allocation structures
|
||||
|
||||
Memory usage for archive Decompressing:
|
||||
- Temporary pool:
|
||||
- Memory for LZMA decompressing structures
|
||||
- Main pool:
|
||||
- Memory for decompressed solid block
|
||||
- Memory for temprorary buffers, if BCJ2 fileter is used. Usually these
|
||||
temprorary buffers can be about 15% of solid block size.
|
||||
|
||||
|
||||
7z Decoder doesn't allocate memory for compressed blocks.
|
||||
Instead of this, you must allocate buffer with desired
|
||||
size before calling 7z Decoder. Use 7zMain.c as example.
|
||||
|
||||
|
||||
Defines
|
||||
-------
|
||||
|
||||
_SZ_ALLOC_DEBUG - define it if you want to debug alloc/free operations to stderr.
|
||||
|
||||
|
||||
---
|
||||
|
||||
http://www.7-zip.org
|
||||
http://www.7-zip.org/sdk.html
|
||||
http://www.7-zip.org/support.html
|
||||
|
|
148
fex/7z_C/7zCrc.c
148
fex/7z_C/7zCrc.c
|
@ -1,74 +1,74 @@
|
|||
/* 7zCrc.c -- CRC32 calculation
|
||||
2009-11-23 : Igor Pavlov : Public domain */
|
||||
|
||||
#include "7zCrc.h"
|
||||
#include "CpuArch.h"
|
||||
|
||||
#define kCrcPoly 0xEDB88320
|
||||
|
||||
#ifdef MY_CPU_LE
|
||||
#define CRC_NUM_TABLES 8
|
||||
#else
|
||||
#define CRC_NUM_TABLES 1
|
||||
#endif
|
||||
|
||||
typedef UInt32 (MY_FAST_CALL *CRC_FUNC)(UInt32 v, const void *data, size_t size, const UInt32 *table);
|
||||
|
||||
static CRC_FUNC g_CrcUpdate;
|
||||
UInt32 g_CrcTable[256 * CRC_NUM_TABLES];
|
||||
|
||||
#if CRC_NUM_TABLES == 1
|
||||
|
||||
#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
|
||||
|
||||
static UInt32 MY_FAST_CALL CrcUpdateT1(UInt32 v, const void *data, size_t size, const UInt32 *table)
|
||||
{
|
||||
const Byte *p = (const Byte *)data;
|
||||
for (; size > 0; size--, p++)
|
||||
v = CRC_UPDATE_BYTE_2(v, *p);
|
||||
return v;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table);
|
||||
UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table);
|
||||
|
||||
#endif
|
||||
|
||||
UInt32 MY_FAST_CALL CrcUpdate(UInt32 v, const void *data, size_t size)
|
||||
{
|
||||
return g_CrcUpdate(v, data, size, g_CrcTable);
|
||||
}
|
||||
|
||||
UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size)
|
||||
{
|
||||
return g_CrcUpdate(CRC_INIT_VAL, data, size, g_CrcTable) ^ CRC_INIT_VAL;
|
||||
}
|
||||
|
||||
void MY_FAST_CALL CrcGenerateTable()
|
||||
{
|
||||
UInt32 i;
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
UInt32 r = i;
|
||||
unsigned j;
|
||||
for (j = 0; j < 8; j++)
|
||||
r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1));
|
||||
g_CrcTable[i] = r;
|
||||
}
|
||||
#if CRC_NUM_TABLES == 1
|
||||
g_CrcUpdate = CrcUpdateT1;
|
||||
#else
|
||||
for (; i < 256 * CRC_NUM_TABLES; i++)
|
||||
{
|
||||
UInt32 r = g_CrcTable[i - 256];
|
||||
g_CrcTable[i] = g_CrcTable[r & 0xFF] ^ (r >> 8);
|
||||
}
|
||||
g_CrcUpdate = CrcUpdateT4;
|
||||
#ifdef MY_CPU_X86_OR_AMD64
|
||||
if (!CPU_Is_InOrder())
|
||||
g_CrcUpdate = CrcUpdateT8;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
/* 7zCrc.c -- CRC32 calculation
|
||||
2009-11-23 : Igor Pavlov : Public domain */
|
||||
|
||||
#include "7zCrc.h"
|
||||
#include "CpuArch.h"
|
||||
|
||||
#define kCrcPoly 0xEDB88320
|
||||
|
||||
#ifdef MY_CPU_LE
|
||||
#define CRC_NUM_TABLES 8
|
||||
#else
|
||||
#define CRC_NUM_TABLES 1
|
||||
#endif
|
||||
|
||||
typedef UInt32 (MY_FAST_CALL *CRC_FUNC)(UInt32 v, const void *data, size_t size, const UInt32 *table);
|
||||
|
||||
static CRC_FUNC g_CrcUpdate;
|
||||
UInt32 g_CrcTable[256 * CRC_NUM_TABLES];
|
||||
|
||||
#if CRC_NUM_TABLES == 1
|
||||
|
||||
#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
|
||||
|
||||
static UInt32 MY_FAST_CALL CrcUpdateT1(UInt32 v, const void *data, size_t size, const UInt32 *table)
|
||||
{
|
||||
const Byte *p = (const Byte *)data;
|
||||
for (; size > 0; size--, p++)
|
||||
v = CRC_UPDATE_BYTE_2(v, *p);
|
||||
return v;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table);
|
||||
UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table);
|
||||
|
||||
#endif
|
||||
|
||||
UInt32 MY_FAST_CALL CrcUpdate(UInt32 v, const void *data, size_t size)
|
||||
{
|
||||
return g_CrcUpdate(v, data, size, g_CrcTable);
|
||||
}
|
||||
|
||||
UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size)
|
||||
{
|
||||
return g_CrcUpdate(CRC_INIT_VAL, data, size, g_CrcTable) ^ CRC_INIT_VAL;
|
||||
}
|
||||
|
||||
void MY_FAST_CALL CrcGenerateTable()
|
||||
{
|
||||
UInt32 i;
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
UInt32 r = i;
|
||||
unsigned j;
|
||||
for (j = 0; j < 8; j++)
|
||||
r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1));
|
||||
g_CrcTable[i] = r;
|
||||
}
|
||||
#if CRC_NUM_TABLES == 1
|
||||
g_CrcUpdate = CrcUpdateT1;
|
||||
#else
|
||||
for (; i < 256 * CRC_NUM_TABLES; i++)
|
||||
{
|
||||
UInt32 r = g_CrcTable[i - 256];
|
||||
g_CrcTable[i] = g_CrcTable[r & 0xFF] ^ (r >> 8);
|
||||
}
|
||||
g_CrcUpdate = CrcUpdateT4;
|
||||
#ifdef MY_CPU_X86_OR_AMD64
|
||||
if (!CPU_Is_InOrder())
|
||||
g_CrcUpdate = CrcUpdateT8;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -1,25 +1,25 @@
|
|||
/* 7zCrc.h -- CRC32 calculation
|
||||
2009-11-21 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __7Z_CRC_H
|
||||
#define __7Z_CRC_H
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
EXTERN_C_BEGIN
|
||||
|
||||
extern UInt32 g_CrcTable[];
|
||||
|
||||
/* Call CrcGenerateTable one time before other CRC functions */
|
||||
void MY_FAST_CALL CrcGenerateTable(void);
|
||||
|
||||
#define CRC_INIT_VAL 0xFFFFFFFF
|
||||
#define CRC_GET_DIGEST(crc) ((crc) ^ CRC_INIT_VAL)
|
||||
#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);
|
||||
|
||||
EXTERN_C_END
|
||||
|
||||
#endif
|
||||
/* 7zCrc.h -- CRC32 calculation
|
||||
2009-11-21 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __7Z_CRC_H
|
||||
#define __7Z_CRC_H
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
EXTERN_C_BEGIN
|
||||
|
||||
extern UInt32 g_CrcTable[];
|
||||
|
||||
/* Call CrcGenerateTable one time before other CRC functions */
|
||||
void MY_FAST_CALL CrcGenerateTable(void);
|
||||
|
||||
#define CRC_INIT_VAL 0xFFFFFFFF
|
||||
#define CRC_GET_DIGEST(crc) ((crc) ^ CRC_INIT_VAL)
|
||||
#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);
|
||||
|
||||
EXTERN_C_END
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,34 +1,34 @@
|
|||
/* 7zCrcOpt.c -- CRC32 calculation : optimized version
|
||||
2009-11-23 : Igor Pavlov : Public domain */
|
||||
|
||||
#include "CpuArch.h"
|
||||
|
||||
#ifdef MY_CPU_LE
|
||||
|
||||
#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
|
||||
|
||||
UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table)
|
||||
{
|
||||
const Byte *p = (const Byte *)data;
|
||||
for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++)
|
||||
v = CRC_UPDATE_BYTE_2(v, *p);
|
||||
for (; size >= 4; size -= 4, p += 4)
|
||||
{
|
||||
v ^= *(const UInt32 *)p;
|
||||
v =
|
||||
table[0x300 + (v & 0xFF)] ^
|
||||
table[0x200 + ((v >> 8) & 0xFF)] ^
|
||||
table[0x100 + ((v >> 16) & 0xFF)] ^
|
||||
table[0x000 + ((v >> 24))];
|
||||
}
|
||||
for (; size > 0; size--, p++)
|
||||
v = CRC_UPDATE_BYTE_2(v, *p);
|
||||
return v;
|
||||
}
|
||||
|
||||
UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table)
|
||||
{
|
||||
return CrcUpdateT4(v, data, size, table);
|
||||
}
|
||||
|
||||
#endif
|
||||
/* 7zCrcOpt.c -- CRC32 calculation : optimized version
|
||||
2009-11-23 : Igor Pavlov : Public domain */
|
||||
|
||||
#include "CpuArch.h"
|
||||
|
||||
#ifdef MY_CPU_LE
|
||||
|
||||
#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
|
||||
|
||||
UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table)
|
||||
{
|
||||
const Byte *p = (const Byte *)data;
|
||||
for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++)
|
||||
v = CRC_UPDATE_BYTE_2(v, *p);
|
||||
for (; size >= 4; size -= 4, p += 4)
|
||||
{
|
||||
v ^= *(const UInt32 *)p;
|
||||
v =
|
||||
table[0x300 + (v & 0xFF)] ^
|
||||
table[0x200 + ((v >> 8) & 0xFF)] ^
|
||||
table[0x100 + ((v >> 16) & 0xFF)] ^
|
||||
table[0x000 + ((v >> 24))];
|
||||
}
|
||||
for (; size > 0; size--, p++)
|
||||
v = CRC_UPDATE_BYTE_2(v, *p);
|
||||
return v;
|
||||
}
|
||||
|
||||
UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table)
|
||||
{
|
||||
return CrcUpdateT4(v, data, size, table);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,470 +1,470 @@
|
|||
/* 7zDec.c -- Decoding from 7z folder
|
||||
2010-11-02 : Igor Pavlov : Public domain */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/* #define _7ZIP_PPMD_SUPPPORT */
|
||||
|
||||
#include "7z.h"
|
||||
|
||||
#include "Bcj2.h"
|
||||
#include "Bra.h"
|
||||
#include "CpuArch.h"
|
||||
#include "LzmaDec.h"
|
||||
#include "Lzma2Dec.h"
|
||||
#ifdef _7ZIP_PPMD_SUPPPORT
|
||||
#include "Ppmd7.h"
|
||||
#endif
|
||||
|
||||
#define k_Copy 0
|
||||
#define k_LZMA2 0x21
|
||||
#define k_LZMA 0x30101
|
||||
#define k_BCJ 0x03030103
|
||||
#define k_PPC 0x03030205
|
||||
#define k_ARM 0x03030501
|
||||
#define k_ARMT 0x03030701
|
||||
#define k_SPARC 0x03030805
|
||||
#define k_BCJ2 0x0303011B
|
||||
|
||||
#ifdef _7ZIP_PPMD_SUPPPORT
|
||||
|
||||
#define k_PPMD 0x30401
|
||||
|
||||
typedef struct
|
||||
{
|
||||
IByteIn p;
|
||||
const Byte *cur;
|
||||
const Byte *end;
|
||||
const Byte *begin;
|
||||
UInt64 processed;
|
||||
Bool extra;
|
||||
SRes res;
|
||||
ILookInStream *inStream;
|
||||
} CByteInToLook;
|
||||
|
||||
static Byte ReadByte(void *pp)
|
||||
{
|
||||
CByteInToLook *p = (CByteInToLook *)pp;
|
||||
if (p->cur != p->end)
|
||||
return *p->cur++;
|
||||
if (p->res == SZ_OK)
|
||||
{
|
||||
size_t size = p->cur - p->begin;
|
||||
p->processed += size;
|
||||
p->res = p->inStream->Skip(p->inStream, size);
|
||||
size = (1 << 25);
|
||||
p->res = p->inStream->Look(p->inStream, (const void **)&p->begin, &size);
|
||||
p->cur = p->begin;
|
||||
p->end = p->begin + size;
|
||||
if (size != 0)
|
||||
return *p->cur++;;
|
||||
}
|
||||
p->extra = True;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SRes SzDecodePpmd(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inStream,
|
||||
Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain)
|
||||
{
|
||||
CPpmd7 ppmd;
|
||||
CByteInToLook s;
|
||||
SRes res = SZ_OK;
|
||||
|
||||
s.p.Read = ReadByte;
|
||||
s.inStream = inStream;
|
||||
s.begin = s.end = s.cur = NULL;
|
||||
s.extra = False;
|
||||
s.res = SZ_OK;
|
||||
s.processed = 0;
|
||||
|
||||
if (coder->Props.size != 5)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
|
||||
{
|
||||
unsigned order = coder->Props.data[0];
|
||||
UInt32 memSize = GetUi32(coder->Props.data + 1);
|
||||
if (order < PPMD7_MIN_ORDER ||
|
||||
order > PPMD7_MAX_ORDER ||
|
||||
memSize < PPMD7_MIN_MEM_SIZE ||
|
||||
memSize > PPMD7_MAX_MEM_SIZE)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
Ppmd7_Construct(&ppmd);
|
||||
if (!Ppmd7_Alloc(&ppmd, memSize, allocMain))
|
||||
return SZ_ERROR_MEM;
|
||||
Ppmd7_Init(&ppmd, order);
|
||||
}
|
||||
{
|
||||
CPpmd7z_RangeDec rc;
|
||||
Ppmd7z_RangeDec_CreateVTable(&rc);
|
||||
rc.Stream = &s.p;
|
||||
if (!Ppmd7z_RangeDec_Init(&rc))
|
||||
res = SZ_ERROR_DATA;
|
||||
else if (s.extra)
|
||||
res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA);
|
||||
else
|
||||
{
|
||||
SizeT i;
|
||||
for (i = 0; i < outSize; i++)
|
||||
{
|
||||
int sym = Ppmd7_DecodeSymbol(&ppmd, &rc.p);
|
||||
if (s.extra || sym < 0)
|
||||
break;
|
||||
outBuffer[i] = (Byte)sym;
|
||||
}
|
||||
if (i != outSize)
|
||||
res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA);
|
||||
else if (s.processed + (s.cur - s.begin) != inSize || !Ppmd7z_RangeDec_IsFinishedOK(&rc))
|
||||
res = SZ_ERROR_DATA;
|
||||
}
|
||||
}
|
||||
Ppmd7_Free(&ppmd, allocMain);
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
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, (const 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 SzDecodeLzma2(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inStream,
|
||||
Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain)
|
||||
{
|
||||
CLzma2Dec state;
|
||||
SRes res = SZ_OK;
|
||||
|
||||
Lzma2Dec_Construct(&state);
|
||||
if (coder->Props.size != 1)
|
||||
return SZ_ERROR_DATA;
|
||||
RINOK(Lzma2Dec_AllocateProbs(&state, coder->Props.data[0], allocMain));
|
||||
state.decoder.dic = outBuffer;
|
||||
state.decoder.dicBufSize = outSize;
|
||||
Lzma2Dec_Init(&state);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
Byte *inBuf = NULL;
|
||||
size_t lookahead = (1 << 18);
|
||||
if (lookahead > inSize)
|
||||
lookahead = (size_t)inSize;
|
||||
res = inStream->Look((void *)inStream, (const void **)&inBuf, &lookahead);
|
||||
if (res != SZ_OK)
|
||||
break;
|
||||
|
||||
{
|
||||
SizeT inProcessed = (SizeT)lookahead, dicPos = state.decoder.dicPos;
|
||||
ELzmaStatus status;
|
||||
res = Lzma2Dec_DecodeToDic(&state, outSize, inBuf, &inProcessed, LZMA_FINISH_END, &status);
|
||||
lookahead -= inProcessed;
|
||||
inSize -= inProcessed;
|
||||
if (res != SZ_OK)
|
||||
break;
|
||||
if (state.decoder.dicPos == state.decoder.dicBufSize || (inProcessed == 0 && dicPos == state.decoder.dicPos))
|
||||
{
|
||||
if (state.decoder.dicBufSize != outSize || lookahead != 0 ||
|
||||
(status != LZMA_STATUS_FINISHED_WITH_MARK))
|
||||
res = SZ_ERROR_DATA;
|
||||
break;
|
||||
}
|
||||
res = inStream->Skip((void *)inStream, inProcessed);
|
||||
if (res != SZ_OK)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Lzma2Dec_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, (const 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;
|
||||
}
|
||||
|
||||
static Bool IS_MAIN_METHOD(UInt32 m)
|
||||
{
|
||||
switch(m)
|
||||
{
|
||||
case k_Copy:
|
||||
case k_LZMA:
|
||||
case k_LZMA2:
|
||||
#ifdef _7ZIP_PPMD_SUPPPORT
|
||||
case k_PPMD:
|
||||
#endif
|
||||
return True;
|
||||
}
|
||||
return False;
|
||||
}
|
||||
|
||||
static Bool IS_SUPPORTED_CODER(const CSzCoderInfo *c)
|
||||
{
|
||||
return
|
||||
c->NumInStreams == 1 &&
|
||||
c->NumOutStreams == 1 &&
|
||||
c->MethodID <= (UInt32)0xFFFFFFFF &&
|
||||
IS_MAIN_METHOD((UInt32)c->MethodID);
|
||||
}
|
||||
|
||||
#define IS_BCJ2(c) ((c)->MethodID == k_BCJ2 && (c)->NumInStreams == 4 && (c)->NumOutStreams == 1)
|
||||
|
||||
static SRes CheckSupportedFolder(const CSzFolder *f)
|
||||
{
|
||||
if (f->NumCoders < 1 || f->NumCoders > 4)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
if (!IS_SUPPORTED_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)
|
||||
{
|
||||
CSzCoderInfo *c = &f->Coders[1];
|
||||
if (c->MethodID > (UInt32)0xFFFFFFFF ||
|
||||
c->NumInStreams != 1 ||
|
||||
c->NumOutStreams != 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;
|
||||
switch ((UInt32)c->MethodID)
|
||||
{
|
||||
case k_BCJ:
|
||||
case k_ARM:
|
||||
break;
|
||||
default:
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
}
|
||||
return SZ_OK;
|
||||
}
|
||||
if (f->NumCoders == 4)
|
||||
{
|
||||
if (!IS_SUPPORTED_CODER(&f->Coders[1]) ||
|
||||
!IS_SUPPORTED_CODER(&f->Coders[2]) ||
|
||||
!IS_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;
|
||||
}
|
||||
|
||||
static UInt64 GetSum(const UInt64 *values, UInt32 index)
|
||||
{
|
||||
UInt64 sum = 0;
|
||||
UInt32 i;
|
||||
for (i = 0; i < index; i++)
|
||||
sum += values[i];
|
||||
return sum;
|
||||
}
|
||||
|
||||
#define CASE_BRA_CONV(isa) case k_ ## isa: isa ## _Convert(outBuffer, outSize, 0, 0); break;
|
||||
|
||||
static SRes SzFolder_Decode2(const CSzFolder *folder, const UInt64 *packSizes,
|
||||
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 (IS_MAIN_METHOD((UInt32)coder->MethodID))
|
||||
{
|
||||
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 if (coder->MethodID == k_LZMA)
|
||||
{
|
||||
RINOK(SzDecodeLzma(coder, inSize, inStream, outBufCur, outSizeCur, allocMain));
|
||||
}
|
||||
else if (coder->MethodID == k_LZMA2)
|
||||
{
|
||||
RINOK(SzDecodeLzma2(coder, inSize, inStream, outBufCur, outSizeCur, allocMain));
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef _7ZIP_PPMD_SUPPPORT
|
||||
RINOK(SzDecodePpmd(coder, inSize, inStream, outBufCur, outSizeCur, allocMain));
|
||||
#else
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
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
|
||||
{
|
||||
if (ci != 1)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
switch(coder->MethodID)
|
||||
{
|
||||
case k_BCJ:
|
||||
{
|
||||
UInt32 state;
|
||||
x86_Convert_Init(state);
|
||||
x86_Convert(outBuffer, outSize, 0, &state, 0);
|
||||
break;
|
||||
}
|
||||
CASE_BRA_CONV(ARM)
|
||||
default:
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
}
|
||||
}
|
||||
}
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
SRes SzFolder_Decode(const CSzFolder *folder, const UInt64 *packSizes,
|
||||
ILookInStream *inStream, UInt64 startPos,
|
||||
Byte *outBuffer, size_t outSize, ISzAlloc *allocMain)
|
||||
{
|
||||
Byte *tempBuf[3] = { 0, 0, 0};
|
||||
int i;
|
||||
SRes res = SzFolder_Decode2(folder, packSizes, inStream, startPos,
|
||||
outBuffer, (SizeT)outSize, allocMain, tempBuf);
|
||||
for (i = 0; i < 3; i++)
|
||||
IAlloc_Free(allocMain, tempBuf[i]);
|
||||
return res;
|
||||
}
|
||||
/* 7zDec.c -- Decoding from 7z folder
|
||||
2010-11-02 : Igor Pavlov : Public domain */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/* #define _7ZIP_PPMD_SUPPPORT */
|
||||
|
||||
#include "7z.h"
|
||||
|
||||
#include "Bcj2.h"
|
||||
#include "Bra.h"
|
||||
#include "CpuArch.h"
|
||||
#include "LzmaDec.h"
|
||||
#include "Lzma2Dec.h"
|
||||
#ifdef _7ZIP_PPMD_SUPPPORT
|
||||
#include "Ppmd7.h"
|
||||
#endif
|
||||
|
||||
#define k_Copy 0
|
||||
#define k_LZMA2 0x21
|
||||
#define k_LZMA 0x30101
|
||||
#define k_BCJ 0x03030103
|
||||
#define k_PPC 0x03030205
|
||||
#define k_ARM 0x03030501
|
||||
#define k_ARMT 0x03030701
|
||||
#define k_SPARC 0x03030805
|
||||
#define k_BCJ2 0x0303011B
|
||||
|
||||
#ifdef _7ZIP_PPMD_SUPPPORT
|
||||
|
||||
#define k_PPMD 0x30401
|
||||
|
||||
typedef struct
|
||||
{
|
||||
IByteIn p;
|
||||
const Byte *cur;
|
||||
const Byte *end;
|
||||
const Byte *begin;
|
||||
UInt64 processed;
|
||||
Bool extra;
|
||||
SRes res;
|
||||
ILookInStream *inStream;
|
||||
} CByteInToLook;
|
||||
|
||||
static Byte ReadByte(void *pp)
|
||||
{
|
||||
CByteInToLook *p = (CByteInToLook *)pp;
|
||||
if (p->cur != p->end)
|
||||
return *p->cur++;
|
||||
if (p->res == SZ_OK)
|
||||
{
|
||||
size_t size = p->cur - p->begin;
|
||||
p->processed += size;
|
||||
p->res = p->inStream->Skip(p->inStream, size);
|
||||
size = (1 << 25);
|
||||
p->res = p->inStream->Look(p->inStream, (const void **)&p->begin, &size);
|
||||
p->cur = p->begin;
|
||||
p->end = p->begin + size;
|
||||
if (size != 0)
|
||||
return *p->cur++;;
|
||||
}
|
||||
p->extra = True;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SRes SzDecodePpmd(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inStream,
|
||||
Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain)
|
||||
{
|
||||
CPpmd7 ppmd;
|
||||
CByteInToLook s;
|
||||
SRes res = SZ_OK;
|
||||
|
||||
s.p.Read = ReadByte;
|
||||
s.inStream = inStream;
|
||||
s.begin = s.end = s.cur = NULL;
|
||||
s.extra = False;
|
||||
s.res = SZ_OK;
|
||||
s.processed = 0;
|
||||
|
||||
if (coder->Props.size != 5)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
|
||||
{
|
||||
unsigned order = coder->Props.data[0];
|
||||
UInt32 memSize = GetUi32(coder->Props.data + 1);
|
||||
if (order < PPMD7_MIN_ORDER ||
|
||||
order > PPMD7_MAX_ORDER ||
|
||||
memSize < PPMD7_MIN_MEM_SIZE ||
|
||||
memSize > PPMD7_MAX_MEM_SIZE)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
Ppmd7_Construct(&ppmd);
|
||||
if (!Ppmd7_Alloc(&ppmd, memSize, allocMain))
|
||||
return SZ_ERROR_MEM;
|
||||
Ppmd7_Init(&ppmd, order);
|
||||
}
|
||||
{
|
||||
CPpmd7z_RangeDec rc;
|
||||
Ppmd7z_RangeDec_CreateVTable(&rc);
|
||||
rc.Stream = &s.p;
|
||||
if (!Ppmd7z_RangeDec_Init(&rc))
|
||||
res = SZ_ERROR_DATA;
|
||||
else if (s.extra)
|
||||
res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA);
|
||||
else
|
||||
{
|
||||
SizeT i;
|
||||
for (i = 0; i < outSize; i++)
|
||||
{
|
||||
int sym = Ppmd7_DecodeSymbol(&ppmd, &rc.p);
|
||||
if (s.extra || sym < 0)
|
||||
break;
|
||||
outBuffer[i] = (Byte)sym;
|
||||
}
|
||||
if (i != outSize)
|
||||
res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA);
|
||||
else if (s.processed + (s.cur - s.begin) != inSize || !Ppmd7z_RangeDec_IsFinishedOK(&rc))
|
||||
res = SZ_ERROR_DATA;
|
||||
}
|
||||
}
|
||||
Ppmd7_Free(&ppmd, allocMain);
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
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, (const 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 SzDecodeLzma2(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inStream,
|
||||
Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain)
|
||||
{
|
||||
CLzma2Dec state;
|
||||
SRes res = SZ_OK;
|
||||
|
||||
Lzma2Dec_Construct(&state);
|
||||
if (coder->Props.size != 1)
|
||||
return SZ_ERROR_DATA;
|
||||
RINOK(Lzma2Dec_AllocateProbs(&state, coder->Props.data[0], allocMain));
|
||||
state.decoder.dic = outBuffer;
|
||||
state.decoder.dicBufSize = outSize;
|
||||
Lzma2Dec_Init(&state);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
Byte *inBuf = NULL;
|
||||
size_t lookahead = (1 << 18);
|
||||
if (lookahead > inSize)
|
||||
lookahead = (size_t)inSize;
|
||||
res = inStream->Look((void *)inStream, (const void **)&inBuf, &lookahead);
|
||||
if (res != SZ_OK)
|
||||
break;
|
||||
|
||||
{
|
||||
SizeT inProcessed = (SizeT)lookahead, dicPos = state.decoder.dicPos;
|
||||
ELzmaStatus status;
|
||||
res = Lzma2Dec_DecodeToDic(&state, outSize, inBuf, &inProcessed, LZMA_FINISH_END, &status);
|
||||
lookahead -= inProcessed;
|
||||
inSize -= inProcessed;
|
||||
if (res != SZ_OK)
|
||||
break;
|
||||
if (state.decoder.dicPos == state.decoder.dicBufSize || (inProcessed == 0 && dicPos == state.decoder.dicPos))
|
||||
{
|
||||
if (state.decoder.dicBufSize != outSize || lookahead != 0 ||
|
||||
(status != LZMA_STATUS_FINISHED_WITH_MARK))
|
||||
res = SZ_ERROR_DATA;
|
||||
break;
|
||||
}
|
||||
res = inStream->Skip((void *)inStream, inProcessed);
|
||||
if (res != SZ_OK)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Lzma2Dec_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, (const 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;
|
||||
}
|
||||
|
||||
static Bool IS_MAIN_METHOD(UInt32 m)
|
||||
{
|
||||
switch(m)
|
||||
{
|
||||
case k_Copy:
|
||||
case k_LZMA:
|
||||
case k_LZMA2:
|
||||
#ifdef _7ZIP_PPMD_SUPPPORT
|
||||
case k_PPMD:
|
||||
#endif
|
||||
return True;
|
||||
}
|
||||
return False;
|
||||
}
|
||||
|
||||
static Bool IS_SUPPORTED_CODER(const CSzCoderInfo *c)
|
||||
{
|
||||
return
|
||||
c->NumInStreams == 1 &&
|
||||
c->NumOutStreams == 1 &&
|
||||
c->MethodID <= (UInt32)0xFFFFFFFF &&
|
||||
IS_MAIN_METHOD((UInt32)c->MethodID);
|
||||
}
|
||||
|
||||
#define IS_BCJ2(c) ((c)->MethodID == k_BCJ2 && (c)->NumInStreams == 4 && (c)->NumOutStreams == 1)
|
||||
|
||||
static SRes CheckSupportedFolder(const CSzFolder *f)
|
||||
{
|
||||
if (f->NumCoders < 1 || f->NumCoders > 4)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
if (!IS_SUPPORTED_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)
|
||||
{
|
||||
CSzCoderInfo *c = &f->Coders[1];
|
||||
if (c->MethodID > (UInt32)0xFFFFFFFF ||
|
||||
c->NumInStreams != 1 ||
|
||||
c->NumOutStreams != 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;
|
||||
switch ((UInt32)c->MethodID)
|
||||
{
|
||||
case k_BCJ:
|
||||
case k_ARM:
|
||||
break;
|
||||
default:
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
}
|
||||
return SZ_OK;
|
||||
}
|
||||
if (f->NumCoders == 4)
|
||||
{
|
||||
if (!IS_SUPPORTED_CODER(&f->Coders[1]) ||
|
||||
!IS_SUPPORTED_CODER(&f->Coders[2]) ||
|
||||
!IS_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;
|
||||
}
|
||||
|
||||
static UInt64 GetSum(const UInt64 *values, UInt32 index)
|
||||
{
|
||||
UInt64 sum = 0;
|
||||
UInt32 i;
|
||||
for (i = 0; i < index; i++)
|
||||
sum += values[i];
|
||||
return sum;
|
||||
}
|
||||
|
||||
#define CASE_BRA_CONV(isa) case k_ ## isa: isa ## _Convert(outBuffer, outSize, 0, 0); break;
|
||||
|
||||
static SRes SzFolder_Decode2(const CSzFolder *folder, const UInt64 *packSizes,
|
||||
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 (IS_MAIN_METHOD((UInt32)coder->MethodID))
|
||||
{
|
||||
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 if (coder->MethodID == k_LZMA)
|
||||
{
|
||||
RINOK(SzDecodeLzma(coder, inSize, inStream, outBufCur, outSizeCur, allocMain));
|
||||
}
|
||||
else if (coder->MethodID == k_LZMA2)
|
||||
{
|
||||
RINOK(SzDecodeLzma2(coder, inSize, inStream, outBufCur, outSizeCur, allocMain));
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef _7ZIP_PPMD_SUPPPORT
|
||||
RINOK(SzDecodePpmd(coder, inSize, inStream, outBufCur, outSizeCur, allocMain));
|
||||
#else
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
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
|
||||
{
|
||||
if (ci != 1)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
switch(coder->MethodID)
|
||||
{
|
||||
case k_BCJ:
|
||||
{
|
||||
UInt32 state;
|
||||
x86_Convert_Init(state);
|
||||
x86_Convert(outBuffer, outSize, 0, &state, 0);
|
||||
break;
|
||||
}
|
||||
CASE_BRA_CONV(ARM)
|
||||
default:
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
}
|
||||
}
|
||||
}
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
SRes SzFolder_Decode(const CSzFolder *folder, const UInt64 *packSizes,
|
||||
ILookInStream *inStream, UInt64 startPos,
|
||||
Byte *outBuffer, size_t outSize, ISzAlloc *allocMain)
|
||||
{
|
||||
Byte *tempBuf[3] = { 0, 0, 0};
|
||||
int i;
|
||||
SRes res = SzFolder_Decode2(folder, packSizes, inStream, startPos,
|
||||
outBuffer, (SizeT)outSize, allocMain, tempBuf);
|
||||
for (i = 0; i < 3; i++)
|
||||
IAlloc_Free(allocMain, tempBuf[i]);
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -1,13 +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
|
||||
/* 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
|
||||
|
|
|
@ -1,93 +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;
|
||||
}
|
||||
/* 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;
|
||||
}
|
||||
|
|
|
@ -1,49 +1,49 @@
|
|||
/* 7zExtract.h -- Extracting from 7z archive
|
||||
2008-11-23 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __7Z_EXTRACT_H
|
||||
#define __7Z_EXTRACT_H
|
||||
|
||||
#include "7zIn.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/* 7zExtract.h -- Extracting from 7z archive
|
||||
2008-11-23 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __7Z_EXTRACT_H
|
||||
#define __7Z_EXTRACT_H
|
||||
|
||||
#include "7zIn.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,6 +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};
|
||||
/* 7zHeader.c -- 7z Headers
|
||||
2008-10-04 : Igor Pavlov : Public domain */
|
||||
|
||||
#include "7zHeader.h"
|
||||
|
||||
Byte k7zSignature[k7zSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C};
|
||||
|
|
|
@ -1,57 +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
|
||||
/* 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
|
||||
|
|
2804
fex/7z_C/7zIn.c
2804
fex/7z_C/7zIn.c
File diff suppressed because it is too large
Load Diff
|
@ -1,49 +1,49 @@
|
|||
/* 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"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/* 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"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,129 +1,129 @@
|
|||
/* 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;
|
||||
}
|
||||
|
||||
static
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
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);
|
||||
}
|
||||
/* 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;
|
||||
}
|
||||
|
||||
static
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -1,83 +1,83 @@
|
|||
/* 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);
|
||||
|
||||
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
|
||||
/* 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);
|
||||
|
||||
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
|
||||
|
|
|
@ -1,169 +1,169 @@
|
|||
/* 7zStream.c -- 7z Stream functions
|
||||
2010-03-11 : 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)
|
||||
{
|
||||
const 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, const 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, const 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;
|
||||
}
|
||||
/* 7zStream.c -- 7z Stream functions
|
||||
2010-03-11 : 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)
|
||||
{
|
||||
const 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, const 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, const 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;
|
||||
}
|
||||
|
|
264
fex/7z_C/Bcj2.c
264
fex/7z_C/Bcj2.c
|
@ -1,132 +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;
|
||||
}
|
||||
/* 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;
|
||||
}
|
||||
|
|
|
@ -1,38 +1,38 @@
|
|||
/* Bcj2.h -- Converter for x86 code (BCJ2)
|
||||
2009-02-07 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __BCJ2_H
|
||||
#define __BCJ2_H
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/* Bcj2.h -- Converter for x86 code (BCJ2)
|
||||
2009-02-07 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __BCJ2_H
|
||||
#define __BCJ2_H
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
266
fex/7z_C/Bra.c
266
fex/7z_C/Bra.c
|
@ -1,133 +1,133 @@
|
|||
/* Bra.c -- Converters for RISC code
|
||||
2010-04-16 : 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;
|
||||
}
|
||||
/* Bra.c -- Converters for RISC code
|
||||
2010-04-16 : 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;
|
||||
}
|
||||
|
|
136
fex/7z_C/Bra.h
136
fex/7z_C/Bra.h
|
@ -1,68 +1,68 @@
|
|||
/* Bra.h -- Branch converters for executables
|
||||
2009-02-07 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __BRA_H
|
||||
#define __BRA_H
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/* Bra.h -- Branch converters for executables
|
||||
2009-02-07 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __BRA_H
|
||||
#define __BRA_H
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
170
fex/7z_C/Bra86.c
170
fex/7z_C/Bra86.c
|
@ -1,85 +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;
|
||||
}
|
||||
/* 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;
|
||||
}
|
||||
|
|
|
@ -1,173 +1,173 @@
|
|||
/* CpuArch.c -- CPU specific code
|
||||
2010-10-26: Igor Pavlov : Public domain */
|
||||
|
||||
#include "CpuArch.h"
|
||||
|
||||
#ifdef MY_CPU_X86_OR_AMD64
|
||||
|
||||
#if (defined(_MSC_VER) && !defined(MY_CPU_AMD64)) || defined(__GNUC__)
|
||||
#define USE_ASM
|
||||
#endif
|
||||
|
||||
#if defined(USE_ASM) && !defined(MY_CPU_AMD64)
|
||||
static UInt32 CheckFlag(UInt32 flag)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
__asm pushfd;
|
||||
__asm pop EAX;
|
||||
__asm mov EDX, EAX;
|
||||
__asm xor EAX, flag;
|
||||
__asm push EAX;
|
||||
__asm popfd;
|
||||
__asm pushfd;
|
||||
__asm pop EAX;
|
||||
__asm xor EAX, EDX;
|
||||
__asm push EDX;
|
||||
__asm popfd;
|
||||
__asm and flag, EAX;
|
||||
#else
|
||||
__asm__ __volatile__ (
|
||||
"pushf\n\t"
|
||||
"pop %%EAX\n\t"
|
||||
"movl %%EAX,%%EDX\n\t"
|
||||
"xorl %0,%%EAX\n\t"
|
||||
"push %%EAX\n\t"
|
||||
"popf\n\t"
|
||||
"pushf\n\t"
|
||||
"pop %%EAX\n\t"
|
||||
"xorl %%EDX,%%EAX\n\t"
|
||||
"push %%EDX\n\t"
|
||||
"popf\n\t"
|
||||
"andl %%EAX, %0\n\t":
|
||||
"=c" (flag) : "c" (flag));
|
||||
#endif
|
||||
return flag;
|
||||
}
|
||||
#define CHECK_CPUID_IS_SUPPORTED if (CheckFlag(1 << 18) == 0 || CheckFlag(1 << 21) == 0) return False;
|
||||
#else
|
||||
#define CHECK_CPUID_IS_SUPPORTED
|
||||
#endif
|
||||
|
||||
static void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d)
|
||||
{
|
||||
#ifdef USE_ASM
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
UInt32 a2, b2, c2, d2;
|
||||
__asm xor EBX, EBX;
|
||||
__asm xor ECX, ECX;
|
||||
__asm xor EDX, EDX;
|
||||
__asm mov EAX, function;
|
||||
__asm cpuid;
|
||||
__asm mov a2, EAX;
|
||||
__asm mov b2, EBX;
|
||||
__asm mov c2, ECX;
|
||||
__asm mov d2, EDX;
|
||||
|
||||
*a = a2;
|
||||
*b = b2;
|
||||
*c = c2;
|
||||
*d = d2;
|
||||
|
||||
#else
|
||||
|
||||
// Mac cross-compile compiler:
|
||||
// can't find register in class 'BREG' while reloading 'asm'
|
||||
// so use class 'r' and register var binding
|
||||
register _b asm("%bx");
|
||||
__asm__ __volatile__ (
|
||||
"cpuid"
|
||||
: "=a" (*a) ,
|
||||
"=r" (_b) ,
|
||||
"=c" (*c) ,
|
||||
"=d" (*d)
|
||||
: "0" (function)) ;
|
||||
*b = _b;
|
||||
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
int CPUInfo[4];
|
||||
__cpuid(CPUInfo, function);
|
||||
*a = CPUInfo[0];
|
||||
*b = CPUInfo[1];
|
||||
*c = CPUInfo[2];
|
||||
*d = CPUInfo[3];
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
Bool x86cpuid_CheckAndRead(Cx86cpuid *p)
|
||||
{
|
||||
CHECK_CPUID_IS_SUPPORTED
|
||||
MyCPUID(0, &p->maxFunc, &p->vendor[0], &p->vendor[2], &p->vendor[1]);
|
||||
MyCPUID(1, &p->ver, &p->b, &p->c, &p->d);
|
||||
return True;
|
||||
}
|
||||
|
||||
static UInt32 kVendors[][3] =
|
||||
{
|
||||
{ 0x756E6547, 0x49656E69, 0x6C65746E},
|
||||
{ 0x68747541, 0x69746E65, 0x444D4163},
|
||||
{ 0x746E6543, 0x48727561, 0x736C7561}
|
||||
};
|
||||
|
||||
int x86cpuid_GetFirm(const Cx86cpuid *p)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < sizeof(kVendors) / sizeof(kVendors[i]); i++)
|
||||
{
|
||||
const UInt32 *v = kVendors[i];
|
||||
if (v[0] == p->vendor[0] &&
|
||||
v[1] == p->vendor[1] &&
|
||||
v[2] == p->vendor[2])
|
||||
return (int)i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
Bool CPU_Is_InOrder()
|
||||
{
|
||||
Cx86cpuid p;
|
||||
int firm;
|
||||
UInt32 family, model;
|
||||
if (!x86cpuid_CheckAndRead(&p))
|
||||
return True;
|
||||
family = x86cpuid_GetFamily(&p);
|
||||
model = x86cpuid_GetModel(&p);
|
||||
firm = x86cpuid_GetFirm(&p);
|
||||
switch (firm)
|
||||
{
|
||||
case CPU_FIRM_INTEL: return (family < 6 || (family == 6 && model == 0x100C));
|
||||
case CPU_FIRM_AMD: return (family < 5 || (family == 5 && (model < 6 || model == 0xA)));
|
||||
case CPU_FIRM_VIA: return (family < 6 || (family == 6 && model < 0xF));
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
#if !defined(MY_CPU_AMD64) && defined(_WIN32)
|
||||
static Bool CPU_Sys_Is_SSE_Supported()
|
||||
{
|
||||
OSVERSIONINFO vi;
|
||||
vi.dwOSVersionInfoSize = sizeof(vi);
|
||||
if (!GetVersionEx(&vi))
|
||||
return False;
|
||||
return (vi.dwMajorVersion >= 5);
|
||||
}
|
||||
#define CHECK_SYS_SSE_SUPPORT if (!CPU_Sys_Is_SSE_Supported()) return False;
|
||||
#else
|
||||
#define CHECK_SYS_SSE_SUPPORT
|
||||
#endif
|
||||
|
||||
Bool CPU_Is_Aes_Supported()
|
||||
{
|
||||
Cx86cpuid p;
|
||||
CHECK_SYS_SSE_SUPPORT
|
||||
if (!x86cpuid_CheckAndRead(&p))
|
||||
return False;
|
||||
return (p.c >> 25) & 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
/* CpuArch.c -- CPU specific code
|
||||
2010-10-26: Igor Pavlov : Public domain */
|
||||
|
||||
#include "CpuArch.h"
|
||||
|
||||
#ifdef MY_CPU_X86_OR_AMD64
|
||||
|
||||
#if (defined(_MSC_VER) && !defined(MY_CPU_AMD64)) || defined(__GNUC__)
|
||||
#define USE_ASM
|
||||
#endif
|
||||
|
||||
#if defined(USE_ASM) && !defined(MY_CPU_AMD64)
|
||||
static UInt32 CheckFlag(UInt32 flag)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
__asm pushfd;
|
||||
__asm pop EAX;
|
||||
__asm mov EDX, EAX;
|
||||
__asm xor EAX, flag;
|
||||
__asm push EAX;
|
||||
__asm popfd;
|
||||
__asm pushfd;
|
||||
__asm pop EAX;
|
||||
__asm xor EAX, EDX;
|
||||
__asm push EDX;
|
||||
__asm popfd;
|
||||
__asm and flag, EAX;
|
||||
#else
|
||||
__asm__ __volatile__ (
|
||||
"pushf\n\t"
|
||||
"pop %%EAX\n\t"
|
||||
"movl %%EAX,%%EDX\n\t"
|
||||
"xorl %0,%%EAX\n\t"
|
||||
"push %%EAX\n\t"
|
||||
"popf\n\t"
|
||||
"pushf\n\t"
|
||||
"pop %%EAX\n\t"
|
||||
"xorl %%EDX,%%EAX\n\t"
|
||||
"push %%EDX\n\t"
|
||||
"popf\n\t"
|
||||
"andl %%EAX, %0\n\t":
|
||||
"=c" (flag) : "c" (flag));
|
||||
#endif
|
||||
return flag;
|
||||
}
|
||||
#define CHECK_CPUID_IS_SUPPORTED if (CheckFlag(1 << 18) == 0 || CheckFlag(1 << 21) == 0) return False;
|
||||
#else
|
||||
#define CHECK_CPUID_IS_SUPPORTED
|
||||
#endif
|
||||
|
||||
static void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d)
|
||||
{
|
||||
#ifdef USE_ASM
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
UInt32 a2, b2, c2, d2;
|
||||
__asm xor EBX, EBX;
|
||||
__asm xor ECX, ECX;
|
||||
__asm xor EDX, EDX;
|
||||
__asm mov EAX, function;
|
||||
__asm cpuid;
|
||||
__asm mov a2, EAX;
|
||||
__asm mov b2, EBX;
|
||||
__asm mov c2, ECX;
|
||||
__asm mov d2, EDX;
|
||||
|
||||
*a = a2;
|
||||
*b = b2;
|
||||
*c = c2;
|
||||
*d = d2;
|
||||
|
||||
#else
|
||||
|
||||
// Mac cross-compile compiler:
|
||||
// can't find register in class 'BREG' while reloading 'asm'
|
||||
// so use class 'r' and register var binding
|
||||
register _b asm("%bx");
|
||||
__asm__ __volatile__ (
|
||||
"cpuid"
|
||||
: "=a" (*a) ,
|
||||
"=r" (_b) ,
|
||||
"=c" (*c) ,
|
||||
"=d" (*d)
|
||||
: "0" (function)) ;
|
||||
*b = _b;
|
||||
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
int CPUInfo[4];
|
||||
__cpuid(CPUInfo, function);
|
||||
*a = CPUInfo[0];
|
||||
*b = CPUInfo[1];
|
||||
*c = CPUInfo[2];
|
||||
*d = CPUInfo[3];
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
Bool x86cpuid_CheckAndRead(Cx86cpuid *p)
|
||||
{
|
||||
CHECK_CPUID_IS_SUPPORTED
|
||||
MyCPUID(0, &p->maxFunc, &p->vendor[0], &p->vendor[2], &p->vendor[1]);
|
||||
MyCPUID(1, &p->ver, &p->b, &p->c, &p->d);
|
||||
return True;
|
||||
}
|
||||
|
||||
static UInt32 kVendors[][3] =
|
||||
{
|
||||
{ 0x756E6547, 0x49656E69, 0x6C65746E},
|
||||
{ 0x68747541, 0x69746E65, 0x444D4163},
|
||||
{ 0x746E6543, 0x48727561, 0x736C7561}
|
||||
};
|
||||
|
||||
int x86cpuid_GetFirm(const Cx86cpuid *p)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < sizeof(kVendors) / sizeof(kVendors[i]); i++)
|
||||
{
|
||||
const UInt32 *v = kVendors[i];
|
||||
if (v[0] == p->vendor[0] &&
|
||||
v[1] == p->vendor[1] &&
|
||||
v[2] == p->vendor[2])
|
||||
return (int)i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
Bool CPU_Is_InOrder()
|
||||
{
|
||||
Cx86cpuid p;
|
||||
int firm;
|
||||
UInt32 family, model;
|
||||
if (!x86cpuid_CheckAndRead(&p))
|
||||
return True;
|
||||
family = x86cpuid_GetFamily(&p);
|
||||
model = x86cpuid_GetModel(&p);
|
||||
firm = x86cpuid_GetFirm(&p);
|
||||
switch (firm)
|
||||
{
|
||||
case CPU_FIRM_INTEL: return (family < 6 || (family == 6 && model == 0x100C));
|
||||
case CPU_FIRM_AMD: return (family < 5 || (family == 5 && (model < 6 || model == 0xA)));
|
||||
case CPU_FIRM_VIA: return (family < 6 || (family == 6 && model < 0xF));
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
#if !defined(MY_CPU_AMD64) && defined(_WIN32)
|
||||
static Bool CPU_Sys_Is_SSE_Supported()
|
||||
{
|
||||
OSVERSIONINFO vi;
|
||||
vi.dwOSVersionInfoSize = sizeof(vi);
|
||||
if (!GetVersionEx(&vi))
|
||||
return False;
|
||||
return (vi.dwMajorVersion >= 5);
|
||||
}
|
||||
#define CHECK_SYS_SSE_SUPPORT if (!CPU_Sys_Is_SSE_Supported()) return False;
|
||||
#else
|
||||
#define CHECK_SYS_SSE_SUPPORT
|
||||
#endif
|
||||
|
||||
Bool CPU_Is_Aes_Supported()
|
||||
{
|
||||
Cx86cpuid p;
|
||||
CHECK_SYS_SSE_SUPPORT
|
||||
if (!x86cpuid_CheckAndRead(&p))
|
||||
return False;
|
||||
return (p.c >> 25) & 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,155 +1,155 @@
|
|||
/* CpuArch.h -- CPU specific code
|
||||
2010-10-26: Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __CPU_ARCH_H
|
||||
#define __CPU_ARCH_H
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
EXTERN_C_BEGIN
|
||||
|
||||
/*
|
||||
MY_CPU_LE means that CPU is LITTLE ENDIAN.
|
||||
If MY_CPU_LE is not defined, we don't know about that property of platform (it can be LITTLE ENDIAN).
|
||||
|
||||
MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned memory accesses.
|
||||
If MY_CPU_LE_UNALIGN is not defined, we don't know about these properties of platform.
|
||||
*/
|
||||
|
||||
#if defined(_M_X64) || defined(_M_AMD64) || defined(__x86_64__)
|
||||
#define MY_CPU_AMD64
|
||||
#endif
|
||||
|
||||
#if defined(MY_CPU_AMD64) || defined(_M_IA64)
|
||||
#define MY_CPU_64BIT
|
||||
#endif
|
||||
|
||||
#if defined(_M_IX86) || defined(__i386__)
|
||||
#define MY_CPU_X86
|
||||
#endif
|
||||
|
||||
#if defined(MY_CPU_X86) || defined(MY_CPU_AMD64)
|
||||
#define MY_CPU_X86_OR_AMD64
|
||||
#endif
|
||||
|
||||
#if defined(MY_CPU_X86) || defined(_M_ARM)
|
||||
#define MY_CPU_32BIT
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) && defined(_M_ARM)
|
||||
#define MY_CPU_ARM_LE
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) && defined(_M_IA64)
|
||||
#define MY_CPU_IA64_LE
|
||||
#endif
|
||||
|
||||
#if defined(MY_CPU_X86_OR_AMD64)
|
||||
#define MY_CPU_LE_UNALIGN
|
||||
#endif
|
||||
|
||||
#if defined(MY_CPU_X86_OR_AMD64) || defined(MY_CPU_ARM_LE) || defined(MY_CPU_IA64_LE) || defined(__ARMEL__) || defined(__MIPSEL__) || defined(__LITTLE_ENDIAN__)
|
||||
#define MY_CPU_LE
|
||||
#endif
|
||||
|
||||
#if defined(__BIG_ENDIAN__)
|
||||
#define MY_CPU_BE
|
||||
#endif
|
||||
|
||||
#if defined(MY_CPU_LE) && defined(MY_CPU_BE)
|
||||
Stop_Compiling_Bad_Endian
|
||||
#endif
|
||||
|
||||
#ifdef MY_CPU_LE_UNALIGN
|
||||
|
||||
#define GetUi16(p) (*(const UInt16 *)(p))
|
||||
#define GetUi32(p) (*(const UInt32 *)(p))
|
||||
#define GetUi64(p) (*(const UInt64 *)(p))
|
||||
#define SetUi16(p, d) *(UInt16 *)(p) = (d);
|
||||
#define SetUi32(p, d) *(UInt32 *)(p) = (d);
|
||||
#define SetUi64(p, d) *(UInt64 *)(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 SetUi16(p, d) { UInt32 _x_ = (d); \
|
||||
((Byte *)(p))[0] = (Byte)_x_; \
|
||||
((Byte *)(p))[1] = (Byte)(_x_ >> 8); }
|
||||
|
||||
#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); }
|
||||
|
||||
#define SetUi64(p, d) { UInt64 _x64_ = (d); \
|
||||
SetUi32(p, (UInt32)_x64_); \
|
||||
SetUi32(((Byte *)(p)) + 4, (UInt32)(_x64_ >> 32)); }
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(MY_CPU_LE_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])
|
||||
|
||||
|
||||
#ifdef MY_CPU_X86_OR_AMD64
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UInt32 maxFunc;
|
||||
UInt32 vendor[3];
|
||||
UInt32 ver;
|
||||
UInt32 b;
|
||||
UInt32 c;
|
||||
UInt32 d;
|
||||
} Cx86cpuid;
|
||||
|
||||
enum
|
||||
{
|
||||
CPU_FIRM_INTEL,
|
||||
CPU_FIRM_AMD,
|
||||
CPU_FIRM_VIA
|
||||
};
|
||||
|
||||
Bool x86cpuid_CheckAndRead(Cx86cpuid *p);
|
||||
int x86cpuid_GetFirm(const Cx86cpuid *p);
|
||||
|
||||
#define x86cpuid_GetFamily(p) (((p)->ver >> 8) & 0xFF00F)
|
||||
#define x86cpuid_GetModel(p) (((p)->ver >> 4) & 0xF00F)
|
||||
#define x86cpuid_GetStepping(p) ((p)->ver & 0xF)
|
||||
|
||||
Bool CPU_Is_InOrder();
|
||||
Bool CPU_Is_Aes_Supported();
|
||||
|
||||
#endif
|
||||
|
||||
EXTERN_C_END
|
||||
|
||||
#endif
|
||||
/* CpuArch.h -- CPU specific code
|
||||
2010-10-26: Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __CPU_ARCH_H
|
||||
#define __CPU_ARCH_H
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
EXTERN_C_BEGIN
|
||||
|
||||
/*
|
||||
MY_CPU_LE means that CPU is LITTLE ENDIAN.
|
||||
If MY_CPU_LE is not defined, we don't know about that property of platform (it can be LITTLE ENDIAN).
|
||||
|
||||
MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned memory accesses.
|
||||
If MY_CPU_LE_UNALIGN is not defined, we don't know about these properties of platform.
|
||||
*/
|
||||
|
||||
#if defined(_M_X64) || defined(_M_AMD64) || defined(__x86_64__)
|
||||
#define MY_CPU_AMD64
|
||||
#endif
|
||||
|
||||
#if defined(MY_CPU_AMD64) || defined(_M_IA64)
|
||||
#define MY_CPU_64BIT
|
||||
#endif
|
||||
|
||||
#if defined(_M_IX86) || defined(__i386__)
|
||||
#define MY_CPU_X86
|
||||
#endif
|
||||
|
||||
#if defined(MY_CPU_X86) || defined(MY_CPU_AMD64)
|
||||
#define MY_CPU_X86_OR_AMD64
|
||||
#endif
|
||||
|
||||
#if defined(MY_CPU_X86) || defined(_M_ARM)
|
||||
#define MY_CPU_32BIT
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) && defined(_M_ARM)
|
||||
#define MY_CPU_ARM_LE
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) && defined(_M_IA64)
|
||||
#define MY_CPU_IA64_LE
|
||||
#endif
|
||||
|
||||
#if defined(MY_CPU_X86_OR_AMD64)
|
||||
#define MY_CPU_LE_UNALIGN
|
||||
#endif
|
||||
|
||||
#if defined(MY_CPU_X86_OR_AMD64) || defined(MY_CPU_ARM_LE) || defined(MY_CPU_IA64_LE) || defined(__ARMEL__) || defined(__MIPSEL__) || defined(__LITTLE_ENDIAN__)
|
||||
#define MY_CPU_LE
|
||||
#endif
|
||||
|
||||
#if defined(__BIG_ENDIAN__)
|
||||
#define MY_CPU_BE
|
||||
#endif
|
||||
|
||||
#if defined(MY_CPU_LE) && defined(MY_CPU_BE)
|
||||
Stop_Compiling_Bad_Endian
|
||||
#endif
|
||||
|
||||
#ifdef MY_CPU_LE_UNALIGN
|
||||
|
||||
#define GetUi16(p) (*(const UInt16 *)(p))
|
||||
#define GetUi32(p) (*(const UInt32 *)(p))
|
||||
#define GetUi64(p) (*(const UInt64 *)(p))
|
||||
#define SetUi16(p, d) *(UInt16 *)(p) = (d);
|
||||
#define SetUi32(p, d) *(UInt32 *)(p) = (d);
|
||||
#define SetUi64(p, d) *(UInt64 *)(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 SetUi16(p, d) { UInt32 _x_ = (d); \
|
||||
((Byte *)(p))[0] = (Byte)_x_; \
|
||||
((Byte *)(p))[1] = (Byte)(_x_ >> 8); }
|
||||
|
||||
#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); }
|
||||
|
||||
#define SetUi64(p, d) { UInt64 _x64_ = (d); \
|
||||
SetUi32(p, (UInt32)_x64_); \
|
||||
SetUi32(((Byte *)(p)) + 4, (UInt32)(_x64_ >> 32)); }
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(MY_CPU_LE_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])
|
||||
|
||||
|
||||
#ifdef MY_CPU_X86_OR_AMD64
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UInt32 maxFunc;
|
||||
UInt32 vendor[3];
|
||||
UInt32 ver;
|
||||
UInt32 b;
|
||||
UInt32 c;
|
||||
UInt32 d;
|
||||
} Cx86cpuid;
|
||||
|
||||
enum
|
||||
{
|
||||
CPU_FIRM_INTEL,
|
||||
CPU_FIRM_AMD,
|
||||
CPU_FIRM_VIA
|
||||
};
|
||||
|
||||
Bool x86cpuid_CheckAndRead(Cx86cpuid *p);
|
||||
int x86cpuid_GetFirm(const Cx86cpuid *p);
|
||||
|
||||
#define x86cpuid_GetFamily(p) (((p)->ver >> 8) & 0xFF00F)
|
||||
#define x86cpuid_GetModel(p) (((p)->ver >> 4) & 0xF00F)
|
||||
#define x86cpuid_GetStepping(p) ((p)->ver & 0xF)
|
||||
|
||||
Bool CPU_Is_InOrder();
|
||||
Bool CPU_Is_Aes_Supported();
|
||||
|
||||
#endif
|
||||
|
||||
EXTERN_C_END
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,371 +1,371 @@
|
|||
/* Lzma2Dec.c -- LZMA2 Decoder
|
||||
2009-05-03 : Igor Pavlov : Public domain */
|
||||
|
||||
/* #define SHOW_DEBUG_INFO */
|
||||
|
||||
#ifdef SHOW_DEBUG_INFO
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "Lzma2Dec.h"
|
||||
|
||||
/*
|
||||
00000000 - EOS
|
||||
00000001 U U - Uncompressed Reset Dic
|
||||
00000010 U U - Uncompressed No Reset
|
||||
100uuuuu U U P P - LZMA no reset
|
||||
101uuuuu U U P P - LZMA reset state
|
||||
110uuuuu U U P P S - LZMA reset state + new prop
|
||||
111uuuuu U U P P S - LZMA reset state + new prop + reset dic
|
||||
|
||||
u, U - Unpack Size
|
||||
P - Pack Size
|
||||
S - Props
|
||||
*/
|
||||
|
||||
#define LZMA2_CONTROL_LZMA (1 << 7)
|
||||
#define LZMA2_CONTROL_COPY_NO_RESET 2
|
||||
#define LZMA2_CONTROL_COPY_RESET_DIC 1
|
||||
#define LZMA2_CONTROL_EOF 0
|
||||
|
||||
#define LZMA2_IS_UNCOMPRESSED_STATE(p) (((p)->control & LZMA2_CONTROL_LZMA) == 0)
|
||||
|
||||
#define LZMA2_GET_LZMA_MODE(p) (((p)->control >> 5) & 3)
|
||||
#define LZMA2_IS_THERE_PROP(mode) ((mode) >= 2)
|
||||
|
||||
#define LZMA2_LCLP_MAX 4
|
||||
#define LZMA2_DIC_SIZE_FROM_PROP(p) (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11))
|
||||
|
||||
#ifdef SHOW_DEBUG_INFO
|
||||
#define PRF(x) x
|
||||
#else
|
||||
#define PRF(x)
|
||||
#endif
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LZMA2_STATE_CONTROL,
|
||||
LZMA2_STATE_UNPACK0,
|
||||
LZMA2_STATE_UNPACK1,
|
||||
LZMA2_STATE_PACK0,
|
||||
LZMA2_STATE_PACK1,
|
||||
LZMA2_STATE_PROP,
|
||||
LZMA2_STATE_DATA,
|
||||
LZMA2_STATE_DATA_CONT,
|
||||
LZMA2_STATE_FINISHED,
|
||||
LZMA2_STATE_ERROR
|
||||
} ELzma2State;
|
||||
|
||||
static SRes Lzma2Dec_GetOldProps(Byte prop, Byte *props)
|
||||
{
|
||||
UInt32 dicSize;
|
||||
if (prop > 40)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
dicSize = (prop == 40) ? 0xFFFFFFFF : LZMA2_DIC_SIZE_FROM_PROP(prop);
|
||||
props[0] = (Byte)LZMA2_LCLP_MAX;
|
||||
props[1] = (Byte)(dicSize);
|
||||
props[2] = (Byte)(dicSize >> 8);
|
||||
props[3] = (Byte)(dicSize >> 16);
|
||||
props[4] = (Byte)(dicSize >> 24);
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
SRes Lzma2Dec_AllocateProbs(CLzma2Dec *p, Byte prop, ISzAlloc *alloc)
|
||||
{
|
||||
Byte props[LZMA_PROPS_SIZE];
|
||||
RINOK(Lzma2Dec_GetOldProps(prop, props));
|
||||
return LzmaDec_AllocateProbs(&p->decoder, props, LZMA_PROPS_SIZE, alloc);
|
||||
}
|
||||
|
||||
SRes Lzma2Dec_Allocate(CLzma2Dec *p, Byte prop, ISzAlloc *alloc)
|
||||
{
|
||||
Byte props[LZMA_PROPS_SIZE];
|
||||
RINOK(Lzma2Dec_GetOldProps(prop, props));
|
||||
return LzmaDec_Allocate(&p->decoder, props, LZMA_PROPS_SIZE, alloc);
|
||||
}
|
||||
|
||||
void Lzma2Dec_Init(CLzma2Dec *p)
|
||||
{
|
||||
p->state = LZMA2_STATE_CONTROL;
|
||||
p->needInitDic = True;
|
||||
p->needInitState = True;
|
||||
p->needInitProp = True;
|
||||
LzmaDec_Init(&p->decoder);
|
||||
}
|
||||
|
||||
static ELzma2State Lzma2Dec_UpdateState(CLzma2Dec *p, Byte b)
|
||||
{
|
||||
switch(p->state)
|
||||
{
|
||||
case LZMA2_STATE_CONTROL:
|
||||
p->control = b;
|
||||
PRF(printf("\n %4X ", p->decoder.dicPos));
|
||||
PRF(printf(" %2X", b));
|
||||
if (p->control == 0)
|
||||
return LZMA2_STATE_FINISHED;
|
||||
if (LZMA2_IS_UNCOMPRESSED_STATE(p))
|
||||
{
|
||||
if ((p->control & 0x7F) > 2)
|
||||
return LZMA2_STATE_ERROR;
|
||||
p->unpackSize = 0;
|
||||
}
|
||||
else
|
||||
p->unpackSize = (UInt32)(p->control & 0x1F) << 16;
|
||||
return LZMA2_STATE_UNPACK0;
|
||||
|
||||
case LZMA2_STATE_UNPACK0:
|
||||
p->unpackSize |= (UInt32)b << 8;
|
||||
return LZMA2_STATE_UNPACK1;
|
||||
|
||||
case LZMA2_STATE_UNPACK1:
|
||||
p->unpackSize |= (UInt32)b;
|
||||
p->unpackSize++;
|
||||
PRF(printf(" %8d", p->unpackSize));
|
||||
return (LZMA2_IS_UNCOMPRESSED_STATE(p)) ? LZMA2_STATE_DATA : LZMA2_STATE_PACK0;
|
||||
|
||||
case LZMA2_STATE_PACK0:
|
||||
p->packSize = (UInt32)b << 8;
|
||||
return LZMA2_STATE_PACK1;
|
||||
|
||||
case LZMA2_STATE_PACK1:
|
||||
p->packSize |= (UInt32)b;
|
||||
p->packSize++;
|
||||
PRF(printf(" %8d", p->packSize));
|
||||
return LZMA2_IS_THERE_PROP(LZMA2_GET_LZMA_MODE(p)) ? LZMA2_STATE_PROP:
|
||||
(p->needInitProp ? LZMA2_STATE_ERROR : LZMA2_STATE_DATA);
|
||||
|
||||
case LZMA2_STATE_PROP:
|
||||
{
|
||||
int lc, lp;
|
||||
if (b >= (9 * 5 * 5))
|
||||
return LZMA2_STATE_ERROR;
|
||||
lc = b % 9;
|
||||
b /= 9;
|
||||
p->decoder.prop.pb = b / 5;
|
||||
lp = b % 5;
|
||||
if (lc + lp > LZMA2_LCLP_MAX)
|
||||
return LZMA2_STATE_ERROR;
|
||||
p->decoder.prop.lc = lc;
|
||||
p->decoder.prop.lp = lp;
|
||||
p->needInitProp = False;
|
||||
return LZMA2_STATE_DATA;
|
||||
}
|
||||
}
|
||||
return LZMA2_STATE_ERROR;
|
||||
}
|
||||
|
||||
static void LzmaDec_UpdateWithUncompressed(CLzmaDec *p, const Byte *src, SizeT size)
|
||||
{
|
||||
memcpy(p->dic + p->dicPos, src, size);
|
||||
p->dicPos += size;
|
||||
if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= size)
|
||||
p->checkDicSize = p->prop.dicSize;
|
||||
p->processedPos += (UInt32)size;
|
||||
}
|
||||
|
||||
static
|
||||
void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState)
|
||||
{
|
||||
p->needFlush = 1;
|
||||
p->remainLen = 0;
|
||||
p->tempBufSize = 0;
|
||||
|
||||
if (initDic)
|
||||
{
|
||||
p->processedPos = 0;
|
||||
p->checkDicSize = 0;
|
||||
p->needInitState = 1;
|
||||
}
|
||||
if (initState)
|
||||
p->needInitState = 1;
|
||||
}
|
||||
|
||||
SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit,
|
||||
const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status)
|
||||
{
|
||||
SizeT inSize = *srcLen;
|
||||
*srcLen = 0;
|
||||
*status = LZMA_STATUS_NOT_SPECIFIED;
|
||||
|
||||
while (p->state != LZMA2_STATE_FINISHED)
|
||||
{
|
||||
SizeT dicPos = p->decoder.dicPos;
|
||||
if (p->state == LZMA2_STATE_ERROR)
|
||||
return SZ_ERROR_DATA;
|
||||
if (dicPos == dicLimit && finishMode == LZMA_FINISH_ANY)
|
||||
{
|
||||
*status = LZMA_STATUS_NOT_FINISHED;
|
||||
return SZ_OK;
|
||||
}
|
||||
if (p->state != LZMA2_STATE_DATA && p->state != LZMA2_STATE_DATA_CONT)
|
||||
{
|
||||
if (*srcLen == inSize)
|
||||
{
|
||||
*status = LZMA_STATUS_NEEDS_MORE_INPUT;
|
||||
return SZ_OK;
|
||||
}
|
||||
(*srcLen)++;
|
||||
p->state = Lzma2Dec_UpdateState(p, *src++);
|
||||
continue;
|
||||
}
|
||||
{
|
||||
SizeT destSizeCur = dicLimit - dicPos;
|
||||
SizeT srcSizeCur = inSize - *srcLen;
|
||||
ELzmaFinishMode curFinishMode = LZMA_FINISH_ANY;
|
||||
|
||||
if (p->unpackSize <= destSizeCur)
|
||||
{
|
||||
destSizeCur = (SizeT)p->unpackSize;
|
||||
curFinishMode = LZMA_FINISH_END;
|
||||
}
|
||||
|
||||
if (LZMA2_IS_UNCOMPRESSED_STATE(p))
|
||||
{
|
||||
if (*srcLen == inSize)
|
||||
{
|
||||
*status = LZMA_STATUS_NEEDS_MORE_INPUT;
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
if (p->state == LZMA2_STATE_DATA)
|
||||
{
|
||||
Bool initDic = (p->control == LZMA2_CONTROL_COPY_RESET_DIC);
|
||||
if (initDic)
|
||||
p->needInitProp = p->needInitState = True;
|
||||
else if (p->needInitDic)
|
||||
return SZ_ERROR_DATA;
|
||||
p->needInitDic = False;
|
||||
LzmaDec_InitDicAndState(&p->decoder, initDic, False);
|
||||
}
|
||||
|
||||
if (srcSizeCur > destSizeCur)
|
||||
srcSizeCur = destSizeCur;
|
||||
|
||||
if (srcSizeCur == 0)
|
||||
return SZ_ERROR_DATA;
|
||||
|
||||
LzmaDec_UpdateWithUncompressed(&p->decoder, src, srcSizeCur);
|
||||
|
||||
src += srcSizeCur;
|
||||
*srcLen += srcSizeCur;
|
||||
p->unpackSize -= (UInt32)srcSizeCur;
|
||||
p->state = (p->unpackSize == 0) ? LZMA2_STATE_CONTROL : LZMA2_STATE_DATA_CONT;
|
||||
}
|
||||
else
|
||||
{
|
||||
SizeT outSizeProcessed;
|
||||
SRes res;
|
||||
|
||||
if (p->state == LZMA2_STATE_DATA)
|
||||
{
|
||||
int mode = LZMA2_GET_LZMA_MODE(p);
|
||||
Bool initDic = (mode == 3);
|
||||
Bool initState = (mode > 0);
|
||||
if ((!initDic && p->needInitDic) || (!initState && p->needInitState))
|
||||
return SZ_ERROR_DATA;
|
||||
|
||||
LzmaDec_InitDicAndState(&p->decoder, initDic, initState);
|
||||
p->needInitDic = False;
|
||||
p->needInitState = False;
|
||||
p->state = LZMA2_STATE_DATA_CONT;
|
||||
}
|
||||
if (srcSizeCur > p->packSize)
|
||||
srcSizeCur = (SizeT)p->packSize;
|
||||
|
||||
res = LzmaDec_DecodeToDic(&p->decoder, dicPos + destSizeCur, src, &srcSizeCur, curFinishMode, status);
|
||||
|
||||
src += srcSizeCur;
|
||||
*srcLen += srcSizeCur;
|
||||
p->packSize -= (UInt32)srcSizeCur;
|
||||
|
||||
outSizeProcessed = p->decoder.dicPos - dicPos;
|
||||
p->unpackSize -= (UInt32)outSizeProcessed;
|
||||
|
||||
RINOK(res);
|
||||
if (*status == LZMA_STATUS_NEEDS_MORE_INPUT)
|
||||
return res;
|
||||
|
||||
if (srcSizeCur == 0 && outSizeProcessed == 0)
|
||||
{
|
||||
if (*status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK ||
|
||||
p->unpackSize != 0 || p->packSize != 0)
|
||||
return SZ_ERROR_DATA;
|
||||
p->state = LZMA2_STATE_CONTROL;
|
||||
}
|
||||
if (*status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)
|
||||
*status = LZMA_STATUS_NOT_FINISHED;
|
||||
}
|
||||
}
|
||||
}
|
||||
*status = LZMA_STATUS_FINISHED_WITH_MARK;
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
SRes Lzma2Dec_DecodeToBuf(CLzma2Dec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status)
|
||||
{
|
||||
SizeT outSize = *destLen, inSize = *srcLen;
|
||||
*srcLen = *destLen = 0;
|
||||
for (;;)
|
||||
{
|
||||
SizeT srcSizeCur = inSize, outSizeCur, dicPos;
|
||||
ELzmaFinishMode curFinishMode;
|
||||
SRes res;
|
||||
if (p->decoder.dicPos == p->decoder.dicBufSize)
|
||||
p->decoder.dicPos = 0;
|
||||
dicPos = p->decoder.dicPos;
|
||||
if (outSize > p->decoder.dicBufSize - dicPos)
|
||||
{
|
||||
outSizeCur = p->decoder.dicBufSize;
|
||||
curFinishMode = LZMA_FINISH_ANY;
|
||||
}
|
||||
else
|
||||
{
|
||||
outSizeCur = dicPos + outSize;
|
||||
curFinishMode = finishMode;
|
||||
}
|
||||
|
||||
res = Lzma2Dec_DecodeToDic(p, outSizeCur, src, &srcSizeCur, curFinishMode, status);
|
||||
src += srcSizeCur;
|
||||
inSize -= srcSizeCur;
|
||||
*srcLen += srcSizeCur;
|
||||
outSizeCur = p->decoder.dicPos - dicPos;
|
||||
memcpy(dest, p->decoder.dic + dicPos, outSizeCur);
|
||||
dest += outSizeCur;
|
||||
outSize -= outSizeCur;
|
||||
*destLen += outSizeCur;
|
||||
if (res != 0)
|
||||
return res;
|
||||
if (outSizeCur == 0 || outSize == 0)
|
||||
return SZ_OK;
|
||||
}
|
||||
}
|
||||
|
||||
SRes Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
|
||||
Byte prop, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAlloc *alloc)
|
||||
{
|
||||
CLzma2Dec decoder;
|
||||
SRes res;
|
||||
SizeT outSize = *destLen, inSize = *srcLen;
|
||||
Byte props[LZMA_PROPS_SIZE];
|
||||
|
||||
Lzma2Dec_Construct(&decoder);
|
||||
|
||||
*destLen = *srcLen = 0;
|
||||
*status = LZMA_STATUS_NOT_SPECIFIED;
|
||||
decoder.decoder.dic = dest;
|
||||
decoder.decoder.dicBufSize = outSize;
|
||||
|
||||
RINOK(Lzma2Dec_GetOldProps(prop, props));
|
||||
RINOK(LzmaDec_AllocateProbs(&decoder.decoder, props, LZMA_PROPS_SIZE, alloc));
|
||||
|
||||
*srcLen = inSize;
|
||||
res = Lzma2Dec_DecodeToDic(&decoder, outSize, src, srcLen, finishMode, status);
|
||||
*destLen = decoder.decoder.dicPos;
|
||||
if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT)
|
||||
res = SZ_ERROR_INPUT_EOF;
|
||||
|
||||
LzmaDec_FreeProbs(&decoder.decoder, alloc);
|
||||
return res;
|
||||
}
|
||||
/* Lzma2Dec.c -- LZMA2 Decoder
|
||||
2009-05-03 : Igor Pavlov : Public domain */
|
||||
|
||||
/* #define SHOW_DEBUG_INFO */
|
||||
|
||||
#ifdef SHOW_DEBUG_INFO
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "Lzma2Dec.h"
|
||||
|
||||
/*
|
||||
00000000 - EOS
|
||||
00000001 U U - Uncompressed Reset Dic
|
||||
00000010 U U - Uncompressed No Reset
|
||||
100uuuuu U U P P - LZMA no reset
|
||||
101uuuuu U U P P - LZMA reset state
|
||||
110uuuuu U U P P S - LZMA reset state + new prop
|
||||
111uuuuu U U P P S - LZMA reset state + new prop + reset dic
|
||||
|
||||
u, U - Unpack Size
|
||||
P - Pack Size
|
||||
S - Props
|
||||
*/
|
||||
|
||||
#define LZMA2_CONTROL_LZMA (1 << 7)
|
||||
#define LZMA2_CONTROL_COPY_NO_RESET 2
|
||||
#define LZMA2_CONTROL_COPY_RESET_DIC 1
|
||||
#define LZMA2_CONTROL_EOF 0
|
||||
|
||||
#define LZMA2_IS_UNCOMPRESSED_STATE(p) (((p)->control & LZMA2_CONTROL_LZMA) == 0)
|
||||
|
||||
#define LZMA2_GET_LZMA_MODE(p) (((p)->control >> 5) & 3)
|
||||
#define LZMA2_IS_THERE_PROP(mode) ((mode) >= 2)
|
||||
|
||||
#define LZMA2_LCLP_MAX 4
|
||||
#define LZMA2_DIC_SIZE_FROM_PROP(p) (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11))
|
||||
|
||||
#ifdef SHOW_DEBUG_INFO
|
||||
#define PRF(x) x
|
||||
#else
|
||||
#define PRF(x)
|
||||
#endif
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LZMA2_STATE_CONTROL,
|
||||
LZMA2_STATE_UNPACK0,
|
||||
LZMA2_STATE_UNPACK1,
|
||||
LZMA2_STATE_PACK0,
|
||||
LZMA2_STATE_PACK1,
|
||||
LZMA2_STATE_PROP,
|
||||
LZMA2_STATE_DATA,
|
||||
LZMA2_STATE_DATA_CONT,
|
||||
LZMA2_STATE_FINISHED,
|
||||
LZMA2_STATE_ERROR
|
||||
} ELzma2State;
|
||||
|
||||
static SRes Lzma2Dec_GetOldProps(Byte prop, Byte *props)
|
||||
{
|
||||
UInt32 dicSize;
|
||||
if (prop > 40)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
dicSize = (prop == 40) ? 0xFFFFFFFF : LZMA2_DIC_SIZE_FROM_PROP(prop);
|
||||
props[0] = (Byte)LZMA2_LCLP_MAX;
|
||||
props[1] = (Byte)(dicSize);
|
||||
props[2] = (Byte)(dicSize >> 8);
|
||||
props[3] = (Byte)(dicSize >> 16);
|
||||
props[4] = (Byte)(dicSize >> 24);
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
SRes Lzma2Dec_AllocateProbs(CLzma2Dec *p, Byte prop, ISzAlloc *alloc)
|
||||
{
|
||||
Byte props[LZMA_PROPS_SIZE];
|
||||
RINOK(Lzma2Dec_GetOldProps(prop, props));
|
||||
return LzmaDec_AllocateProbs(&p->decoder, props, LZMA_PROPS_SIZE, alloc);
|
||||
}
|
||||
|
||||
SRes Lzma2Dec_Allocate(CLzma2Dec *p, Byte prop, ISzAlloc *alloc)
|
||||
{
|
||||
Byte props[LZMA_PROPS_SIZE];
|
||||
RINOK(Lzma2Dec_GetOldProps(prop, props));
|
||||
return LzmaDec_Allocate(&p->decoder, props, LZMA_PROPS_SIZE, alloc);
|
||||
}
|
||||
|
||||
void Lzma2Dec_Init(CLzma2Dec *p)
|
||||
{
|
||||
p->state = LZMA2_STATE_CONTROL;
|
||||
p->needInitDic = True;
|
||||
p->needInitState = True;
|
||||
p->needInitProp = True;
|
||||
LzmaDec_Init(&p->decoder);
|
||||
}
|
||||
|
||||
static ELzma2State Lzma2Dec_UpdateState(CLzma2Dec *p, Byte b)
|
||||
{
|
||||
switch(p->state)
|
||||
{
|
||||
case LZMA2_STATE_CONTROL:
|
||||
p->control = b;
|
||||
PRF(printf("\n %4X ", p->decoder.dicPos));
|
||||
PRF(printf(" %2X", b));
|
||||
if (p->control == 0)
|
||||
return LZMA2_STATE_FINISHED;
|
||||
if (LZMA2_IS_UNCOMPRESSED_STATE(p))
|
||||
{
|
||||
if ((p->control & 0x7F) > 2)
|
||||
return LZMA2_STATE_ERROR;
|
||||
p->unpackSize = 0;
|
||||
}
|
||||
else
|
||||
p->unpackSize = (UInt32)(p->control & 0x1F) << 16;
|
||||
return LZMA2_STATE_UNPACK0;
|
||||
|
||||
case LZMA2_STATE_UNPACK0:
|
||||
p->unpackSize |= (UInt32)b << 8;
|
||||
return LZMA2_STATE_UNPACK1;
|
||||
|
||||
case LZMA2_STATE_UNPACK1:
|
||||
p->unpackSize |= (UInt32)b;
|
||||
p->unpackSize++;
|
||||
PRF(printf(" %8d", p->unpackSize));
|
||||
return (LZMA2_IS_UNCOMPRESSED_STATE(p)) ? LZMA2_STATE_DATA : LZMA2_STATE_PACK0;
|
||||
|
||||
case LZMA2_STATE_PACK0:
|
||||
p->packSize = (UInt32)b << 8;
|
||||
return LZMA2_STATE_PACK1;
|
||||
|
||||
case LZMA2_STATE_PACK1:
|
||||
p->packSize |= (UInt32)b;
|
||||
p->packSize++;
|
||||
PRF(printf(" %8d", p->packSize));
|
||||
return LZMA2_IS_THERE_PROP(LZMA2_GET_LZMA_MODE(p)) ? LZMA2_STATE_PROP:
|
||||
(p->needInitProp ? LZMA2_STATE_ERROR : LZMA2_STATE_DATA);
|
||||
|
||||
case LZMA2_STATE_PROP:
|
||||
{
|
||||
int lc, lp;
|
||||
if (b >= (9 * 5 * 5))
|
||||
return LZMA2_STATE_ERROR;
|
||||
lc = b % 9;
|
||||
b /= 9;
|
||||
p->decoder.prop.pb = b / 5;
|
||||
lp = b % 5;
|
||||
if (lc + lp > LZMA2_LCLP_MAX)
|
||||
return LZMA2_STATE_ERROR;
|
||||
p->decoder.prop.lc = lc;
|
||||
p->decoder.prop.lp = lp;
|
||||
p->needInitProp = False;
|
||||
return LZMA2_STATE_DATA;
|
||||
}
|
||||
}
|
||||
return LZMA2_STATE_ERROR;
|
||||
}
|
||||
|
||||
static void LzmaDec_UpdateWithUncompressed(CLzmaDec *p, const Byte *src, SizeT size)
|
||||
{
|
||||
memcpy(p->dic + p->dicPos, src, size);
|
||||
p->dicPos += size;
|
||||
if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= size)
|
||||
p->checkDicSize = p->prop.dicSize;
|
||||
p->processedPos += (UInt32)size;
|
||||
}
|
||||
|
||||
static
|
||||
void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState)
|
||||
{
|
||||
p->needFlush = 1;
|
||||
p->remainLen = 0;
|
||||
p->tempBufSize = 0;
|
||||
|
||||
if (initDic)
|
||||
{
|
||||
p->processedPos = 0;
|
||||
p->checkDicSize = 0;
|
||||
p->needInitState = 1;
|
||||
}
|
||||
if (initState)
|
||||
p->needInitState = 1;
|
||||
}
|
||||
|
||||
SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit,
|
||||
const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status)
|
||||
{
|
||||
SizeT inSize = *srcLen;
|
||||
*srcLen = 0;
|
||||
*status = LZMA_STATUS_NOT_SPECIFIED;
|
||||
|
||||
while (p->state != LZMA2_STATE_FINISHED)
|
||||
{
|
||||
SizeT dicPos = p->decoder.dicPos;
|
||||
if (p->state == LZMA2_STATE_ERROR)
|
||||
return SZ_ERROR_DATA;
|
||||
if (dicPos == dicLimit && finishMode == LZMA_FINISH_ANY)
|
||||
{
|
||||
*status = LZMA_STATUS_NOT_FINISHED;
|
||||
return SZ_OK;
|
||||
}
|
||||
if (p->state != LZMA2_STATE_DATA && p->state != LZMA2_STATE_DATA_CONT)
|
||||
{
|
||||
if (*srcLen == inSize)
|
||||
{
|
||||
*status = LZMA_STATUS_NEEDS_MORE_INPUT;
|
||||
return SZ_OK;
|
||||
}
|
||||
(*srcLen)++;
|
||||
p->state = Lzma2Dec_UpdateState(p, *src++);
|
||||
continue;
|
||||
}
|
||||
{
|
||||
SizeT destSizeCur = dicLimit - dicPos;
|
||||
SizeT srcSizeCur = inSize - *srcLen;
|
||||
ELzmaFinishMode curFinishMode = LZMA_FINISH_ANY;
|
||||
|
||||
if (p->unpackSize <= destSizeCur)
|
||||
{
|
||||
destSizeCur = (SizeT)p->unpackSize;
|
||||
curFinishMode = LZMA_FINISH_END;
|
||||
}
|
||||
|
||||
if (LZMA2_IS_UNCOMPRESSED_STATE(p))
|
||||
{
|
||||
if (*srcLen == inSize)
|
||||
{
|
||||
*status = LZMA_STATUS_NEEDS_MORE_INPUT;
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
if (p->state == LZMA2_STATE_DATA)
|
||||
{
|
||||
Bool initDic = (p->control == LZMA2_CONTROL_COPY_RESET_DIC);
|
||||
if (initDic)
|
||||
p->needInitProp = p->needInitState = True;
|
||||
else if (p->needInitDic)
|
||||
return SZ_ERROR_DATA;
|
||||
p->needInitDic = False;
|
||||
LzmaDec_InitDicAndState(&p->decoder, initDic, False);
|
||||
}
|
||||
|
||||
if (srcSizeCur > destSizeCur)
|
||||
srcSizeCur = destSizeCur;
|
||||
|
||||
if (srcSizeCur == 0)
|
||||
return SZ_ERROR_DATA;
|
||||
|
||||
LzmaDec_UpdateWithUncompressed(&p->decoder, src, srcSizeCur);
|
||||
|
||||
src += srcSizeCur;
|
||||
*srcLen += srcSizeCur;
|
||||
p->unpackSize -= (UInt32)srcSizeCur;
|
||||
p->state = (p->unpackSize == 0) ? LZMA2_STATE_CONTROL : LZMA2_STATE_DATA_CONT;
|
||||
}
|
||||
else
|
||||
{
|
||||
SizeT outSizeProcessed;
|
||||
SRes res;
|
||||
|
||||
if (p->state == LZMA2_STATE_DATA)
|
||||
{
|
||||
int mode = LZMA2_GET_LZMA_MODE(p);
|
||||
Bool initDic = (mode == 3);
|
||||
Bool initState = (mode > 0);
|
||||
if ((!initDic && p->needInitDic) || (!initState && p->needInitState))
|
||||
return SZ_ERROR_DATA;
|
||||
|
||||
LzmaDec_InitDicAndState(&p->decoder, initDic, initState);
|
||||
p->needInitDic = False;
|
||||
p->needInitState = False;
|
||||
p->state = LZMA2_STATE_DATA_CONT;
|
||||
}
|
||||
if (srcSizeCur > p->packSize)
|
||||
srcSizeCur = (SizeT)p->packSize;
|
||||
|
||||
res = LzmaDec_DecodeToDic(&p->decoder, dicPos + destSizeCur, src, &srcSizeCur, curFinishMode, status);
|
||||
|
||||
src += srcSizeCur;
|
||||
*srcLen += srcSizeCur;
|
||||
p->packSize -= (UInt32)srcSizeCur;
|
||||
|
||||
outSizeProcessed = p->decoder.dicPos - dicPos;
|
||||
p->unpackSize -= (UInt32)outSizeProcessed;
|
||||
|
||||
RINOK(res);
|
||||
if (*status == LZMA_STATUS_NEEDS_MORE_INPUT)
|
||||
return res;
|
||||
|
||||
if (srcSizeCur == 0 && outSizeProcessed == 0)
|
||||
{
|
||||
if (*status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK ||
|
||||
p->unpackSize != 0 || p->packSize != 0)
|
||||
return SZ_ERROR_DATA;
|
||||
p->state = LZMA2_STATE_CONTROL;
|
||||
}
|
||||
if (*status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)
|
||||
*status = LZMA_STATUS_NOT_FINISHED;
|
||||
}
|
||||
}
|
||||
}
|
||||
*status = LZMA_STATUS_FINISHED_WITH_MARK;
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
SRes Lzma2Dec_DecodeToBuf(CLzma2Dec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status)
|
||||
{
|
||||
SizeT outSize = *destLen, inSize = *srcLen;
|
||||
*srcLen = *destLen = 0;
|
||||
for (;;)
|
||||
{
|
||||
SizeT srcSizeCur = inSize, outSizeCur, dicPos;
|
||||
ELzmaFinishMode curFinishMode;
|
||||
SRes res;
|
||||
if (p->decoder.dicPos == p->decoder.dicBufSize)
|
||||
p->decoder.dicPos = 0;
|
||||
dicPos = p->decoder.dicPos;
|
||||
if (outSize > p->decoder.dicBufSize - dicPos)
|
||||
{
|
||||
outSizeCur = p->decoder.dicBufSize;
|
||||
curFinishMode = LZMA_FINISH_ANY;
|
||||
}
|
||||
else
|
||||
{
|
||||
outSizeCur = dicPos + outSize;
|
||||
curFinishMode = finishMode;
|
||||
}
|
||||
|
||||
res = Lzma2Dec_DecodeToDic(p, outSizeCur, src, &srcSizeCur, curFinishMode, status);
|
||||
src += srcSizeCur;
|
||||
inSize -= srcSizeCur;
|
||||
*srcLen += srcSizeCur;
|
||||
outSizeCur = p->decoder.dicPos - dicPos;
|
||||
memcpy(dest, p->decoder.dic + dicPos, outSizeCur);
|
||||
dest += outSizeCur;
|
||||
outSize -= outSizeCur;
|
||||
*destLen += outSizeCur;
|
||||
if (res != 0)
|
||||
return res;
|
||||
if (outSizeCur == 0 || outSize == 0)
|
||||
return SZ_OK;
|
||||
}
|
||||
}
|
||||
|
||||
SRes Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
|
||||
Byte prop, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAlloc *alloc)
|
||||
{
|
||||
CLzma2Dec decoder;
|
||||
SRes res;
|
||||
SizeT outSize = *destLen, inSize = *srcLen;
|
||||
Byte props[LZMA_PROPS_SIZE];
|
||||
|
||||
Lzma2Dec_Construct(&decoder);
|
||||
|
||||
*destLen = *srcLen = 0;
|
||||
*status = LZMA_STATUS_NOT_SPECIFIED;
|
||||
decoder.decoder.dic = dest;
|
||||
decoder.decoder.dicBufSize = outSize;
|
||||
|
||||
RINOK(Lzma2Dec_GetOldProps(prop, props));
|
||||
RINOK(LzmaDec_AllocateProbs(&decoder.decoder, props, LZMA_PROPS_SIZE, alloc));
|
||||
|
||||
*srcLen = inSize;
|
||||
res = Lzma2Dec_DecodeToDic(&decoder, outSize, src, srcLen, finishMode, status);
|
||||
*destLen = decoder.decoder.dicPos;
|
||||
if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT)
|
||||
res = SZ_ERROR_INPUT_EOF;
|
||||
|
||||
LzmaDec_FreeProbs(&decoder.decoder, alloc);
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -1,84 +1,84 @@
|
|||
/* Lzma2Dec.h -- LZMA2 Decoder
|
||||
2009-05-03 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __LZMA2_DEC_H
|
||||
#define __LZMA2_DEC_H
|
||||
|
||||
#include "LzmaDec.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ---------- State Interface ---------- */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CLzmaDec decoder;
|
||||
UInt32 packSize;
|
||||
UInt32 unpackSize;
|
||||
int state;
|
||||
Byte control;
|
||||
Bool needInitDic;
|
||||
Bool needInitState;
|
||||
Bool needInitProp;
|
||||
} CLzma2Dec;
|
||||
|
||||
#define Lzma2Dec_Construct(p) LzmaDec_Construct(&(p)->decoder)
|
||||
#define Lzma2Dec_FreeProbs(p, alloc) LzmaDec_FreeProbs(&(p)->decoder, alloc);
|
||||
#define Lzma2Dec_Free(p, alloc) LzmaDec_Free(&(p)->decoder, alloc);
|
||||
|
||||
SRes Lzma2Dec_AllocateProbs(CLzma2Dec *p, Byte prop, ISzAlloc *alloc);
|
||||
SRes Lzma2Dec_Allocate(CLzma2Dec *p, Byte prop, ISzAlloc *alloc);
|
||||
void Lzma2Dec_Init(CLzma2Dec *p);
|
||||
|
||||
|
||||
/*
|
||||
finishMode:
|
||||
It has meaning only if the decoding reaches output limit (*destLen or dicLimit).
|
||||
LZMA_FINISH_ANY - use smallest number of input bytes
|
||||
LZMA_FINISH_END - read EndOfStream marker after decoding
|
||||
|
||||
Returns:
|
||||
SZ_OK
|
||||
status:
|
||||
LZMA_STATUS_FINISHED_WITH_MARK
|
||||
LZMA_STATUS_NOT_FINISHED
|
||||
LZMA_STATUS_NEEDS_MORE_INPUT
|
||||
SZ_ERROR_DATA - Data error
|
||||
*/
|
||||
|
||||
SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit,
|
||||
const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
|
||||
|
||||
SRes Lzma2Dec_DecodeToBuf(CLzma2Dec *p, Byte *dest, SizeT *destLen,
|
||||
const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
|
||||
|
||||
|
||||
/* ---------- One Call Interface ---------- */
|
||||
|
||||
/*
|
||||
finishMode:
|
||||
It has meaning only if the decoding reaches output limit (*destLen).
|
||||
LZMA_FINISH_ANY - use smallest number of input bytes
|
||||
LZMA_FINISH_END - read EndOfStream marker after decoding
|
||||
|
||||
Returns:
|
||||
SZ_OK
|
||||
status:
|
||||
LZMA_STATUS_FINISHED_WITH_MARK
|
||||
LZMA_STATUS_NOT_FINISHED
|
||||
SZ_ERROR_DATA - Data error
|
||||
SZ_ERROR_MEM - Memory allocation error
|
||||
SZ_ERROR_UNSUPPORTED - Unsupported properties
|
||||
SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
|
||||
*/
|
||||
|
||||
SRes Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
|
||||
Byte prop, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAlloc *alloc);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/* Lzma2Dec.h -- LZMA2 Decoder
|
||||
2009-05-03 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __LZMA2_DEC_H
|
||||
#define __LZMA2_DEC_H
|
||||
|
||||
#include "LzmaDec.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ---------- State Interface ---------- */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CLzmaDec decoder;
|
||||
UInt32 packSize;
|
||||
UInt32 unpackSize;
|
||||
int state;
|
||||
Byte control;
|
||||
Bool needInitDic;
|
||||
Bool needInitState;
|
||||
Bool needInitProp;
|
||||
} CLzma2Dec;
|
||||
|
||||
#define Lzma2Dec_Construct(p) LzmaDec_Construct(&(p)->decoder)
|
||||
#define Lzma2Dec_FreeProbs(p, alloc) LzmaDec_FreeProbs(&(p)->decoder, alloc);
|
||||
#define Lzma2Dec_Free(p, alloc) LzmaDec_Free(&(p)->decoder, alloc);
|
||||
|
||||
SRes Lzma2Dec_AllocateProbs(CLzma2Dec *p, Byte prop, ISzAlloc *alloc);
|
||||
SRes Lzma2Dec_Allocate(CLzma2Dec *p, Byte prop, ISzAlloc *alloc);
|
||||
void Lzma2Dec_Init(CLzma2Dec *p);
|
||||
|
||||
|
||||
/*
|
||||
finishMode:
|
||||
It has meaning only if the decoding reaches output limit (*destLen or dicLimit).
|
||||
LZMA_FINISH_ANY - use smallest number of input bytes
|
||||
LZMA_FINISH_END - read EndOfStream marker after decoding
|
||||
|
||||
Returns:
|
||||
SZ_OK
|
||||
status:
|
||||
LZMA_STATUS_FINISHED_WITH_MARK
|
||||
LZMA_STATUS_NOT_FINISHED
|
||||
LZMA_STATUS_NEEDS_MORE_INPUT
|
||||
SZ_ERROR_DATA - Data error
|
||||
*/
|
||||
|
||||
SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit,
|
||||
const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
|
||||
|
||||
SRes Lzma2Dec_DecodeToBuf(CLzma2Dec *p, Byte *dest, SizeT *destLen,
|
||||
const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
|
||||
|
||||
|
||||
/* ---------- One Call Interface ---------- */
|
||||
|
||||
/*
|
||||
finishMode:
|
||||
It has meaning only if the decoding reaches output limit (*destLen).
|
||||
LZMA_FINISH_ANY - use smallest number of input bytes
|
||||
LZMA_FINISH_END - read EndOfStream marker after decoding
|
||||
|
||||
Returns:
|
||||
SZ_OK
|
||||
status:
|
||||
LZMA_STATUS_FINISHED_WITH_MARK
|
||||
LZMA_STATUS_NOT_FINISHED
|
||||
SZ_ERROR_DATA - Data error
|
||||
SZ_ERROR_MEM - Memory allocation error
|
||||
SZ_ERROR_UNSUPPORTED - Unsupported properties
|
||||
SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
|
||||
*/
|
||||
|
||||
SRes Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
|
||||
Byte prop, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAlloc *alloc);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
2000
fex/7z_C/LzmaDec.c
2000
fex/7z_C/LzmaDec.c
File diff suppressed because it is too large
Load Diff
|
@ -1,231 +1,231 @@
|
|||
/* LzmaDec.h -- LZMA Decoder
|
||||
2009-02-07 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __LZMA_DEC_H
|
||||
#define __LZMA_DEC_H
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* #define _LZMA_PROB32 */
|
||||
/* _LZMA_PROB32 can increase the speed on some CPUs,
|
||||
but memory usage for CLzmaDec::probs will be doubled in that case */
|
||||
|
||||
#ifdef _LZMA_PROB32
|
||||
#define CLzmaProb UInt32
|
||||
#else
|
||||
#define CLzmaProb UInt16
|
||||
#endif
|
||||
|
||||
|
||||
/* ---------- LZMA Properties ---------- */
|
||||
|
||||
#define LZMA_PROPS_SIZE 5
|
||||
|
||||
typedef struct _CLzmaProps
|
||||
{
|
||||
unsigned lc, lp, pb;
|
||||
UInt32 dicSize;
|
||||
} CLzmaProps;
|
||||
|
||||
/* LzmaProps_Decode - decodes properties
|
||||
Returns:
|
||||
SZ_OK
|
||||
SZ_ERROR_UNSUPPORTED - Unsupported properties
|
||||
*/
|
||||
|
||||
SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size);
|
||||
|
||||
|
||||
/* ---------- LZMA Decoder state ---------- */
|
||||
|
||||
/* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case.
|
||||
Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */
|
||||
|
||||
#define LZMA_REQUIRED_INPUT_MAX 20
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CLzmaProps prop;
|
||||
CLzmaProb *probs;
|
||||
Byte *dic;
|
||||
const Byte *buf;
|
||||
UInt32 range, code;
|
||||
SizeT dicPos;
|
||||
SizeT dicBufSize;
|
||||
UInt32 processedPos;
|
||||
UInt32 checkDicSize;
|
||||
unsigned state;
|
||||
UInt32 reps[4];
|
||||
unsigned remainLen;
|
||||
int needFlush;
|
||||
int needInitState;
|
||||
UInt32 numProbs;
|
||||
unsigned tempBufSize;
|
||||
Byte tempBuf[LZMA_REQUIRED_INPUT_MAX];
|
||||
} CLzmaDec;
|
||||
|
||||
#define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; }
|
||||
|
||||
void LzmaDec_Init(CLzmaDec *p);
|
||||
|
||||
/* There are two types of LZMA streams:
|
||||
0) Stream with end mark. That end mark adds about 6 bytes to compressed size.
|
||||
1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LZMA_FINISH_ANY, /* finish at any point */
|
||||
LZMA_FINISH_END /* block must be finished at the end */
|
||||
} ELzmaFinishMode;
|
||||
|
||||
/* ELzmaFinishMode has meaning only if the decoding reaches output limit !!!
|
||||
|
||||
You must use LZMA_FINISH_END, when you know that current output buffer
|
||||
covers last bytes of block. In other cases you must use LZMA_FINISH_ANY.
|
||||
|
||||
If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK,
|
||||
and output value of destLen will be less than output buffer size limit.
|
||||
You can check status result also.
|
||||
|
||||
You can use multiple checks to test data integrity after full decompression:
|
||||
1) Check Result and "status" variable.
|
||||
2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize.
|
||||
3) Check that output(srcLen) = compressedSize, if you know real compressedSize.
|
||||
You must use correct finish mode in that case. */
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LZMA_STATUS_NOT_SPECIFIED, /* use main error code instead */
|
||||
LZMA_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */
|
||||
LZMA_STATUS_NOT_FINISHED, /* stream was not finished */
|
||||
LZMA_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */
|
||||
LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK /* there is probability that stream was finished without end mark */
|
||||
} ELzmaStatus;
|
||||
|
||||
/* ELzmaStatus is used only as output value for function call */
|
||||
|
||||
|
||||
/* ---------- Interfaces ---------- */
|
||||
|
||||
/* There are 3 levels of interfaces:
|
||||
1) Dictionary Interface
|
||||
2) Buffer Interface
|
||||
3) One Call Interface
|
||||
You can select any of these interfaces, but don't mix functions from different
|
||||
groups for same object. */
|
||||
|
||||
|
||||
/* There are two variants to allocate state for Dictionary Interface:
|
||||
1) LzmaDec_Allocate / LzmaDec_Free
|
||||
2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs
|
||||
You can use variant 2, if you set dictionary buffer manually.
|
||||
For Buffer Interface you must always use variant 1.
|
||||
|
||||
LzmaDec_Allocate* can return:
|
||||
SZ_OK
|
||||
SZ_ERROR_MEM - Memory allocation error
|
||||
SZ_ERROR_UNSUPPORTED - Unsupported properties
|
||||
*/
|
||||
|
||||
SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc);
|
||||
void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc);
|
||||
|
||||
SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc);
|
||||
void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc);
|
||||
|
||||
/* ---------- Dictionary Interface ---------- */
|
||||
|
||||
/* You can use it, if you want to eliminate the overhead for data copying from
|
||||
dictionary to some other external buffer.
|
||||
You must work with CLzmaDec variables directly in this interface.
|
||||
|
||||
STEPS:
|
||||
LzmaDec_Constr()
|
||||
LzmaDec_Allocate()
|
||||
for (each new stream)
|
||||
{
|
||||
LzmaDec_Init()
|
||||
while (it needs more decompression)
|
||||
{
|
||||
LzmaDec_DecodeToDic()
|
||||
use data from CLzmaDec::dic and update CLzmaDec::dicPos
|
||||
}
|
||||
}
|
||||
LzmaDec_Free()
|
||||
*/
|
||||
|
||||
/* LzmaDec_DecodeToDic
|
||||
|
||||
The decoding to internal dictionary buffer (CLzmaDec::dic).
|
||||
You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!!
|
||||
|
||||
finishMode:
|
||||
It has meaning only if the decoding reaches output limit (dicLimit).
|
||||
LZMA_FINISH_ANY - Decode just dicLimit bytes.
|
||||
LZMA_FINISH_END - Stream must be finished after dicLimit.
|
||||
|
||||
Returns:
|
||||
SZ_OK
|
||||
status:
|
||||
LZMA_STATUS_FINISHED_WITH_MARK
|
||||
LZMA_STATUS_NOT_FINISHED
|
||||
LZMA_STATUS_NEEDS_MORE_INPUT
|
||||
LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
|
||||
SZ_ERROR_DATA - Data error
|
||||
*/
|
||||
|
||||
SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit,
|
||||
const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
|
||||
|
||||
|
||||
/* ---------- Buffer Interface ---------- */
|
||||
|
||||
/* It's zlib-like interface.
|
||||
See LzmaDec_DecodeToDic description for information about STEPS and return results,
|
||||
but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need
|
||||
to work with CLzmaDec variables manually.
|
||||
|
||||
finishMode:
|
||||
It has meaning only if the decoding reaches output limit (*destLen).
|
||||
LZMA_FINISH_ANY - Decode just destLen bytes.
|
||||
LZMA_FINISH_END - Stream must be finished after (*destLen).
|
||||
*/
|
||||
|
||||
SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen,
|
||||
const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
|
||||
|
||||
|
||||
/* ---------- One Call Interface ---------- */
|
||||
|
||||
/* LzmaDecode
|
||||
|
||||
finishMode:
|
||||
It has meaning only if the decoding reaches output limit (*destLen).
|
||||
LZMA_FINISH_ANY - Decode just destLen bytes.
|
||||
LZMA_FINISH_END - Stream must be finished after (*destLen).
|
||||
|
||||
Returns:
|
||||
SZ_OK
|
||||
status:
|
||||
LZMA_STATUS_FINISHED_WITH_MARK
|
||||
LZMA_STATUS_NOT_FINISHED
|
||||
LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
|
||||
SZ_ERROR_DATA - Data error
|
||||
SZ_ERROR_MEM - Memory allocation error
|
||||
SZ_ERROR_UNSUPPORTED - Unsupported properties
|
||||
SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
|
||||
*/
|
||||
|
||||
SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
|
||||
const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
|
||||
ELzmaStatus *status, ISzAlloc *alloc);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/* LzmaDec.h -- LZMA Decoder
|
||||
2009-02-07 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __LZMA_DEC_H
|
||||
#define __LZMA_DEC_H
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* #define _LZMA_PROB32 */
|
||||
/* _LZMA_PROB32 can increase the speed on some CPUs,
|
||||
but memory usage for CLzmaDec::probs will be doubled in that case */
|
||||
|
||||
#ifdef _LZMA_PROB32
|
||||
#define CLzmaProb UInt32
|
||||
#else
|
||||
#define CLzmaProb UInt16
|
||||
#endif
|
||||
|
||||
|
||||
/* ---------- LZMA Properties ---------- */
|
||||
|
||||
#define LZMA_PROPS_SIZE 5
|
||||
|
||||
typedef struct _CLzmaProps
|
||||
{
|
||||
unsigned lc, lp, pb;
|
||||
UInt32 dicSize;
|
||||
} CLzmaProps;
|
||||
|
||||
/* LzmaProps_Decode - decodes properties
|
||||
Returns:
|
||||
SZ_OK
|
||||
SZ_ERROR_UNSUPPORTED - Unsupported properties
|
||||
*/
|
||||
|
||||
SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size);
|
||||
|
||||
|
||||
/* ---------- LZMA Decoder state ---------- */
|
||||
|
||||
/* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case.
|
||||
Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */
|
||||
|
||||
#define LZMA_REQUIRED_INPUT_MAX 20
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CLzmaProps prop;
|
||||
CLzmaProb *probs;
|
||||
Byte *dic;
|
||||
const Byte *buf;
|
||||
UInt32 range, code;
|
||||
SizeT dicPos;
|
||||
SizeT dicBufSize;
|
||||
UInt32 processedPos;
|
||||
UInt32 checkDicSize;
|
||||
unsigned state;
|
||||
UInt32 reps[4];
|
||||
unsigned remainLen;
|
||||
int needFlush;
|
||||
int needInitState;
|
||||
UInt32 numProbs;
|
||||
unsigned tempBufSize;
|
||||
Byte tempBuf[LZMA_REQUIRED_INPUT_MAX];
|
||||
} CLzmaDec;
|
||||
|
||||
#define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; }
|
||||
|
||||
void LzmaDec_Init(CLzmaDec *p);
|
||||
|
||||
/* There are two types of LZMA streams:
|
||||
0) Stream with end mark. That end mark adds about 6 bytes to compressed size.
|
||||
1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LZMA_FINISH_ANY, /* finish at any point */
|
||||
LZMA_FINISH_END /* block must be finished at the end */
|
||||
} ELzmaFinishMode;
|
||||
|
||||
/* ELzmaFinishMode has meaning only if the decoding reaches output limit !!!
|
||||
|
||||
You must use LZMA_FINISH_END, when you know that current output buffer
|
||||
covers last bytes of block. In other cases you must use LZMA_FINISH_ANY.
|
||||
|
||||
If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK,
|
||||
and output value of destLen will be less than output buffer size limit.
|
||||
You can check status result also.
|
||||
|
||||
You can use multiple checks to test data integrity after full decompression:
|
||||
1) Check Result and "status" variable.
|
||||
2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize.
|
||||
3) Check that output(srcLen) = compressedSize, if you know real compressedSize.
|
||||
You must use correct finish mode in that case. */
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LZMA_STATUS_NOT_SPECIFIED, /* use main error code instead */
|
||||
LZMA_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */
|
||||
LZMA_STATUS_NOT_FINISHED, /* stream was not finished */
|
||||
LZMA_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */
|
||||
LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK /* there is probability that stream was finished without end mark */
|
||||
} ELzmaStatus;
|
||||
|
||||
/* ELzmaStatus is used only as output value for function call */
|
||||
|
||||
|
||||
/* ---------- Interfaces ---------- */
|
||||
|
||||
/* There are 3 levels of interfaces:
|
||||
1) Dictionary Interface
|
||||
2) Buffer Interface
|
||||
3) One Call Interface
|
||||
You can select any of these interfaces, but don't mix functions from different
|
||||
groups for same object. */
|
||||
|
||||
|
||||
/* There are two variants to allocate state for Dictionary Interface:
|
||||
1) LzmaDec_Allocate / LzmaDec_Free
|
||||
2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs
|
||||
You can use variant 2, if you set dictionary buffer manually.
|
||||
For Buffer Interface you must always use variant 1.
|
||||
|
||||
LzmaDec_Allocate* can return:
|
||||
SZ_OK
|
||||
SZ_ERROR_MEM - Memory allocation error
|
||||
SZ_ERROR_UNSUPPORTED - Unsupported properties
|
||||
*/
|
||||
|
||||
SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc);
|
||||
void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc);
|
||||
|
||||
SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc);
|
||||
void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc);
|
||||
|
||||
/* ---------- Dictionary Interface ---------- */
|
||||
|
||||
/* You can use it, if you want to eliminate the overhead for data copying from
|
||||
dictionary to some other external buffer.
|
||||
You must work with CLzmaDec variables directly in this interface.
|
||||
|
||||
STEPS:
|
||||
LzmaDec_Constr()
|
||||
LzmaDec_Allocate()
|
||||
for (each new stream)
|
||||
{
|
||||
LzmaDec_Init()
|
||||
while (it needs more decompression)
|
||||
{
|
||||
LzmaDec_DecodeToDic()
|
||||
use data from CLzmaDec::dic and update CLzmaDec::dicPos
|
||||
}
|
||||
}
|
||||
LzmaDec_Free()
|
||||
*/
|
||||
|
||||
/* LzmaDec_DecodeToDic
|
||||
|
||||
The decoding to internal dictionary buffer (CLzmaDec::dic).
|
||||
You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!!
|
||||
|
||||
finishMode:
|
||||
It has meaning only if the decoding reaches output limit (dicLimit).
|
||||
LZMA_FINISH_ANY - Decode just dicLimit bytes.
|
||||
LZMA_FINISH_END - Stream must be finished after dicLimit.
|
||||
|
||||
Returns:
|
||||
SZ_OK
|
||||
status:
|
||||
LZMA_STATUS_FINISHED_WITH_MARK
|
||||
LZMA_STATUS_NOT_FINISHED
|
||||
LZMA_STATUS_NEEDS_MORE_INPUT
|
||||
LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
|
||||
SZ_ERROR_DATA - Data error
|
||||
*/
|
||||
|
||||
SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit,
|
||||
const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
|
||||
|
||||
|
||||
/* ---------- Buffer Interface ---------- */
|
||||
|
||||
/* It's zlib-like interface.
|
||||
See LzmaDec_DecodeToDic description for information about STEPS and return results,
|
||||
but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need
|
||||
to work with CLzmaDec variables manually.
|
||||
|
||||
finishMode:
|
||||
It has meaning only if the decoding reaches output limit (*destLen).
|
||||
LZMA_FINISH_ANY - Decode just destLen bytes.
|
||||
LZMA_FINISH_END - Stream must be finished after (*destLen).
|
||||
*/
|
||||
|
||||
SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen,
|
||||
const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
|
||||
|
||||
|
||||
/* ---------- One Call Interface ---------- */
|
||||
|
||||
/* LzmaDecode
|
||||
|
||||
finishMode:
|
||||
It has meaning only if the decoding reaches output limit (*destLen).
|
||||
LZMA_FINISH_ANY - Decode just destLen bytes.
|
||||
LZMA_FINISH_END - Stream must be finished after (*destLen).
|
||||
|
||||
Returns:
|
||||
SZ_OK
|
||||
status:
|
||||
LZMA_STATUS_FINISHED_WITH_MARK
|
||||
LZMA_STATUS_NOT_FINISHED
|
||||
LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
|
||||
SZ_ERROR_DATA - Data error
|
||||
SZ_ERROR_MEM - Memory allocation error
|
||||
SZ_ERROR_UNSUPPORTED - Unsupported properties
|
||||
SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
|
||||
*/
|
||||
|
||||
SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
|
||||
const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
|
||||
ELzmaStatus *status, ISzAlloc *alloc);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
508
fex/7z_C/Types.h
508
fex/7z_C/Types.h
|
@ -1,254 +1,254 @@
|
|||
/* Types.h -- Basic types
|
||||
2010-10-09 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __7Z_TYPES_H
|
||||
#define __7Z_TYPES_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#ifndef EXTERN_C_BEGIN
|
||||
#ifdef __cplusplus
|
||||
#define EXTERN_C_BEGIN extern "C" {
|
||||
#define EXTERN_C_END }
|
||||
#else
|
||||
#define EXTERN_C_BEGIN
|
||||
#define EXTERN_C_END
|
||||
#endif
|
||||
#endif
|
||||
|
||||
EXTERN_C_BEGIN
|
||||
|
||||
#define SZ_OK 0
|
||||
|
||||
#define SZ_ERROR_DATA 1
|
||||
#define SZ_ERROR_MEM 2
|
||||
#define SZ_ERROR_CRC 3
|
||||
#define SZ_ERROR_UNSUPPORTED 4
|
||||
#define SZ_ERROR_PARAM 5
|
||||
#define SZ_ERROR_INPUT_EOF 6
|
||||
#define SZ_ERROR_OUTPUT_EOF 7
|
||||
#define SZ_ERROR_READ 8
|
||||
#define SZ_ERROR_WRITE 9
|
||||
#define SZ_ERROR_PROGRESS 10
|
||||
#define SZ_ERROR_FAIL 11
|
||||
#define SZ_ERROR_THREAD 12
|
||||
|
||||
#define SZ_ERROR_ARCHIVE 16
|
||||
#define SZ_ERROR_NO_ARCHIVE 17
|
||||
|
||||
typedef int SRes;
|
||||
|
||||
#ifdef _WIN32
|
||||
typedef DWORD WRes;
|
||||
#else
|
||||
typedef int WRes;
|
||||
#endif
|
||||
|
||||
#ifndef RINOK
|
||||
#define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; }
|
||||
#endif
|
||||
|
||||
typedef unsigned char Byte;
|
||||
typedef short Int16;
|
||||
typedef unsigned short UInt16;
|
||||
|
||||
#ifdef _LZMA_UINT32_IS_ULONG
|
||||
typedef long Int32;
|
||||
typedef unsigned long UInt32;
|
||||
#else
|
||||
typedef int Int32;
|
||||
typedef unsigned int UInt32;
|
||||
#endif
|
||||
|
||||
#ifdef _SZ_NO_INT_64
|
||||
|
||||
/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers.
|
||||
NOTES: Some code will work incorrectly in that case! */
|
||||
|
||||
typedef long Int64;
|
||||
typedef unsigned long UInt64;
|
||||
|
||||
#else
|
||||
|
||||
#if defined(_MSC_VER) || defined(__BORLANDC__)
|
||||
typedef __int64 Int64;
|
||||
typedef unsigned __int64 UInt64;
|
||||
#define UINT64_CONST(n) n
|
||||
#else
|
||||
typedef long long int Int64;
|
||||
typedef unsigned long long int UInt64;
|
||||
#define UINT64_CONST(n) n ## ULL
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef _LZMA_NO_SYSTEM_SIZE_T
|
||||
typedef UInt32 SizeT;
|
||||
#else
|
||||
typedef size_t SizeT;
|
||||
#endif
|
||||
|
||||
typedef int Bool;
|
||||
#define True 1
|
||||
#define False 0
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
#define MY_STD_CALL __stdcall
|
||||
#else
|
||||
#define MY_STD_CALL
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#if _MSC_VER >= 1300
|
||||
#define MY_NO_INLINE __declspec(noinline)
|
||||
#else
|
||||
#define MY_NO_INLINE
|
||||
#endif
|
||||
|
||||
#define MY_CDECL __cdecl
|
||||
#define MY_FAST_CALL __fastcall
|
||||
|
||||
#else
|
||||
|
||||
#define MY_CDECL
|
||||
#define MY_FAST_CALL
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* The following interfaces use first parameter as pointer to structure */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Byte (*Read)(void *p); /* reads one byte, returns 0 in case of EOF or error */
|
||||
} IByteIn;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void (*Write)(void *p, Byte b);
|
||||
} IByteOut;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SRes (*Read)(void *p, void *buf, size_t *size);
|
||||
/* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
|
||||
(output(*size) < input(*size)) is allowed */
|
||||
} ISeqInStream;
|
||||
|
||||
/* it can return SZ_ERROR_INPUT_EOF */
|
||||
SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size);
|
||||
SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType);
|
||||
SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
size_t (*Write)(void *p, const void *buf, size_t size);
|
||||
/* Returns: result - the number of actually written bytes.
|
||||
(result < size) means error */
|
||||
} ISeqOutStream;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SZ_SEEK_SET = 0,
|
||||
SZ_SEEK_CUR = 1,
|
||||
SZ_SEEK_END = 2
|
||||
} ESzSeek;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SRes (*Read)(void *p, void *buf, size_t *size); /* same as ISeqInStream::Read */
|
||||
SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin);
|
||||
} ISeekInStream;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SRes (*Look)(void *p, const void **buf, size_t *size);
|
||||
/* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
|
||||
(output(*size) > input(*size)) is not allowed
|
||||
(output(*size) < input(*size)) is allowed */
|
||||
SRes (*Skip)(void *p, size_t offset);
|
||||
/* offset must be <= output(*size) of Look */
|
||||
|
||||
SRes (*Read)(void *p, void *buf, size_t *size);
|
||||
/* reads directly (without buffer). It's same as ISeqInStream::Read */
|
||||
SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin);
|
||||
} ILookInStream;
|
||||
|
||||
SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size);
|
||||
SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset);
|
||||
|
||||
/* reads via ILookInStream::Read */
|
||||
SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType);
|
||||
SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size);
|
||||
|
||||
#define LookToRead_BUF_SIZE (1 << 14)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ILookInStream s;
|
||||
ISeekInStream *realStream;
|
||||
size_t pos;
|
||||
size_t size;
|
||||
Byte buf[LookToRead_BUF_SIZE];
|
||||
} CLookToRead;
|
||||
|
||||
void LookToRead_CreateVTable(CLookToRead *p, int lookahead);
|
||||
void LookToRead_Init(CLookToRead *p);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ISeqInStream s;
|
||||
ILookInStream *realStream;
|
||||
} CSecToLook;
|
||||
|
||||
void SecToLook_CreateVTable(CSecToLook *p);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ISeqInStream s;
|
||||
ILookInStream *realStream;
|
||||
} CSecToRead;
|
||||
|
||||
void SecToRead_CreateVTable(CSecToRead *p);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize);
|
||||
/* Returns: result. (result != SZ_OK) means break.
|
||||
Value (UInt64)(Int64)-1 for size means unknown value. */
|
||||
} ICompressProgress;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void *(*Alloc)(void *p, size_t size);
|
||||
void (*Free)(void *p, void *address); /* address can be 0 */
|
||||
} ISzAlloc;
|
||||
|
||||
#define IAlloc_Alloc(p, size) (p)->Alloc((p), size)
|
||||
#define IAlloc_Free(p, a) (p)->Free((p), a)
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#define CHAR_PATH_SEPARATOR '\\'
|
||||
#define WCHAR_PATH_SEPARATOR L'\\'
|
||||
#define STRING_PATH_SEPARATOR "\\"
|
||||
#define WSTRING_PATH_SEPARATOR L"\\"
|
||||
|
||||
#else
|
||||
|
||||
#define CHAR_PATH_SEPARATOR '/'
|
||||
#define WCHAR_PATH_SEPARATOR L'/'
|
||||
#define STRING_PATH_SEPARATOR "/"
|
||||
#define WSTRING_PATH_SEPARATOR L"/"
|
||||
|
||||
#endif
|
||||
|
||||
EXTERN_C_END
|
||||
|
||||
#endif
|
||||
/* Types.h -- Basic types
|
||||
2010-10-09 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __7Z_TYPES_H
|
||||
#define __7Z_TYPES_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#ifndef EXTERN_C_BEGIN
|
||||
#ifdef __cplusplus
|
||||
#define EXTERN_C_BEGIN extern "C" {
|
||||
#define EXTERN_C_END }
|
||||
#else
|
||||
#define EXTERN_C_BEGIN
|
||||
#define EXTERN_C_END
|
||||
#endif
|
||||
#endif
|
||||
|
||||
EXTERN_C_BEGIN
|
||||
|
||||
#define SZ_OK 0
|
||||
|
||||
#define SZ_ERROR_DATA 1
|
||||
#define SZ_ERROR_MEM 2
|
||||
#define SZ_ERROR_CRC 3
|
||||
#define SZ_ERROR_UNSUPPORTED 4
|
||||
#define SZ_ERROR_PARAM 5
|
||||
#define SZ_ERROR_INPUT_EOF 6
|
||||
#define SZ_ERROR_OUTPUT_EOF 7
|
||||
#define SZ_ERROR_READ 8
|
||||
#define SZ_ERROR_WRITE 9
|
||||
#define SZ_ERROR_PROGRESS 10
|
||||
#define SZ_ERROR_FAIL 11
|
||||
#define SZ_ERROR_THREAD 12
|
||||
|
||||
#define SZ_ERROR_ARCHIVE 16
|
||||
#define SZ_ERROR_NO_ARCHIVE 17
|
||||
|
||||
typedef int SRes;
|
||||
|
||||
#ifdef _WIN32
|
||||
typedef DWORD WRes;
|
||||
#else
|
||||
typedef int WRes;
|
||||
#endif
|
||||
|
||||
#ifndef RINOK
|
||||
#define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; }
|
||||
#endif
|
||||
|
||||
typedef unsigned char Byte;
|
||||
typedef short Int16;
|
||||
typedef unsigned short UInt16;
|
||||
|
||||
#ifdef _LZMA_UINT32_IS_ULONG
|
||||
typedef long Int32;
|
||||
typedef unsigned long UInt32;
|
||||
#else
|
||||
typedef int Int32;
|
||||
typedef unsigned int UInt32;
|
||||
#endif
|
||||
|
||||
#ifdef _SZ_NO_INT_64
|
||||
|
||||
/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers.
|
||||
NOTES: Some code will work incorrectly in that case! */
|
||||
|
||||
typedef long Int64;
|
||||
typedef unsigned long UInt64;
|
||||
|
||||
#else
|
||||
|
||||
#if defined(_MSC_VER) || defined(__BORLANDC__)
|
||||
typedef __int64 Int64;
|
||||
typedef unsigned __int64 UInt64;
|
||||
#define UINT64_CONST(n) n
|
||||
#else
|
||||
typedef long long int Int64;
|
||||
typedef unsigned long long int UInt64;
|
||||
#define UINT64_CONST(n) n ## ULL
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef _LZMA_NO_SYSTEM_SIZE_T
|
||||
typedef UInt32 SizeT;
|
||||
#else
|
||||
typedef size_t SizeT;
|
||||
#endif
|
||||
|
||||
typedef int Bool;
|
||||
#define True 1
|
||||
#define False 0
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
#define MY_STD_CALL __stdcall
|
||||
#else
|
||||
#define MY_STD_CALL
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#if _MSC_VER >= 1300
|
||||
#define MY_NO_INLINE __declspec(noinline)
|
||||
#else
|
||||
#define MY_NO_INLINE
|
||||
#endif
|
||||
|
||||
#define MY_CDECL __cdecl
|
||||
#define MY_FAST_CALL __fastcall
|
||||
|
||||
#else
|
||||
|
||||
#define MY_CDECL
|
||||
#define MY_FAST_CALL
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* The following interfaces use first parameter as pointer to structure */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Byte (*Read)(void *p); /* reads one byte, returns 0 in case of EOF or error */
|
||||
} IByteIn;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void (*Write)(void *p, Byte b);
|
||||
} IByteOut;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SRes (*Read)(void *p, void *buf, size_t *size);
|
||||
/* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
|
||||
(output(*size) < input(*size)) is allowed */
|
||||
} ISeqInStream;
|
||||
|
||||
/* it can return SZ_ERROR_INPUT_EOF */
|
||||
SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size);
|
||||
SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType);
|
||||
SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
size_t (*Write)(void *p, const void *buf, size_t size);
|
||||
/* Returns: result - the number of actually written bytes.
|
||||
(result < size) means error */
|
||||
} ISeqOutStream;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SZ_SEEK_SET = 0,
|
||||
SZ_SEEK_CUR = 1,
|
||||
SZ_SEEK_END = 2
|
||||
} ESzSeek;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SRes (*Read)(void *p, void *buf, size_t *size); /* same as ISeqInStream::Read */
|
||||
SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin);
|
||||
} ISeekInStream;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SRes (*Look)(void *p, const void **buf, size_t *size);
|
||||
/* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
|
||||
(output(*size) > input(*size)) is not allowed
|
||||
(output(*size) < input(*size)) is allowed */
|
||||
SRes (*Skip)(void *p, size_t offset);
|
||||
/* offset must be <= output(*size) of Look */
|
||||
|
||||
SRes (*Read)(void *p, void *buf, size_t *size);
|
||||
/* reads directly (without buffer). It's same as ISeqInStream::Read */
|
||||
SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin);
|
||||
} ILookInStream;
|
||||
|
||||
SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size);
|
||||
SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset);
|
||||
|
||||
/* reads via ILookInStream::Read */
|
||||
SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType);
|
||||
SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size);
|
||||
|
||||
#define LookToRead_BUF_SIZE (1 << 14)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ILookInStream s;
|
||||
ISeekInStream *realStream;
|
||||
size_t pos;
|
||||
size_t size;
|
||||
Byte buf[LookToRead_BUF_SIZE];
|
||||
} CLookToRead;
|
||||
|
||||
void LookToRead_CreateVTable(CLookToRead *p, int lookahead);
|
||||
void LookToRead_Init(CLookToRead *p);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ISeqInStream s;
|
||||
ILookInStream *realStream;
|
||||
} CSecToLook;
|
||||
|
||||
void SecToLook_CreateVTable(CSecToLook *p);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ISeqInStream s;
|
||||
ILookInStream *realStream;
|
||||
} CSecToRead;
|
||||
|
||||
void SecToRead_CreateVTable(CSecToRead *p);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize);
|
||||
/* Returns: result. (result != SZ_OK) means break.
|
||||
Value (UInt64)(Int64)-1 for size means unknown value. */
|
||||
} ICompressProgress;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void *(*Alloc)(void *p, size_t size);
|
||||
void (*Free)(void *p, void *address); /* address can be 0 */
|
||||
} ISzAlloc;
|
||||
|
||||
#define IAlloc_Alloc(p, size) (p)->Alloc((p), size)
|
||||
#define IAlloc_Free(p, a) (p)->Free((p), a)
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#define CHAR_PATH_SEPARATOR '\\'
|
||||
#define WCHAR_PATH_SEPARATOR L'\\'
|
||||
#define STRING_PATH_SEPARATOR "\\"
|
||||
#define WSTRING_PATH_SEPARATOR L"\\"
|
||||
|
||||
#else
|
||||
|
||||
#define CHAR_PATH_SEPARATOR '/'
|
||||
#define WCHAR_PATH_SEPARATOR L'/'
|
||||
#define STRING_PATH_SEPARATOR "/"
|
||||
#define WSTRING_PATH_SEPARATOR L"/"
|
||||
|
||||
#endif
|
||||
|
||||
EXTERN_C_END
|
||||
|
||||
#endif
|
||||
|
|
1188
fex/7z_C/lzma.txt
1188
fex/7z_C/lzma.txt
File diff suppressed because it is too large
Load Diff
142
fex/changes.txt
142
fex/changes.txt
|
@ -1,71 +1,71 @@
|
|||
File_Extractor Change Log
|
||||
-------------------------
|
||||
- Change that might break code.
|
||||
+ Improvement that is unlikely to break any code.
|
||||
* Other changes.
|
||||
|
||||
|
||||
File_Extractor 1.0.0 (2009-10-12)
|
||||
--------------------
|
||||
- Added fex_stat() which MUST be called before getting current file
|
||||
information beyond name, like fex_size().
|
||||
|
||||
- Changed fex_*() functions to always report error via return value,
|
||||
rather than sometimes via a parameter. This will break user code that
|
||||
uses fex_data(), fex_open(), fex_open_type(), and fex_identify_file().
|
||||
See demos for usage.
|
||||
|
||||
- Deprecated C++ interface. Use fex.h and nothing else to access library
|
||||
from user code.
|
||||
|
||||
- Removed archive types (fex_zip_type, etc.) from interface. Use
|
||||
fex_identify_extension() to get particular type.
|
||||
|
||||
- Removed fex_mini.c, unzip.h, and unrarlib.h for now, as maintaining
|
||||
them was too taxing. If others express desire for them, I can re-add
|
||||
them.
|
||||
|
||||
- Removed fex_scan_only() and fex_read_once(), as they don't improve
|
||||
performance anymore. Use fex_read() in place of fex_read_once().
|
||||
|
||||
- Removed fex_remain(). Use fex_size()-fex_tell() to find number of
|
||||
bytes remaining.
|
||||
|
||||
- Removed fex_set_user_data() and related functions, as they didn't seem
|
||||
useful to anyone.
|
||||
|
||||
- Removed fex_type_t structure from interface and added accessors
|
||||
instead (fex_type_name(), fex_type_extension()).
|
||||
|
||||
+ Improved archive file type determination to reject other archive types
|
||||
not handled by the library, rather than opening them as binary files.
|
||||
|
||||
+ Added Doxygen compatibility to fex.h.
|
||||
|
||||
+ Added fex_crc32() to quickly get CRC-32 of current file from archive
|
||||
header, without having to read entire file to calculate it.
|
||||
|
||||
+ Added fex_err_code() to get numeric error code, along with other
|
||||
helpful error-related functions. Also added more documentation on how to
|
||||
handle library errors in user code.
|
||||
|
||||
+ Added fex_init() for use in multi-threaded programs.
|
||||
|
||||
+ Added fex_seek_arc() to seek to particular file in archive.
|
||||
|
||||
+ Added fex_wname() to get Unicode name of current file.
|
||||
|
||||
+ Added support for building as DLL.
|
||||
|
||||
+ Added support for wide-character file paths on Windows, enabled with
|
||||
BLARGG_UTF8_PATHS (thanks to byuu for the idea). This is necessary to
|
||||
support file paths on non-English Windows systems.
|
||||
|
||||
+ Started using unit testing during development.
|
||||
|
||||
+ Updated to 7-zip 4.65, unrar_core 3.8.5.
|
||||
|
||||
|
||||
File_Extractor 0.4.3 (2008-12-08)
|
||||
--------------------
|
||||
* Limited release
|
||||
File_Extractor Change Log
|
||||
-------------------------
|
||||
- Change that might break code.
|
||||
+ Improvement that is unlikely to break any code.
|
||||
* Other changes.
|
||||
|
||||
|
||||
File_Extractor 1.0.0 (2009-10-12)
|
||||
--------------------
|
||||
- Added fex_stat() which MUST be called before getting current file
|
||||
information beyond name, like fex_size().
|
||||
|
||||
- Changed fex_*() functions to always report error via return value,
|
||||
rather than sometimes via a parameter. This will break user code that
|
||||
uses fex_data(), fex_open(), fex_open_type(), and fex_identify_file().
|
||||
See demos for usage.
|
||||
|
||||
- Deprecated C++ interface. Use fex.h and nothing else to access library
|
||||
from user code.
|
||||
|
||||
- Removed archive types (fex_zip_type, etc.) from interface. Use
|
||||
fex_identify_extension() to get particular type.
|
||||
|
||||
- Removed fex_mini.c, unzip.h, and unrarlib.h for now, as maintaining
|
||||
them was too taxing. If others express desire for them, I can re-add
|
||||
them.
|
||||
|
||||
- Removed fex_scan_only() and fex_read_once(), as they don't improve
|
||||
performance anymore. Use fex_read() in place of fex_read_once().
|
||||
|
||||
- Removed fex_remain(). Use fex_size()-fex_tell() to find number of
|
||||
bytes remaining.
|
||||
|
||||
- Removed fex_set_user_data() and related functions, as they didn't seem
|
||||
useful to anyone.
|
||||
|
||||
- Removed fex_type_t structure from interface and added accessors
|
||||
instead (fex_type_name(), fex_type_extension()).
|
||||
|
||||
+ Improved archive file type determination to reject other archive types
|
||||
not handled by the library, rather than opening them as binary files.
|
||||
|
||||
+ Added Doxygen compatibility to fex.h.
|
||||
|
||||
+ Added fex_crc32() to quickly get CRC-32 of current file from archive
|
||||
header, without having to read entire file to calculate it.
|
||||
|
||||
+ Added fex_err_code() to get numeric error code, along with other
|
||||
helpful error-related functions. Also added more documentation on how to
|
||||
handle library errors in user code.
|
||||
|
||||
+ Added fex_init() for use in multi-threaded programs.
|
||||
|
||||
+ Added fex_seek_arc() to seek to particular file in archive.
|
||||
|
||||
+ Added fex_wname() to get Unicode name of current file.
|
||||
|
||||
+ Added support for building as DLL.
|
||||
|
||||
+ Added support for wide-character file paths on Windows, enabled with
|
||||
BLARGG_UTF8_PATHS (thanks to byuu for the idea). This is necessary to
|
||||
support file paths on non-English Windows systems.
|
||||
|
||||
+ Started using unit testing during development.
|
||||
|
||||
+ Updated to 7-zip 4.65, unrar_core 3.8.5.
|
||||
|
||||
|
||||
File_Extractor 0.4.3 (2008-12-08)
|
||||
--------------------
|
||||
* Limited release
|
||||
|
|
660
fex/fex.txt
660
fex/fex.txt
|
@ -1,330 +1,330 @@
|
|||
File_Extractor 1.0.0
|
||||
--------------------
|
||||
Author : Shay Green <gblargg@gmail.com>
|
||||
Website : http://code.google.com/p/file-extractor/
|
||||
License : GNU LGPL 2.1 or later for all except unrar
|
||||
Language: C interface, C++ implementation
|
||||
|
||||
|
||||
Contents
|
||||
--------
|
||||
* Overview
|
||||
* Limitations
|
||||
* Extracting file data
|
||||
* Archive file type handling
|
||||
* Using in multiple threads
|
||||
* Error handling
|
||||
* Solving problems
|
||||
* Thanks
|
||||
|
||||
|
||||
Overview
|
||||
--------
|
||||
File_Exactor (fex) allows you to write one version of file-opening code
|
||||
that handles normal files and archives of files. It presents each as a
|
||||
series of files that you can scan and optionally extract; a single file
|
||||
is made to act like an archive of just one file, so your code doesn't
|
||||
need to do anything special to handle it.
|
||||
|
||||
Basic steps for scanning and extracting from an archive:
|
||||
|
||||
* Open an archive or normal file using fex_open().
|
||||
* Scanning/extraction loop:
|
||||
- Exit loop if fex_done() returns true.
|
||||
- Get current file's name with fex_name().
|
||||
- If more file information is needed, call fex_stat() first.
|
||||
- If extracting, use fex_data() or fex_read().
|
||||
- Go to next file in archive with fex_next().
|
||||
* Close archive and free memory with fex_close().
|
||||
|
||||
You can stop scanning an archive at any point, for example once you've
|
||||
found the file you're looking for. If you need to go back to the first
|
||||
file, call fex_rewind() at any time. Be sure to check error codes
|
||||
returned by most functions.
|
||||
|
||||
|
||||
Limitations
|
||||
-----------
|
||||
All archives:
|
||||
* A file's checksum is verified only after ALL its data is extracted.
|
||||
* Encryption, segmentation, files larger than 2GB, and other extra
|
||||
features are not supported.
|
||||
|
||||
GZ archives:
|
||||
* Only gzip archives of a single file are supported. If it has multiple
|
||||
files, the reported size will be wrong. Multi-file gzip archives are
|
||||
very rare.
|
||||
|
||||
ZIP archives:
|
||||
* Supports files compressed using either deflation or store
|
||||
(uncompressed). Other compression schemes like BZip2 and Deflate64 are
|
||||
not supported.
|
||||
* Archive must have a valid directory structure at the end.
|
||||
|
||||
RAR archives:
|
||||
* Support for really old 1.x archives might not work. If you have some
|
||||
of these old archives, send them to me so I can test them.
|
||||
|
||||
7-zip:
|
||||
* Solid archives can currently use lots of memory when open.
|
||||
|
||||
|
||||
Extracting file data
|
||||
--------------------
|
||||
A file's data can be extracted with one or more calls to fex_read(), as
|
||||
you would read from a normal file. Use fex_tell() to find out how much
|
||||
has already been read. Use this if you need the data read into your own
|
||||
structure in memory.
|
||||
|
||||
File data can also be extracted to memory by the library with
|
||||
fex_data(). The pointer returned is valid only until you go to another
|
||||
file or close the archive, so this is only useful if you need to examine
|
||||
or process the data immediately and not keep it around for later.
|
||||
Archive extractors naturally keep a copy of the extracted data in memory
|
||||
already for solid archive types (currently 7-zip and RAR), so this
|
||||
function is optimized to avoid making a second copy of it in those
|
||||
cases.
|
||||
|
||||
Use fex_size() to find the size of the extracted data. Remember that
|
||||
fex_stat() or fex_data() must be called BEFORE calling fex_size().
|
||||
|
||||
|
||||
Archive file type handling
|
||||
--------------------------
|
||||
By default, fex uses the filename extension and header to determine
|
||||
archive type. If the filename extension is unrecognized or it lacks an
|
||||
extension, fex examines the first few bytes of the file. If still
|
||||
unrecognized, fex opens it as binary. Fex also checks for common archive
|
||||
types that it doesn't support, so that it can reject as unsupported them
|
||||
rather than unhelpfully opening them as binary.
|
||||
|
||||
Your file format might itself be an archive, for example your files end
|
||||
in ".rsn" yet are normal RAR archives, or they end in ".vgz" and are
|
||||
gzipped. This is why fex checks the headers of files with unknown
|
||||
filename extensions, rather than treating them as binary or rejecting
|
||||
them.
|
||||
|
||||
Type identification can be customized by using the various
|
||||
identification functions and fex_open_type(). For example, you could
|
||||
avoid the header check:
|
||||
|
||||
fex_t* fex;
|
||||
fex_type_t type = fex_identify_extension( path );
|
||||
if ( type == NULL )
|
||||
error( "Unsupported archive type" );
|
||||
|
||||
error( fex_open_type( &fex, path, type ) );
|
||||
|
||||
Note that you'll only get a NULL type for known archive type that fex
|
||||
doesn't handle; you won't get it for your own files, for example
|
||||
fex_identify_extension("myfile.foo") won't return NULL (unless for some
|
||||
reason you've disabled binary file support).
|
||||
|
||||
Use fex_type_list() to get a list of the types fex supports, for example
|
||||
to tell the user what archive types your program supports:
|
||||
|
||||
const fex_type_t* t;
|
||||
for ( t = fex_type_list(); *t; t++ )
|
||||
printf( "%s\n", fex_type_name( *t ) );
|
||||
|
||||
To get the fex_type_t for a particular archive type, use
|
||||
fex_identify_extension():
|
||||
|
||||
fex_type_t zip_type = fex_identify_extension( ".zip" );
|
||||
if ( zip_type == NULL )
|
||||
error( "ZIP isn't supported" );
|
||||
|
||||
Be sure to check the result as shown, rather than assuming the library
|
||||
supports a particular archive type. Use an extension of "" to get the
|
||||
type for binary files:
|
||||
|
||||
fex_type_t bin_type = fex_identify_extension( "" );
|
||||
if ( bin_type == NULL )
|
||||
error( "Binary files aren't supported?!?" );
|
||||
|
||||
|
||||
Using in multiple threads
|
||||
-------------------------
|
||||
Fex supports multi-threaded programs. If only one thread at a time is
|
||||
using the library, nothing special needs to be done. If more than one
|
||||
thread is using the library, the following must be done:
|
||||
|
||||
* Call fex_init() from the main thread and ensure it completes before
|
||||
any other threads use any fex functions. This initializes shared data
|
||||
tables used by the extractors.
|
||||
|
||||
* For each archive opened, only access it from one thread at a time.
|
||||
Different archives can be accessed from different threads without any
|
||||
synchronization, since fex uses no global variables. If the same archive
|
||||
must be accessed from multiple threads, all calls to any fex functions
|
||||
must be in critical section(s).
|
||||
|
||||
|
||||
Unicode file paths on Windows
|
||||
-----------------------------
|
||||
If using Windows and your program supports Unicode file paths, enable
|
||||
BLARGG_UTF8_PATHS in blargg_config.h, and convert your wide-character
|
||||
paths to UTF-8 before passing them to fex.h functions:
|
||||
|
||||
/* Wide-character path that could have come from system */
|
||||
wchar_t wide_path [] = L"demo.zip";
|
||||
|
||||
/* Convert from wide path and check for error */
|
||||
char* path = fex_wide_to_path( wide_path );
|
||||
if ( path == NULL )
|
||||
error( "Out of memory" );
|
||||
|
||||
/* Use converted path for fex call */
|
||||
error( fex_open( &fex, path ) );
|
||||
|
||||
/* Free memory used by path */
|
||||
fex_free_path( path );
|
||||
|
||||
The converted path can be used with any of the fex functions that take
|
||||
paths, for example fex_identify_extension() or fex_has_extension().
|
||||
|
||||
|
||||
Error handling
|
||||
--------------
|
||||
Most functions that can fail return fex_err_t, a pointer type. On
|
||||
failure they return a pointer to an error object, and on success they
|
||||
return NULL. Use fex_err_code() to get a conventional error code, or
|
||||
fex_err_str() to get a string suitable for reporting to the user.
|
||||
|
||||
There are two basic approches that your code can use to handle library
|
||||
errors. It can return errors, or report them and exit the function via
|
||||
some other means.
|
||||
|
||||
Your code can return errors as the library does, using fex_err_t:
|
||||
|
||||
#define RETURN_ERR( expr ) \
|
||||
do {\
|
||||
fex_err_t err = (expr);\
|
||||
if ( err != NULL )\
|
||||
return err;\
|
||||
} while ( 0 )
|
||||
|
||||
fex_err_t my_func()
|
||||
{
|
||||
RETURN_ERR( fex_foo() );
|
||||
RETURN_ERR( fex_bar() );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
If you have your own error codes, you can convert fex's errors to them:
|
||||
|
||||
// error codes that differ from library's
|
||||
enum {
|
||||
my_ok = 0,
|
||||
my_generic_error = 123,
|
||||
my_out_of_memory = 456,
|
||||
my_file_not_found = 789
|
||||
// ...
|
||||
};
|
||||
|
||||
int convert_error( fex_err_t err )
|
||||
{
|
||||
switch ( fex_err_code( err ) )
|
||||
{
|
||||
case fex_ok: return my_ok;
|
||||
case fex_err_generic: return my_generic_error;
|
||||
case fex_err_memory: return my_out_of_memory;
|
||||
case fex_err_file_missing: return my_file_not_found;
|
||||
// ...
|
||||
default: return my_generic_error;
|
||||
}
|
||||
}
|
||||
|
||||
#define RETURN_ERR( expr ) \
|
||||
do {\
|
||||
fex_err_t err = (expr);\
|
||||
if ( err != NULL )\
|
||||
return convert_error( err );\
|
||||
} while ( 0 )
|
||||
|
||||
int my_func()
|
||||
{
|
||||
RETURN_ERR( fex_foo() );
|
||||
RETURN_ERR( fex_bar() );
|
||||
return my_ok;
|
||||
}
|
||||
|
||||
The other approach is to pass all errors to an error handler function
|
||||
that never returns if passed a non-success error value:
|
||||
|
||||
// never returns if err != NULL
|
||||
void handle_error( fex_err_t err );
|
||||
|
||||
void my_func()
|
||||
{
|
||||
handle_error( fex_foo() );
|
||||
handle_error( fex_bar() );
|
||||
}
|
||||
|
||||
handle_error() could print the error and exit the program:
|
||||
|
||||
void handle_error( fex_err_t err )
|
||||
{
|
||||
if ( err != NULL )
|
||||
{
|
||||
const char* str = fex_err_str( err );
|
||||
printf( "Error: %s\n", str );
|
||||
exit( EXIT_FAILURE );
|
||||
}
|
||||
}
|
||||
|
||||
handle_error() could also throw a C++ exception (or equivalently in C,
|
||||
longmp() back to a setjmp() done inside caller()):
|
||||
|
||||
void handle_error( fex_err_t err )
|
||||
{
|
||||
switch ( fex_err_code( err ) )
|
||||
{
|
||||
case fex_ok: return;
|
||||
case fex_err_memory: throw std::bad_alloc();
|
||||
// ...
|
||||
case fex_err_generic:
|
||||
default:
|
||||
throw std::runtime_error( fex_err_str( err ) );
|
||||
}
|
||||
}
|
||||
|
||||
void caller()
|
||||
{
|
||||
try
|
||||
{
|
||||
my_func();
|
||||
}
|
||||
catch ( const std::exception& e )
|
||||
{
|
||||
printf( "Error: %s\n", e.what() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Solving problems
|
||||
----------------
|
||||
If you're having problems, try the following:
|
||||
|
||||
* Enable debugging support in your environment. This enables assertions
|
||||
and other run-time checks. In particular, be sure NDEBUG isn't defined.
|
||||
|
||||
* Turn the compiler's optimizer is off. Sometimes an optimizer generates
|
||||
bad code.
|
||||
|
||||
* If multiple threads are being used, ensure that only one at a time is
|
||||
accessing a given set of objects from the library. This library is not
|
||||
in general thread-safe, though independent objects can be used in
|
||||
separate threads.
|
||||
|
||||
* If all else fails, see if the demo works.
|
||||
|
||||
|
||||
Thanks
|
||||
------
|
||||
Thanks to Richard Bannister, Kode54, byuu, Cless, and DJRobX for testing
|
||||
and giving feedback for the library. Thanks to the authors of zlib,
|
||||
unrar, and 7-zip.
|
||||
|
||||
--
|
||||
Shay Green <gblargg@gmail.com>
|
||||
File_Extractor 1.0.0
|
||||
--------------------
|
||||
Author : Shay Green <gblargg@gmail.com>
|
||||
Website : http://code.google.com/p/file-extractor/
|
||||
License : GNU LGPL 2.1 or later for all except unrar
|
||||
Language: C interface, C++ implementation
|
||||
|
||||
|
||||
Contents
|
||||
--------
|
||||
* Overview
|
||||
* Limitations
|
||||
* Extracting file data
|
||||
* Archive file type handling
|
||||
* Using in multiple threads
|
||||
* Error handling
|
||||
* Solving problems
|
||||
* Thanks
|
||||
|
||||
|
||||
Overview
|
||||
--------
|
||||
File_Exactor (fex) allows you to write one version of file-opening code
|
||||
that handles normal files and archives of files. It presents each as a
|
||||
series of files that you can scan and optionally extract; a single file
|
||||
is made to act like an archive of just one file, so your code doesn't
|
||||
need to do anything special to handle it.
|
||||
|
||||
Basic steps for scanning and extracting from an archive:
|
||||
|
||||
* Open an archive or normal file using fex_open().
|
||||
* Scanning/extraction loop:
|
||||
- Exit loop if fex_done() returns true.
|
||||
- Get current file's name with fex_name().
|
||||
- If more file information is needed, call fex_stat() first.
|
||||
- If extracting, use fex_data() or fex_read().
|
||||
- Go to next file in archive with fex_next().
|
||||
* Close archive and free memory with fex_close().
|
||||
|
||||
You can stop scanning an archive at any point, for example once you've
|
||||
found the file you're looking for. If you need to go back to the first
|
||||
file, call fex_rewind() at any time. Be sure to check error codes
|
||||
returned by most functions.
|
||||
|
||||
|
||||
Limitations
|
||||
-----------
|
||||
All archives:
|
||||
* A file's checksum is verified only after ALL its data is extracted.
|
||||
* Encryption, segmentation, files larger than 2GB, and other extra
|
||||
features are not supported.
|
||||
|
||||
GZ archives:
|
||||
* Only gzip archives of a single file are supported. If it has multiple
|
||||
files, the reported size will be wrong. Multi-file gzip archives are
|
||||
very rare.
|
||||
|
||||
ZIP archives:
|
||||
* Supports files compressed using either deflation or store
|
||||
(uncompressed). Other compression schemes like BZip2 and Deflate64 are
|
||||
not supported.
|
||||
* Archive must have a valid directory structure at the end.
|
||||
|
||||
RAR archives:
|
||||
* Support for really old 1.x archives might not work. If you have some
|
||||
of these old archives, send them to me so I can test them.
|
||||
|
||||
7-zip:
|
||||
* Solid archives can currently use lots of memory when open.
|
||||
|
||||
|
||||
Extracting file data
|
||||
--------------------
|
||||
A file's data can be extracted with one or more calls to fex_read(), as
|
||||
you would read from a normal file. Use fex_tell() to find out how much
|
||||
has already been read. Use this if you need the data read into your own
|
||||
structure in memory.
|
||||
|
||||
File data can also be extracted to memory by the library with
|
||||
fex_data(). The pointer returned is valid only until you go to another
|
||||
file or close the archive, so this is only useful if you need to examine
|
||||
or process the data immediately and not keep it around for later.
|
||||
Archive extractors naturally keep a copy of the extracted data in memory
|
||||
already for solid archive types (currently 7-zip and RAR), so this
|
||||
function is optimized to avoid making a second copy of it in those
|
||||
cases.
|
||||
|
||||
Use fex_size() to find the size of the extracted data. Remember that
|
||||
fex_stat() or fex_data() must be called BEFORE calling fex_size().
|
||||
|
||||
|
||||
Archive file type handling
|
||||
--------------------------
|
||||
By default, fex uses the filename extension and header to determine
|
||||
archive type. If the filename extension is unrecognized or it lacks an
|
||||
extension, fex examines the first few bytes of the file. If still
|
||||
unrecognized, fex opens it as binary. Fex also checks for common archive
|
||||
types that it doesn't support, so that it can reject as unsupported them
|
||||
rather than unhelpfully opening them as binary.
|
||||
|
||||
Your file format might itself be an archive, for example your files end
|
||||
in ".rsn" yet are normal RAR archives, or they end in ".vgz" and are
|
||||
gzipped. This is why fex checks the headers of files with unknown
|
||||
filename extensions, rather than treating them as binary or rejecting
|
||||
them.
|
||||
|
||||
Type identification can be customized by using the various
|
||||
identification functions and fex_open_type(). For example, you could
|
||||
avoid the header check:
|
||||
|
||||
fex_t* fex;
|
||||
fex_type_t type = fex_identify_extension( path );
|
||||
if ( type == NULL )
|
||||
error( "Unsupported archive type" );
|
||||
|
||||
error( fex_open_type( &fex, path, type ) );
|
||||
|
||||
Note that you'll only get a NULL type for known archive type that fex
|
||||
doesn't handle; you won't get it for your own files, for example
|
||||
fex_identify_extension("myfile.foo") won't return NULL (unless for some
|
||||
reason you've disabled binary file support).
|
||||
|
||||
Use fex_type_list() to get a list of the types fex supports, for example
|
||||
to tell the user what archive types your program supports:
|
||||
|
||||
const fex_type_t* t;
|
||||
for ( t = fex_type_list(); *t; t++ )
|
||||
printf( "%s\n", fex_type_name( *t ) );
|
||||
|
||||
To get the fex_type_t for a particular archive type, use
|
||||
fex_identify_extension():
|
||||
|
||||
fex_type_t zip_type = fex_identify_extension( ".zip" );
|
||||
if ( zip_type == NULL )
|
||||
error( "ZIP isn't supported" );
|
||||
|
||||
Be sure to check the result as shown, rather than assuming the library
|
||||
supports a particular archive type. Use an extension of "" to get the
|
||||
type for binary files:
|
||||
|
||||
fex_type_t bin_type = fex_identify_extension( "" );
|
||||
if ( bin_type == NULL )
|
||||
error( "Binary files aren't supported?!?" );
|
||||
|
||||
|
||||
Using in multiple threads
|
||||
-------------------------
|
||||
Fex supports multi-threaded programs. If only one thread at a time is
|
||||
using the library, nothing special needs to be done. If more than one
|
||||
thread is using the library, the following must be done:
|
||||
|
||||
* Call fex_init() from the main thread and ensure it completes before
|
||||
any other threads use any fex functions. This initializes shared data
|
||||
tables used by the extractors.
|
||||
|
||||
* For each archive opened, only access it from one thread at a time.
|
||||
Different archives can be accessed from different threads without any
|
||||
synchronization, since fex uses no global variables. If the same archive
|
||||
must be accessed from multiple threads, all calls to any fex functions
|
||||
must be in critical section(s).
|
||||
|
||||
|
||||
Unicode file paths on Windows
|
||||
-----------------------------
|
||||
If using Windows and your program supports Unicode file paths, enable
|
||||
BLARGG_UTF8_PATHS in blargg_config.h, and convert your wide-character
|
||||
paths to UTF-8 before passing them to fex.h functions:
|
||||
|
||||
/* Wide-character path that could have come from system */
|
||||
wchar_t wide_path [] = L"demo.zip";
|
||||
|
||||
/* Convert from wide path and check for error */
|
||||
char* path = fex_wide_to_path( wide_path );
|
||||
if ( path == NULL )
|
||||
error( "Out of memory" );
|
||||
|
||||
/* Use converted path for fex call */
|
||||
error( fex_open( &fex, path ) );
|
||||
|
||||
/* Free memory used by path */
|
||||
fex_free_path( path );
|
||||
|
||||
The converted path can be used with any of the fex functions that take
|
||||
paths, for example fex_identify_extension() or fex_has_extension().
|
||||
|
||||
|
||||
Error handling
|
||||
--------------
|
||||
Most functions that can fail return fex_err_t, a pointer type. On
|
||||
failure they return a pointer to an error object, and on success they
|
||||
return NULL. Use fex_err_code() to get a conventional error code, or
|
||||
fex_err_str() to get a string suitable for reporting to the user.
|
||||
|
||||
There are two basic approches that your code can use to handle library
|
||||
errors. It can return errors, or report them and exit the function via
|
||||
some other means.
|
||||
|
||||
Your code can return errors as the library does, using fex_err_t:
|
||||
|
||||
#define RETURN_ERR( expr ) \
|
||||
do {\
|
||||
fex_err_t err = (expr);\
|
||||
if ( err != NULL )\
|
||||
return err;\
|
||||
} while ( 0 )
|
||||
|
||||
fex_err_t my_func()
|
||||
{
|
||||
RETURN_ERR( fex_foo() );
|
||||
RETURN_ERR( fex_bar() );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
If you have your own error codes, you can convert fex's errors to them:
|
||||
|
||||
// error codes that differ from library's
|
||||
enum {
|
||||
my_ok = 0,
|
||||
my_generic_error = 123,
|
||||
my_out_of_memory = 456,
|
||||
my_file_not_found = 789
|
||||
// ...
|
||||
};
|
||||
|
||||
int convert_error( fex_err_t err )
|
||||
{
|
||||
switch ( fex_err_code( err ) )
|
||||
{
|
||||
case fex_ok: return my_ok;
|
||||
case fex_err_generic: return my_generic_error;
|
||||
case fex_err_memory: return my_out_of_memory;
|
||||
case fex_err_file_missing: return my_file_not_found;
|
||||
// ...
|
||||
default: return my_generic_error;
|
||||
}
|
||||
}
|
||||
|
||||
#define RETURN_ERR( expr ) \
|
||||
do {\
|
||||
fex_err_t err = (expr);\
|
||||
if ( err != NULL )\
|
||||
return convert_error( err );\
|
||||
} while ( 0 )
|
||||
|
||||
int my_func()
|
||||
{
|
||||
RETURN_ERR( fex_foo() );
|
||||
RETURN_ERR( fex_bar() );
|
||||
return my_ok;
|
||||
}
|
||||
|
||||
The other approach is to pass all errors to an error handler function
|
||||
that never returns if passed a non-success error value:
|
||||
|
||||
// never returns if err != NULL
|
||||
void handle_error( fex_err_t err );
|
||||
|
||||
void my_func()
|
||||
{
|
||||
handle_error( fex_foo() );
|
||||
handle_error( fex_bar() );
|
||||
}
|
||||
|
||||
handle_error() could print the error and exit the program:
|
||||
|
||||
void handle_error( fex_err_t err )
|
||||
{
|
||||
if ( err != NULL )
|
||||
{
|
||||
const char* str = fex_err_str( err );
|
||||
printf( "Error: %s\n", str );
|
||||
exit( EXIT_FAILURE );
|
||||
}
|
||||
}
|
||||
|
||||
handle_error() could also throw a C++ exception (or equivalently in C,
|
||||
longmp() back to a setjmp() done inside caller()):
|
||||
|
||||
void handle_error( fex_err_t err )
|
||||
{
|
||||
switch ( fex_err_code( err ) )
|
||||
{
|
||||
case fex_ok: return;
|
||||
case fex_err_memory: throw std::bad_alloc();
|
||||
// ...
|
||||
case fex_err_generic:
|
||||
default:
|
||||
throw std::runtime_error( fex_err_str( err ) );
|
||||
}
|
||||
}
|
||||
|
||||
void caller()
|
||||
{
|
||||
try
|
||||
{
|
||||
my_func();
|
||||
}
|
||||
catch ( const std::exception& e )
|
||||
{
|
||||
printf( "Error: %s\n", e.what() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Solving problems
|
||||
----------------
|
||||
If you're having problems, try the following:
|
||||
|
||||
* Enable debugging support in your environment. This enables assertions
|
||||
and other run-time checks. In particular, be sure NDEBUG isn't defined.
|
||||
|
||||
* Turn the compiler's optimizer is off. Sometimes an optimizer generates
|
||||
bad code.
|
||||
|
||||
* If multiple threads are being used, ensure that only one at a time is
|
||||
accessing a given set of objects from the library. This library is not
|
||||
in general thread-safe, though independent objects can be used in
|
||||
separate threads.
|
||||
|
||||
* If all else fails, see if the demo works.
|
||||
|
||||
|
||||
Thanks
|
||||
------
|
||||
Thanks to Richard Bannister, Kode54, byuu, Cless, and DJRobX for testing
|
||||
and giving feedback for the library. Thanks to the authors of zlib,
|
||||
unrar, and 7-zip.
|
||||
|
||||
--
|
||||
Shay Green <gblargg@gmail.com>
|
||||
|
|
|
@ -1,77 +1,77 @@
|
|||
// File_Extractor 1.0.0. http://www.slack.net/~ant/
|
||||
|
||||
#include "Binary_Extractor.h"
|
||||
|
||||
/* Copyright (C) 2005-2009 Shay Green. This module is free software; you
|
||||
can redistribute it and/or modify it under the terms of the GNU Lesser
|
||||
General Public License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version. This
|
||||
module 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 Lesser General Public License for more
|
||||
details. You should have received a copy of the GNU Lesser General Public
|
||||
License along with this module; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
#include "blargg_source.h"
|
||||
|
||||
// TODO: could close file once data has been read into memory
|
||||
|
||||
static File_Extractor* new_binary()
|
||||
{
|
||||
return BLARGG_NEW Binary_Extractor;
|
||||
}
|
||||
|
||||
fex_type_t_ const fex_bin_type [1] = {{
|
||||
"",
|
||||
&new_binary,
|
||||
"file",
|
||||
NULL
|
||||
}};
|
||||
|
||||
Binary_Extractor::Binary_Extractor() :
|
||||
File_Extractor( fex_bin_type )
|
||||
{ }
|
||||
|
||||
Binary_Extractor::~Binary_Extractor()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
blargg_err_t Binary_Extractor::open_path_v()
|
||||
{
|
||||
set_name( arc_path() );
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
blargg_err_t Binary_Extractor::open_v()
|
||||
{
|
||||
set_name( arc_path() );
|
||||
set_info( arc().remain(), 0, 0 );
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
void Binary_Extractor::close_v()
|
||||
{ }
|
||||
|
||||
blargg_err_t Binary_Extractor::next_v()
|
||||
{
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
blargg_err_t Binary_Extractor::rewind_v()
|
||||
{
|
||||
return open_path_v();
|
||||
}
|
||||
|
||||
blargg_err_t Binary_Extractor::stat_v()
|
||||
{
|
||||
RETURN_ERR( open_arc_file() );
|
||||
RETURN_ERR( arc().seek( 0 ) );
|
||||
return open_v();
|
||||
}
|
||||
|
||||
blargg_err_t Binary_Extractor::extract_v( void* p, int n )
|
||||
{
|
||||
return arc().read( p, n );
|
||||
}
|
||||
// File_Extractor 1.0.0. http://www.slack.net/~ant/
|
||||
|
||||
#include "Binary_Extractor.h"
|
||||
|
||||
/* Copyright (C) 2005-2009 Shay Green. This module is free software; you
|
||||
can redistribute it and/or modify it under the terms of the GNU Lesser
|
||||
General Public License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version. This
|
||||
module 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 Lesser General Public License for more
|
||||
details. You should have received a copy of the GNU Lesser General Public
|
||||
License along with this module; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
#include "blargg_source.h"
|
||||
|
||||
// TODO: could close file once data has been read into memory
|
||||
|
||||
static File_Extractor* new_binary()
|
||||
{
|
||||
return BLARGG_NEW Binary_Extractor;
|
||||
}
|
||||
|
||||
fex_type_t_ const fex_bin_type [1] = {{
|
||||
"",
|
||||
&new_binary,
|
||||
"file",
|
||||
NULL
|
||||
}};
|
||||
|
||||
Binary_Extractor::Binary_Extractor() :
|
||||
File_Extractor( fex_bin_type )
|
||||
{ }
|
||||
|
||||
Binary_Extractor::~Binary_Extractor()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
blargg_err_t Binary_Extractor::open_path_v()
|
||||
{
|
||||
set_name( arc_path() );
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
blargg_err_t Binary_Extractor::open_v()
|
||||
{
|
||||
set_name( arc_path() );
|
||||
set_info( arc().remain(), 0, 0 );
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
void Binary_Extractor::close_v()
|
||||
{ }
|
||||
|
||||
blargg_err_t Binary_Extractor::next_v()
|
||||
{
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
blargg_err_t Binary_Extractor::rewind_v()
|
||||
{
|
||||
return open_path_v();
|
||||
}
|
||||
|
||||
blargg_err_t Binary_Extractor::stat_v()
|
||||
{
|
||||
RETURN_ERR( open_arc_file() );
|
||||
RETURN_ERR( arc().seek( 0 ) );
|
||||
return open_v();
|
||||
}
|
||||
|
||||
blargg_err_t Binary_Extractor::extract_v( void* p, int n )
|
||||
{
|
||||
return arc().read( p, n );
|
||||
}
|
||||
|
|
|
@ -1,26 +1,26 @@
|
|||
// Presents a single file as an "archive" of just that file.
|
||||
|
||||
// File_Extractor 1.0.0
|
||||
#ifndef BINARY_EXTRACTOR_H
|
||||
#define BINARY_EXTRACTOR_H
|
||||
|
||||
#include "File_Extractor.h"
|
||||
|
||||
class Binary_Extractor : public File_Extractor {
|
||||
public:
|
||||
Binary_Extractor();
|
||||
virtual ~Binary_Extractor();
|
||||
|
||||
protected:
|
||||
virtual blargg_err_t open_path_v();
|
||||
virtual blargg_err_t open_v();
|
||||
virtual void close_v();
|
||||
|
||||
virtual blargg_err_t next_v();
|
||||
virtual blargg_err_t rewind_v();
|
||||
|
||||
virtual blargg_err_t stat_v();
|
||||
virtual blargg_err_t extract_v( void*, int );
|
||||
};
|
||||
|
||||
#endif
|
||||
// Presents a single file as an "archive" of just that file.
|
||||
|
||||
// File_Extractor 1.0.0
|
||||
#ifndef BINARY_EXTRACTOR_H
|
||||
#define BINARY_EXTRACTOR_H
|
||||
|
||||
#include "File_Extractor.h"
|
||||
|
||||
class Binary_Extractor : public File_Extractor {
|
||||
public:
|
||||
Binary_Extractor();
|
||||
virtual ~Binary_Extractor();
|
||||
|
||||
protected:
|
||||
virtual blargg_err_t open_path_v();
|
||||
virtual blargg_err_t open_v();
|
||||
virtual void close_v();
|
||||
|
||||
virtual blargg_err_t next_v();
|
||||
virtual blargg_err_t rewind_v();
|
||||
|
||||
virtual blargg_err_t stat_v();
|
||||
virtual blargg_err_t extract_v( void*, int );
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,264 +1,264 @@
|
|||
// Lightweight interface for reading data from byte stream
|
||||
|
||||
// File_Extractor 1.0.0
|
||||
#ifndef DATA_READER_H
|
||||
#define DATA_READER_H
|
||||
|
||||
#include "blargg_common.h"
|
||||
|
||||
/* Some functions accept a long instead of int for convenience where caller has
|
||||
a long due to some other interface, and would otherwise have to get a warning,
|
||||
or cast it (and verify that it wasn't outside the range of an int).
|
||||
|
||||
To really support huge (>2GB) files, long isn't a solution, since there's no
|
||||
guarantee it's more than 32 bits. We'd need to use long long (if available), or
|
||||
something compiler-specific, and change all places file sizes or offsets are
|
||||
used. */
|
||||
|
||||
// Supports reading and finding out how many bytes are remaining
|
||||
class Data_Reader {
|
||||
public:
|
||||
|
||||
// Reads min(*n,remain()) bytes and sets *n to this number, thus trying to read more
|
||||
// tham remain() bytes doesn't result in error, just *n being set to remain().
|
||||
blargg_err_t read_avail( void* p, int* n );
|
||||
blargg_err_t read_avail( void* p, long* n );
|
||||
|
||||
// Reads exactly n bytes, or returns error if they couldn't ALL be read.
|
||||
// Reading past end of file results in blargg_err_file_eof.
|
||||
blargg_err_t read( void* p, int n );
|
||||
|
||||
// Number of bytes remaining until end of file
|
||||
int remain() const { return remain_; }
|
||||
|
||||
// Reads and discards n bytes. Skipping past end of file results in blargg_err_file_eof.
|
||||
blargg_err_t skip( int n );
|
||||
|
||||
virtual ~Data_Reader() { }
|
||||
|
||||
private:
|
||||
// noncopyable
|
||||
Data_Reader( const Data_Reader& );
|
||||
Data_Reader& operator = ( const Data_Reader& );
|
||||
|
||||
// Derived interface
|
||||
protected:
|
||||
Data_Reader() : remain_( 0 ) { }
|
||||
|
||||
// Sets remain
|
||||
void set_remain( int n ) { assert( n >= 0 ); remain_ = n; }
|
||||
|
||||
// Do same as read(). Guaranteed that 0 < n <= remain(). Value of remain() is updated
|
||||
// AFTER this call succeeds, not before. set_remain() should NOT be called from this.
|
||||
virtual blargg_err_t read_v( void*, int n ) BLARGG_PURE( { (void)n; return blargg_ok; } )
|
||||
|
||||
// Do same as skip(). Guaranteed that 0 < n <= remain(). Default just reads data
|
||||
// and discards it. Value of remain() is updated AFTER this call succeeds, not
|
||||
// before. set_remain() should NOT be called from this.
|
||||
virtual blargg_err_t skip_v( int n );
|
||||
|
||||
// Implementation
|
||||
public:
|
||||
BLARGG_DISABLE_NOTHROW
|
||||
|
||||
private:
|
||||
int remain_;
|
||||
};
|
||||
|
||||
|
||||
// Supports seeking in addition to Data_Reader operations
|
||||
class File_Reader : public Data_Reader {
|
||||
public:
|
||||
|
||||
// Size of file
|
||||
int size() const { return size_; }
|
||||
|
||||
// Current position in file
|
||||
int tell() const { return size_ - remain(); }
|
||||
|
||||
// Goes to new position
|
||||
blargg_err_t seek( int );
|
||||
|
||||
// Derived interface
|
||||
protected:
|
||||
// Sets size and resets position
|
||||
void set_size( int n ) { size_ = n; Data_Reader::set_remain( n ); }
|
||||
void set_size( long n ) { set_size( STATIC_CAST(int, n) ); }
|
||||
|
||||
// Sets reported position
|
||||
void set_tell( int i ) { assert( 0 <= i && i <= size_ ); Data_Reader::set_remain( size_ - i ); }
|
||||
|
||||
// Do same as seek(). Guaranteed that 0 <= n <= size(). Value of tell() is updated
|
||||
// AFTER this call succeeds, not before. set_* functions should NOT be called from this.
|
||||
virtual blargg_err_t seek_v( int n ) BLARGG_PURE( { (void)n; return blargg_ok; } )
|
||||
|
||||
// Implementation
|
||||
protected:
|
||||
File_Reader() : size_( 0 ) { }
|
||||
|
||||
virtual blargg_err_t skip_v( int );
|
||||
|
||||
private:
|
||||
int size_;
|
||||
|
||||
void set_remain(); // avoid accidental use of set_remain
|
||||
};
|
||||
|
||||
|
||||
// Reads from file on disk
|
||||
class Std_File_Reader : public File_Reader {
|
||||
public:
|
||||
|
||||
// Opens file
|
||||
blargg_err_t open( const char path [] );
|
||||
|
||||
// Closes file if one was open
|
||||
void close();
|
||||
|
||||
// Switches to unbuffered mode. Useful if buffering is already being
|
||||
// done at a higher level.
|
||||
void make_unbuffered();
|
||||
|
||||
// Implementation
|
||||
public:
|
||||
Std_File_Reader();
|
||||
virtual ~Std_File_Reader();
|
||||
|
||||
protected:
|
||||
virtual blargg_err_t read_v( void*, int );
|
||||
virtual blargg_err_t seek_v( int );
|
||||
|
||||
private:
|
||||
void* file_;
|
||||
};
|
||||
|
||||
|
||||
// Treats range of memory as a file
|
||||
class Mem_File_Reader : public File_Reader {
|
||||
public:
|
||||
|
||||
Mem_File_Reader( const void* begin, long size );
|
||||
|
||||
// Implementation
|
||||
protected:
|
||||
virtual blargg_err_t read_v( void*, int );
|
||||
virtual blargg_err_t seek_v( int );
|
||||
|
||||
private:
|
||||
const char* const begin;
|
||||
};
|
||||
|
||||
|
||||
// Allows only count bytes to be read from reader passed
|
||||
class Subset_Reader : public Data_Reader {
|
||||
public:
|
||||
|
||||
Subset_Reader( Data_Reader*, int count );
|
||||
|
||||
// Implementation
|
||||
protected:
|
||||
virtual blargg_err_t read_v( void*, int );
|
||||
|
||||
private:
|
||||
Data_Reader* const in;
|
||||
};
|
||||
|
||||
|
||||
// Joins already-read header and remaining data into original file.
|
||||
// Meant for cases where you've already read header and don't want
|
||||
// to seek and re-read data (for efficiency).
|
||||
class Remaining_Reader : public Data_Reader {
|
||||
public:
|
||||
|
||||
Remaining_Reader( void const* header, int header_size, Data_Reader* );
|
||||
|
||||
// Implementation
|
||||
protected:
|
||||
virtual blargg_err_t read_v( void*, int );
|
||||
|
||||
private:
|
||||
Data_Reader* const in;
|
||||
void const* header;
|
||||
int header_remain;
|
||||
};
|
||||
|
||||
|
||||
// Invokes callback function to read data
|
||||
extern "C" { // necessary to be usable from C
|
||||
typedef const char* (*callback_reader_func_t)(
|
||||
void* user_data, // Same value passed to constructor
|
||||
void* out, // Buffer to place data into
|
||||
int count // Number of bytes to read
|
||||
);
|
||||
}
|
||||
class Callback_Reader : public Data_Reader {
|
||||
public:
|
||||
typedef callback_reader_func_t callback_t;
|
||||
Callback_Reader( callback_t, long size, void* user_data );
|
||||
|
||||
// Implementation
|
||||
protected:
|
||||
virtual blargg_err_t read_v( void*, int );
|
||||
|
||||
private:
|
||||
callback_t const callback;
|
||||
void* const user_data;
|
||||
};
|
||||
|
||||
|
||||
// Invokes callback function to read data
|
||||
extern "C" { // necessary to be usable from C
|
||||
typedef const char* (*callback_file_reader_func_t)(
|
||||
void* user_data, // Same value passed to constructor
|
||||
void* out, // Buffer to place data into
|
||||
int count, // Number of bytes to read
|
||||
int pos // Position in file to read from
|
||||
);
|
||||
}
|
||||
class Callback_File_Reader : public File_Reader {
|
||||
public:
|
||||
typedef callback_file_reader_func_t callback_t;
|
||||
Callback_File_Reader( callback_t, long size, void* user_data );
|
||||
|
||||
// Implementation
|
||||
protected:
|
||||
virtual blargg_err_t read_v( void*, int );
|
||||
virtual blargg_err_t seek_v( int );
|
||||
|
||||
private:
|
||||
callback_t const callback;
|
||||
void* const user_data;
|
||||
};
|
||||
|
||||
|
||||
#ifdef HAVE_ZLIB_H
|
||||
|
||||
// Reads file compressed with gzip (or uncompressed)
|
||||
class Gzip_File_Reader : public File_Reader {
|
||||
public:
|
||||
|
||||
// Opens possibly gzipped file
|
||||
blargg_err_t open( const char path [] );
|
||||
|
||||
// Closes file if one was open
|
||||
void close();
|
||||
|
||||
// Implementation
|
||||
public:
|
||||
Gzip_File_Reader();
|
||||
~Gzip_File_Reader();
|
||||
|
||||
protected:
|
||||
virtual blargg_err_t read_v( void*, int );
|
||||
virtual blargg_err_t seek_v( int );
|
||||
|
||||
private:
|
||||
// void* so "zlib.h" doesn't have to be included here
|
||||
void* file_;
|
||||
};
|
||||
#endif
|
||||
|
||||
char* blargg_to_utf8( const wchar_t* );
|
||||
wchar_t* blargg_to_wide( const char* );
|
||||
|
||||
#endif
|
||||
// Lightweight interface for reading data from byte stream
|
||||
|
||||
// File_Extractor 1.0.0
|
||||
#ifndef DATA_READER_H
|
||||
#define DATA_READER_H
|
||||
|
||||
#include "blargg_common.h"
|
||||
|
||||
/* Some functions accept a long instead of int for convenience where caller has
|
||||
a long due to some other interface, and would otherwise have to get a warning,
|
||||
or cast it (and verify that it wasn't outside the range of an int).
|
||||
|
||||
To really support huge (>2GB) files, long isn't a solution, since there's no
|
||||
guarantee it's more than 32 bits. We'd need to use long long (if available), or
|
||||
something compiler-specific, and change all places file sizes or offsets are
|
||||
used. */
|
||||
|
||||
// Supports reading and finding out how many bytes are remaining
|
||||
class Data_Reader {
|
||||
public:
|
||||
|
||||
// Reads min(*n,remain()) bytes and sets *n to this number, thus trying to read more
|
||||
// tham remain() bytes doesn't result in error, just *n being set to remain().
|
||||
blargg_err_t read_avail( void* p, int* n );
|
||||
blargg_err_t read_avail( void* p, long* n );
|
||||
|
||||
// Reads exactly n bytes, or returns error if they couldn't ALL be read.
|
||||
// Reading past end of file results in blargg_err_file_eof.
|
||||
blargg_err_t read( void* p, int n );
|
||||
|
||||
// Number of bytes remaining until end of file
|
||||
int remain() const { return remain_; }
|
||||
|
||||
// Reads and discards n bytes. Skipping past end of file results in blargg_err_file_eof.
|
||||
blargg_err_t skip( int n );
|
||||
|
||||
virtual ~Data_Reader() { }
|
||||
|
||||
private:
|
||||
// noncopyable
|
||||
Data_Reader( const Data_Reader& );
|
||||
Data_Reader& operator = ( const Data_Reader& );
|
||||
|
||||
// Derived interface
|
||||
protected:
|
||||
Data_Reader() : remain_( 0 ) { }
|
||||
|
||||
// Sets remain
|
||||
void set_remain( int n ) { assert( n >= 0 ); remain_ = n; }
|
||||
|
||||
// Do same as read(). Guaranteed that 0 < n <= remain(). Value of remain() is updated
|
||||
// AFTER this call succeeds, not before. set_remain() should NOT be called from this.
|
||||
virtual blargg_err_t read_v( void*, int n ) BLARGG_PURE( { (void)n; return blargg_ok; } )
|
||||
|
||||
// Do same as skip(). Guaranteed that 0 < n <= remain(). Default just reads data
|
||||
// and discards it. Value of remain() is updated AFTER this call succeeds, not
|
||||
// before. set_remain() should NOT be called from this.
|
||||
virtual blargg_err_t skip_v( int n );
|
||||
|
||||
// Implementation
|
||||
public:
|
||||
BLARGG_DISABLE_NOTHROW
|
||||
|
||||
private:
|
||||
int remain_;
|
||||
};
|
||||
|
||||
|
||||
// Supports seeking in addition to Data_Reader operations
|
||||
class File_Reader : public Data_Reader {
|
||||
public:
|
||||
|
||||
// Size of file
|
||||
int size() const { return size_; }
|
||||
|
||||
// Current position in file
|
||||
int tell() const { return size_ - remain(); }
|
||||
|
||||
// Goes to new position
|
||||
blargg_err_t seek( int );
|
||||
|
||||
// Derived interface
|
||||
protected:
|
||||
// Sets size and resets position
|
||||
void set_size( int n ) { size_ = n; Data_Reader::set_remain( n ); }
|
||||
void set_size( long n ) { set_size( STATIC_CAST(int, n) ); }
|
||||
|
||||
// Sets reported position
|
||||
void set_tell( int i ) { assert( 0 <= i && i <= size_ ); Data_Reader::set_remain( size_ - i ); }
|
||||
|
||||
// Do same as seek(). Guaranteed that 0 <= n <= size(). Value of tell() is updated
|
||||
// AFTER this call succeeds, not before. set_* functions should NOT be called from this.
|
||||
virtual blargg_err_t seek_v( int n ) BLARGG_PURE( { (void)n; return blargg_ok; } )
|
||||
|
||||
// Implementation
|
||||
protected:
|
||||
File_Reader() : size_( 0 ) { }
|
||||
|
||||
virtual blargg_err_t skip_v( int );
|
||||
|
||||
private:
|
||||
int size_;
|
||||
|
||||
void set_remain(); // avoid accidental use of set_remain
|
||||
};
|
||||
|
||||
|
||||
// Reads from file on disk
|
||||
class Std_File_Reader : public File_Reader {
|
||||
public:
|
||||
|
||||
// Opens file
|
||||
blargg_err_t open( const char path [] );
|
||||
|
||||
// Closes file if one was open
|
||||
void close();
|
||||
|
||||
// Switches to unbuffered mode. Useful if buffering is already being
|
||||
// done at a higher level.
|
||||
void make_unbuffered();
|
||||
|
||||
// Implementation
|
||||
public:
|
||||
Std_File_Reader();
|
||||
virtual ~Std_File_Reader();
|
||||
|
||||
protected:
|
||||
virtual blargg_err_t read_v( void*, int );
|
||||
virtual blargg_err_t seek_v( int );
|
||||
|
||||
private:
|
||||
void* file_;
|
||||
};
|
||||
|
||||
|
||||
// Treats range of memory as a file
|
||||
class Mem_File_Reader : public File_Reader {
|
||||
public:
|
||||
|
||||
Mem_File_Reader( const void* begin, long size );
|
||||
|
||||
// Implementation
|
||||
protected:
|
||||
virtual blargg_err_t read_v( void*, int );
|
||||
virtual blargg_err_t seek_v( int );
|
||||
|
||||
private:
|
||||
const char* const begin;
|
||||
};
|
||||
|
||||
|
||||
// Allows only count bytes to be read from reader passed
|
||||
class Subset_Reader : public Data_Reader {
|
||||
public:
|
||||
|
||||
Subset_Reader( Data_Reader*, int count );
|
||||
|
||||
// Implementation
|
||||
protected:
|
||||
virtual blargg_err_t read_v( void*, int );
|
||||
|
||||
private:
|
||||
Data_Reader* const in;
|
||||
};
|
||||
|
||||
|
||||
// Joins already-read header and remaining data into original file.
|
||||
// Meant for cases where you've already read header and don't want
|
||||
// to seek and re-read data (for efficiency).
|
||||
class Remaining_Reader : public Data_Reader {
|
||||
public:
|
||||
|
||||
Remaining_Reader( void const* header, int header_size, Data_Reader* );
|
||||
|
||||
// Implementation
|
||||
protected:
|
||||
virtual blargg_err_t read_v( void*, int );
|
||||
|
||||
private:
|
||||
Data_Reader* const in;
|
||||
void const* header;
|
||||
int header_remain;
|
||||
};
|
||||
|
||||
|
||||
// Invokes callback function to read data
|
||||
extern "C" { // necessary to be usable from C
|
||||
typedef const char* (*callback_reader_func_t)(
|
||||
void* user_data, // Same value passed to constructor
|
||||
void* out, // Buffer to place data into
|
||||
int count // Number of bytes to read
|
||||
);
|
||||
}
|
||||
class Callback_Reader : public Data_Reader {
|
||||
public:
|
||||
typedef callback_reader_func_t callback_t;
|
||||
Callback_Reader( callback_t, long size, void* user_data );
|
||||
|
||||
// Implementation
|
||||
protected:
|
||||
virtual blargg_err_t read_v( void*, int );
|
||||
|
||||
private:
|
||||
callback_t const callback;
|
||||
void* const user_data;
|
||||
};
|
||||
|
||||
|
||||
// Invokes callback function to read data
|
||||
extern "C" { // necessary to be usable from C
|
||||
typedef const char* (*callback_file_reader_func_t)(
|
||||
void* user_data, // Same value passed to constructor
|
||||
void* out, // Buffer to place data into
|
||||
int count, // Number of bytes to read
|
||||
int pos // Position in file to read from
|
||||
);
|
||||
}
|
||||
class Callback_File_Reader : public File_Reader {
|
||||
public:
|
||||
typedef callback_file_reader_func_t callback_t;
|
||||
Callback_File_Reader( callback_t, long size, void* user_data );
|
||||
|
||||
// Implementation
|
||||
protected:
|
||||
virtual blargg_err_t read_v( void*, int );
|
||||
virtual blargg_err_t seek_v( int );
|
||||
|
||||
private:
|
||||
callback_t const callback;
|
||||
void* const user_data;
|
||||
};
|
||||
|
||||
|
||||
#ifdef HAVE_ZLIB_H
|
||||
|
||||
// Reads file compressed with gzip (or uncompressed)
|
||||
class Gzip_File_Reader : public File_Reader {
|
||||
public:
|
||||
|
||||
// Opens possibly gzipped file
|
||||
blargg_err_t open( const char path [] );
|
||||
|
||||
// Closes file if one was open
|
||||
void close();
|
||||
|
||||
// Implementation
|
||||
public:
|
||||
Gzip_File_Reader();
|
||||
~Gzip_File_Reader();
|
||||
|
||||
protected:
|
||||
virtual blargg_err_t read_v( void*, int );
|
||||
virtual blargg_err_t seek_v( int );
|
||||
|
||||
private:
|
||||
// void* so "zlib.h" doesn't have to be included here
|
||||
void* file_;
|
||||
};
|
||||
#endif
|
||||
|
||||
char* blargg_to_utf8( const wchar_t* );
|
||||
wchar_t* blargg_to_wide( const char* );
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,341 +1,341 @@
|
|||
// File_Extractor 1.0.0. http://www.slack.net/~ant/
|
||||
|
||||
#include "File_Extractor.h"
|
||||
|
||||
/* Copyright (C) 2005-2009 Shay Green. This module is free software; you
|
||||
can redistribute it and/or modify it under the terms of the GNU Lesser
|
||||
General Public License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version. This
|
||||
module 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 Lesser General Public License for more
|
||||
details. You should have received a copy of the GNU Lesser General Public
|
||||
License along with this module; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
#include "blargg_source.h"
|
||||
|
||||
File_Extractor::fex_t( fex_type_t t ) :
|
||||
type_( t )
|
||||
{
|
||||
own_file_ = NULL;
|
||||
|
||||
close_();
|
||||
}
|
||||
|
||||
// Open
|
||||
|
||||
blargg_err_t File_Extractor::set_path( const char* path )
|
||||
{
|
||||
if ( !path )
|
||||
path = "";
|
||||
|
||||
RETURN_ERR( path_.resize( strlen( path ) + 1 ) );
|
||||
memcpy( path_.begin(), path, path_.size() );
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
blargg_err_t File_Extractor::open( const char path [] )
|
||||
{
|
||||
close();
|
||||
|
||||
RETURN_ERR( set_path( path ) );
|
||||
|
||||
blargg_err_t err = open_path_v();
|
||||
if ( err )
|
||||
close();
|
||||
else
|
||||
opened_ = true;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
blargg_err_t File_Extractor::open_path_v()
|
||||
{
|
||||
RETURN_ERR( open_arc_file() );
|
||||
|
||||
return open_v();
|
||||
}
|
||||
|
||||
inline
|
||||
static void make_unbuffered( Std_File_Reader* r )
|
||||
{
|
||||
r->make_unbuffered();
|
||||
}
|
||||
|
||||
inline
|
||||
static void make_unbuffered( void* )
|
||||
{ }
|
||||
|
||||
blargg_err_t File_Extractor::open_arc_file( bool unbuffered )
|
||||
{
|
||||
if ( reader_ )
|
||||
return blargg_ok;
|
||||
|
||||
FEX_FILE_READER* in = BLARGG_NEW FEX_FILE_READER;
|
||||
CHECK_ALLOC( in );
|
||||
|
||||
blargg_err_t err = in->open( arc_path() );
|
||||
if ( err )
|
||||
{
|
||||
delete in;
|
||||
}
|
||||
else
|
||||
{
|
||||
reader_ = in;
|
||||
own_file();
|
||||
if ( unbuffered )
|
||||
make_unbuffered( in );
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
blargg_err_t File_Extractor::open( File_Reader* input, const char* path )
|
||||
{
|
||||
close();
|
||||
|
||||
RETURN_ERR( set_path( path ) );
|
||||
|
||||
RETURN_ERR( input->seek( 0 ) );
|
||||
|
||||
reader_ = input;
|
||||
blargg_err_t err = open_v();
|
||||
if ( err )
|
||||
close();
|
||||
else
|
||||
opened_ = true;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
// Close
|
||||
|
||||
void File_Extractor::close()
|
||||
{
|
||||
close_v();
|
||||
close_();
|
||||
}
|
||||
|
||||
void File_Extractor::close_()
|
||||
{
|
||||
delete own_file_;
|
||||
own_file_ = NULL;
|
||||
|
||||
tell_ = 0;
|
||||
reader_ = NULL;
|
||||
opened_ = false;
|
||||
|
||||
path_.clear();
|
||||
clear_file();
|
||||
}
|
||||
|
||||
File_Extractor::~fex_t()
|
||||
{
|
||||
check( !opened() ); // fails if derived destructor didn't call close()
|
||||
|
||||
delete own_file_;
|
||||
}
|
||||
|
||||
// Scanning
|
||||
|
||||
void File_Extractor::clear_file()
|
||||
{
|
||||
name_ = NULL;
|
||||
wname_ = NULL;
|
||||
done_ = true;
|
||||
stat_called = false;
|
||||
data_ptr_ = NULL;
|
||||
|
||||
set_info( 0 );
|
||||
own_data_.clear();
|
||||
clear_file_v();
|
||||
}
|
||||
|
||||
void File_Extractor::set_name( const char new_name [], const wchar_t* new_wname )
|
||||
{
|
||||
name_ = new_name;
|
||||
wname_ = new_wname;
|
||||
done_ = false;
|
||||
}
|
||||
|
||||
void File_Extractor::set_info( int new_size, unsigned date, unsigned crc )
|
||||
{
|
||||
size_ = new_size;
|
||||
date_ = (date != 0xFFFFFFFF ? date : 0);
|
||||
crc32_ = crc;
|
||||
set_remain( new_size );
|
||||
}
|
||||
|
||||
blargg_err_t File_Extractor::next_()
|
||||
{
|
||||
tell_++;
|
||||
clear_file();
|
||||
|
||||
blargg_err_t err = next_v();
|
||||
if ( err )
|
||||
clear_file();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
blargg_err_t File_Extractor::next()
|
||||
{
|
||||
assert( !done() );
|
||||
return next_();
|
||||
}
|
||||
|
||||
blargg_err_t File_Extractor::rewind()
|
||||
{
|
||||
assert( opened() );
|
||||
|
||||
tell_ = 0;
|
||||
clear_file();
|
||||
|
||||
blargg_err_t err = rewind_v();
|
||||
if ( err )
|
||||
clear_file();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
blargg_err_t File_Extractor::stat()
|
||||
{
|
||||
assert( !done() );
|
||||
|
||||
if ( !stat_called )
|
||||
{
|
||||
RETURN_ERR( stat_v() );
|
||||
stat_called = true;
|
||||
}
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
// Tell/seek
|
||||
|
||||
int const pos_offset = 1;
|
||||
|
||||
fex_pos_t File_Extractor::tell_arc() const
|
||||
{
|
||||
assert( opened() );
|
||||
|
||||
fex_pos_t pos = tell_arc_v();
|
||||
assert( pos >= 0 );
|
||||
|
||||
return pos + pos_offset;
|
||||
}
|
||||
|
||||
blargg_err_t File_Extractor::seek_arc( fex_pos_t pos )
|
||||
{
|
||||
assert( opened() );
|
||||
assert( pos != 0 );
|
||||
|
||||
clear_file();
|
||||
|
||||
blargg_err_t err = seek_arc_v( pos - pos_offset );
|
||||
if ( err )
|
||||
clear_file();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
fex_pos_t File_Extractor::tell_arc_v() const
|
||||
{
|
||||
return tell_;
|
||||
}
|
||||
|
||||
blargg_err_t File_Extractor::seek_arc_v( fex_pos_t pos )
|
||||
{
|
||||
// >= because seeking to current file should always reset read pointer etc.
|
||||
if ( tell_ >= pos )
|
||||
RETURN_ERR( rewind() );
|
||||
|
||||
while ( tell_ < pos )
|
||||
{
|
||||
RETURN_ERR( next_() );
|
||||
|
||||
if ( done() )
|
||||
{
|
||||
assert( false );
|
||||
return blargg_err_caller;
|
||||
}
|
||||
}
|
||||
|
||||
assert( tell_ == pos );
|
||||
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
// Extraction
|
||||
|
||||
blargg_err_t File_Extractor::rewind_file()
|
||||
{
|
||||
RETURN_ERR( stat() );
|
||||
|
||||
if ( tell() > 0 )
|
||||
{
|
||||
if ( data_ptr_ )
|
||||
{
|
||||
set_remain( size() );
|
||||
}
|
||||
else
|
||||
{
|
||||
RETURN_ERR( seek_arc( tell_arc() ) );
|
||||
RETURN_ERR( stat() );
|
||||
}
|
||||
}
|
||||
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
blargg_err_t File_Extractor::data( const void** data_out )
|
||||
{
|
||||
assert( !done() );
|
||||
|
||||
*data_out = NULL;
|
||||
if ( !data_ptr_ )
|
||||
{
|
||||
int old_tell = tell();
|
||||
|
||||
RETURN_ERR( rewind_file() );
|
||||
|
||||
void const* ptr;
|
||||
RETURN_ERR( data_v( &ptr ) );
|
||||
data_ptr_ = ptr;
|
||||
|
||||
// Now that data is in memory, we can seek by simply setting remain
|
||||
set_remain( size() - old_tell );
|
||||
}
|
||||
|
||||
*data_out = data_ptr_;
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
blargg_err_t File_Extractor::data_v( void const** out )
|
||||
{
|
||||
RETURN_ERR( own_data_.resize( size() ) );
|
||||
*out = own_data_.begin();
|
||||
|
||||
blargg_err_t err = extract_v( own_data_.begin(), own_data_.size() );
|
||||
if ( err )
|
||||
own_data_.clear();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
blargg_err_t File_Extractor::extract_v( void* out, int count )
|
||||
{
|
||||
void const* p;
|
||||
RETURN_ERR( data( &p ) );
|
||||
memcpy( out, STATIC_CAST(char const*,p) + (size() - remain()), count );
|
||||
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
blargg_err_t File_Extractor::read_v( void* out, int count )
|
||||
{
|
||||
if ( data_ptr_ )
|
||||
return File_Extractor::extract_v( out, count );
|
||||
|
||||
return extract_v( out, count );
|
||||
}
|
||||
// File_Extractor 1.0.0. http://www.slack.net/~ant/
|
||||
|
||||
#include "File_Extractor.h"
|
||||
|
||||
/* Copyright (C) 2005-2009 Shay Green. This module is free software; you
|
||||
can redistribute it and/or modify it under the terms of the GNU Lesser
|
||||
General Public License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version. This
|
||||
module 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 Lesser General Public License for more
|
||||
details. You should have received a copy of the GNU Lesser General Public
|
||||
License along with this module; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
#include "blargg_source.h"
|
||||
|
||||
File_Extractor::fex_t( fex_type_t t ) :
|
||||
type_( t )
|
||||
{
|
||||
own_file_ = NULL;
|
||||
|
||||
close_();
|
||||
}
|
||||
|
||||
// Open
|
||||
|
||||
blargg_err_t File_Extractor::set_path( const char* path )
|
||||
{
|
||||
if ( !path )
|
||||
path = "";
|
||||
|
||||
RETURN_ERR( path_.resize( strlen( path ) + 1 ) );
|
||||
memcpy( path_.begin(), path, path_.size() );
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
blargg_err_t File_Extractor::open( const char path [] )
|
||||
{
|
||||
close();
|
||||
|
||||
RETURN_ERR( set_path( path ) );
|
||||
|
||||
blargg_err_t err = open_path_v();
|
||||
if ( err )
|
||||
close();
|
||||
else
|
||||
opened_ = true;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
blargg_err_t File_Extractor::open_path_v()
|
||||
{
|
||||
RETURN_ERR( open_arc_file() );
|
||||
|
||||
return open_v();
|
||||
}
|
||||
|
||||
inline
|
||||
static void make_unbuffered( Std_File_Reader* r )
|
||||
{
|
||||
r->make_unbuffered();
|
||||
}
|
||||
|
||||
inline
|
||||
static void make_unbuffered( void* )
|
||||
{ }
|
||||
|
||||
blargg_err_t File_Extractor::open_arc_file( bool unbuffered )
|
||||
{
|
||||
if ( reader_ )
|
||||
return blargg_ok;
|
||||
|
||||
FEX_FILE_READER* in = BLARGG_NEW FEX_FILE_READER;
|
||||
CHECK_ALLOC( in );
|
||||
|
||||
blargg_err_t err = in->open( arc_path() );
|
||||
if ( err )
|
||||
{
|
||||
delete in;
|
||||
}
|
||||
else
|
||||
{
|
||||
reader_ = in;
|
||||
own_file();
|
||||
if ( unbuffered )
|
||||
make_unbuffered( in );
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
blargg_err_t File_Extractor::open( File_Reader* input, const char* path )
|
||||
{
|
||||
close();
|
||||
|
||||
RETURN_ERR( set_path( path ) );
|
||||
|
||||
RETURN_ERR( input->seek( 0 ) );
|
||||
|
||||
reader_ = input;
|
||||
blargg_err_t err = open_v();
|
||||
if ( err )
|
||||
close();
|
||||
else
|
||||
opened_ = true;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
// Close
|
||||
|
||||
void File_Extractor::close()
|
||||
{
|
||||
close_v();
|
||||
close_();
|
||||
}
|
||||
|
||||
void File_Extractor::close_()
|
||||
{
|
||||
delete own_file_;
|
||||
own_file_ = NULL;
|
||||
|
||||
tell_ = 0;
|
||||
reader_ = NULL;
|
||||
opened_ = false;
|
||||
|
||||
path_.clear();
|
||||
clear_file();
|
||||
}
|
||||
|
||||
File_Extractor::~fex_t()
|
||||
{
|
||||
check( !opened() ); // fails if derived destructor didn't call close()
|
||||
|
||||
delete own_file_;
|
||||
}
|
||||
|
||||
// Scanning
|
||||
|
||||
void File_Extractor::clear_file()
|
||||
{
|
||||
name_ = NULL;
|
||||
wname_ = NULL;
|
||||
done_ = true;
|
||||
stat_called = false;
|
||||
data_ptr_ = NULL;
|
||||
|
||||
set_info( 0 );
|
||||
own_data_.clear();
|
||||
clear_file_v();
|
||||
}
|
||||
|
||||
void File_Extractor::set_name( const char new_name [], const wchar_t* new_wname )
|
||||
{
|
||||
name_ = new_name;
|
||||
wname_ = new_wname;
|
||||
done_ = false;
|
||||
}
|
||||
|
||||
void File_Extractor::set_info( int new_size, unsigned date, unsigned crc )
|
||||
{
|
||||
size_ = new_size;
|
||||
date_ = (date != 0xFFFFFFFF ? date : 0);
|
||||
crc32_ = crc;
|
||||
set_remain( new_size );
|
||||
}
|
||||
|
||||
blargg_err_t File_Extractor::next_()
|
||||
{
|
||||
tell_++;
|
||||
clear_file();
|
||||
|
||||
blargg_err_t err = next_v();
|
||||
if ( err )
|
||||
clear_file();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
blargg_err_t File_Extractor::next()
|
||||
{
|
||||
assert( !done() );
|
||||
return next_();
|
||||
}
|
||||
|
||||
blargg_err_t File_Extractor::rewind()
|
||||
{
|
||||
assert( opened() );
|
||||
|
||||
tell_ = 0;
|
||||
clear_file();
|
||||
|
||||
blargg_err_t err = rewind_v();
|
||||
if ( err )
|
||||
clear_file();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
blargg_err_t File_Extractor::stat()
|
||||
{
|
||||
assert( !done() );
|
||||
|
||||
if ( !stat_called )
|
||||
{
|
||||
RETURN_ERR( stat_v() );
|
||||
stat_called = true;
|
||||
}
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
// Tell/seek
|
||||
|
||||
int const pos_offset = 1;
|
||||
|
||||
fex_pos_t File_Extractor::tell_arc() const
|
||||
{
|
||||
assert( opened() );
|
||||
|
||||
fex_pos_t pos = tell_arc_v();
|
||||
assert( pos >= 0 );
|
||||
|
||||
return pos + pos_offset;
|
||||
}
|
||||
|
||||
blargg_err_t File_Extractor::seek_arc( fex_pos_t pos )
|
||||
{
|
||||
assert( opened() );
|
||||
assert( pos != 0 );
|
||||
|
||||
clear_file();
|
||||
|
||||
blargg_err_t err = seek_arc_v( pos - pos_offset );
|
||||
if ( err )
|
||||
clear_file();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
fex_pos_t File_Extractor::tell_arc_v() const
|
||||
{
|
||||
return tell_;
|
||||
}
|
||||
|
||||
blargg_err_t File_Extractor::seek_arc_v( fex_pos_t pos )
|
||||
{
|
||||
// >= because seeking to current file should always reset read pointer etc.
|
||||
if ( tell_ >= pos )
|
||||
RETURN_ERR( rewind() );
|
||||
|
||||
while ( tell_ < pos )
|
||||
{
|
||||
RETURN_ERR( next_() );
|
||||
|
||||
if ( done() )
|
||||
{
|
||||
assert( false );
|
||||
return blargg_err_caller;
|
||||
}
|
||||
}
|
||||
|
||||
assert( tell_ == pos );
|
||||
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
// Extraction
|
||||
|
||||
blargg_err_t File_Extractor::rewind_file()
|
||||
{
|
||||
RETURN_ERR( stat() );
|
||||
|
||||
if ( tell() > 0 )
|
||||
{
|
||||
if ( data_ptr_ )
|
||||
{
|
||||
set_remain( size() );
|
||||
}
|
||||
else
|
||||
{
|
||||
RETURN_ERR( seek_arc( tell_arc() ) );
|
||||
RETURN_ERR( stat() );
|
||||
}
|
||||
}
|
||||
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
blargg_err_t File_Extractor::data( const void** data_out )
|
||||
{
|
||||
assert( !done() );
|
||||
|
||||
*data_out = NULL;
|
||||
if ( !data_ptr_ )
|
||||
{
|
||||
int old_tell = tell();
|
||||
|
||||
RETURN_ERR( rewind_file() );
|
||||
|
||||
void const* ptr;
|
||||
RETURN_ERR( data_v( &ptr ) );
|
||||
data_ptr_ = ptr;
|
||||
|
||||
// Now that data is in memory, we can seek by simply setting remain
|
||||
set_remain( size() - old_tell );
|
||||
}
|
||||
|
||||
*data_out = data_ptr_;
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
blargg_err_t File_Extractor::data_v( void const** out )
|
||||
{
|
||||
RETURN_ERR( own_data_.resize( size() ) );
|
||||
*out = own_data_.begin();
|
||||
|
||||
blargg_err_t err = extract_v( own_data_.begin(), own_data_.size() );
|
||||
if ( err )
|
||||
own_data_.clear();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
blargg_err_t File_Extractor::extract_v( void* out, int count )
|
||||
{
|
||||
void const* p;
|
||||
RETURN_ERR( data( &p ) );
|
||||
memcpy( out, STATIC_CAST(char const*,p) + (size() - remain()), count );
|
||||
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
blargg_err_t File_Extractor::read_v( void* out, int count )
|
||||
{
|
||||
if ( data_ptr_ )
|
||||
return File_Extractor::extract_v( out, count );
|
||||
|
||||
return extract_v( out, count );
|
||||
}
|
||||
|
|
|
@ -1,191 +1,191 @@
|
|||
// Compressed file archive interface
|
||||
|
||||
// File_Extractor 1.0.0
|
||||
#ifndef FILE_EXTRACTOR_H
|
||||
#define FILE_EXTRACTOR_H
|
||||
|
||||
#include "blargg_common.h"
|
||||
#include "Data_Reader.h"
|
||||
#include "fex.h"
|
||||
|
||||
struct fex_t : private Data_Reader {
|
||||
public:
|
||||
virtual ~fex_t();
|
||||
|
||||
// Open/close
|
||||
|
||||
// Opens archive from custom data source. Keeps pointer until close().
|
||||
blargg_err_t open( File_Reader* input, const char* path = NULL );
|
||||
|
||||
// Takes ownership of File_Reader* passed to open(), so that close()
|
||||
// will delete it.
|
||||
void own_file() { own_file_ = reader_; }
|
||||
|
||||
// See fex.h
|
||||
blargg_err_t open( const char path [] );
|
||||
fex_type_t type() const { return type_; }
|
||||
void close();
|
||||
|
||||
// Scanning
|
||||
|
||||
// See fex.h
|
||||
bool done() const { return done_; }
|
||||
blargg_err_t next();
|
||||
blargg_err_t rewind();
|
||||
fex_pos_t tell_arc() const;
|
||||
blargg_err_t seek_arc( fex_pos_t );
|
||||
|
||||
// Info
|
||||
|
||||
// See fex.h
|
||||
const char* name() const { return name_; }
|
||||
const wchar_t* wname() const { return wname_; }
|
||||
blargg_err_t stat();
|
||||
int size() const { assert( stat_called ); return size_; }
|
||||
unsigned int dos_date() const { return date_; }
|
||||
unsigned int crc32() const { return crc32_; }
|
||||
|
||||
// Extraction
|
||||
|
||||
// Data_Reader to current file's data, so standard Data_Reader interface can
|
||||
// be used, rather than having to treat archives specially. stat() must have
|
||||
// been called.
|
||||
Data_Reader& reader() { assert( stat_called ); return *this; }
|
||||
|
||||
// See fex.h
|
||||
blargg_err_t data( const void** data_out );
|
||||
int tell() const { return size_ - remain(); }
|
||||
|
||||
// Derived interface
|
||||
protected:
|
||||
|
||||
// Sets type of object
|
||||
fex_t( fex_type_t );
|
||||
|
||||
// Path to archive file, or "" if none supplied
|
||||
const char* arc_path() const { return path_.begin(); }
|
||||
|
||||
// Opens archive file if it's not already. If unbuffered is true, opens file
|
||||
// without any buffering.
|
||||
blargg_err_t open_arc_file( bool unbuffered = false );
|
||||
|
||||
// Archive file
|
||||
File_Reader& arc() const { return *reader_; }
|
||||
|
||||
// Sets current file name
|
||||
void set_name( const char name [], const wchar_t* wname = NULL );
|
||||
|
||||
// Sets current file information
|
||||
void set_info( int size, unsigned date = 0, unsigned crc = 0 );
|
||||
|
||||
// User overrides
|
||||
|
||||
// Overrides must do indicated task. Non-pure functions have reasonable default
|
||||
// implementation. Overrides should avoid calling public functions like
|
||||
// next() and rewind().
|
||||
|
||||
// Open archive using file_path(). OK to delay actual file opening until later.
|
||||
// Default just calls open_arc_file(), then open_v().
|
||||
virtual blargg_err_t open_path_v();
|
||||
|
||||
// Open archive using file() for source data. If unsupported, return error.
|
||||
virtual blargg_err_t open_v() BLARGG_PURE( ; )
|
||||
|
||||
// Go to next file in archive and call set_name() and optionally set_info()
|
||||
virtual blargg_err_t next_v() BLARGG_PURE( ; )
|
||||
|
||||
// Go back to first file in archive
|
||||
virtual blargg_err_t rewind_v() BLARGG_PURE( ; )
|
||||
|
||||
// Close archive. Called even if open_path_v() or open_v() return unsuccessfully.
|
||||
virtual void close_v() BLARGG_PURE( ; )
|
||||
|
||||
// Clear any fields related to current file
|
||||
virtual void clear_file_v() { }
|
||||
|
||||
// Call set_info() if not already called by next_v()
|
||||
virtual blargg_err_t stat_v() { return blargg_ok; }
|
||||
|
||||
// Return value that allows later return to this file. Result must be >= 0.
|
||||
virtual fex_pos_t tell_arc_v() const;
|
||||
|
||||
// Return to previously saved position
|
||||
virtual blargg_err_t seek_arc_v( fex_pos_t );
|
||||
|
||||
// One or both of the following must be overridden
|
||||
|
||||
// Provide pointer to data for current file in archive
|
||||
virtual blargg_err_t data_v( const void** out );
|
||||
|
||||
// Extract next n bytes
|
||||
virtual blargg_err_t extract_v( void* out, int n );
|
||||
|
||||
// Implementation
|
||||
public:
|
||||
BLARGG_DISABLE_NOTHROW
|
||||
|
||||
private:
|
||||
fex_type_t const type_;
|
||||
|
||||
// Archive file
|
||||
blargg_vector<char> path_;
|
||||
File_Reader* reader_;
|
||||
File_Reader* own_file_;
|
||||
bool opened_;
|
||||
|
||||
// Position in archive
|
||||
fex_pos_t tell_; // only used by default implementation of tell/seek
|
||||
bool done_;
|
||||
|
||||
// Info for current file in archive
|
||||
const char* name_;
|
||||
const wchar_t* wname_;
|
||||
unsigned date_;
|
||||
unsigned crc32_;
|
||||
int size_;
|
||||
bool stat_called;
|
||||
|
||||
// Current file contents
|
||||
void const* data_ptr_; // NULL if not read into memory
|
||||
blargg_vector<char> own_data_;
|
||||
|
||||
bool opened() const { return opened_; }
|
||||
void clear_file();
|
||||
void close_();
|
||||
blargg_err_t set_path( const char* path );
|
||||
blargg_err_t rewind_file();
|
||||
blargg_err_t next_();
|
||||
|
||||
// Data_Reader overrides
|
||||
// TODO: override skip_v?
|
||||
virtual blargg_err_t read_v( void* out, int n );
|
||||
};
|
||||
|
||||
struct fex_type_t_
|
||||
{
|
||||
const char* extension;
|
||||
File_Extractor* (*new_fex)();
|
||||
const char* name;
|
||||
blargg_err_t (*init)(); // Called by fex_init(). Can be NULL.
|
||||
};
|
||||
|
||||
extern const fex_type_t_
|
||||
fex_7z_type [1],
|
||||
fex_gz_type [1],
|
||||
fex_rar_type [1],
|
||||
fex_zip_type [1],
|
||||
fex_bin_type [1];
|
||||
|
||||
inline blargg_err_t File_Extractor::open_v() { return blargg_ok; }
|
||||
inline blargg_err_t File_Extractor::next_v() { return blargg_ok; }
|
||||
inline blargg_err_t File_Extractor::rewind_v() { return blargg_ok; }
|
||||
inline void File_Extractor::close_v() { }
|
||||
|
||||
// Default to Std_File_Reader for archive access
|
||||
#ifndef FEX_FILE_READER
|
||||
#define FEX_FILE_READER Std_File_Reader
|
||||
#elif defined (FEX_FILE_READER_INCLUDE)
|
||||
#include FEX_FILE_READER_INCLUDE
|
||||
#endif
|
||||
|
||||
#endif
|
||||
// Compressed file archive interface
|
||||
|
||||
// File_Extractor 1.0.0
|
||||
#ifndef FILE_EXTRACTOR_H
|
||||
#define FILE_EXTRACTOR_H
|
||||
|
||||
#include "blargg_common.h"
|
||||
#include "Data_Reader.h"
|
||||
#include "fex.h"
|
||||
|
||||
struct fex_t : private Data_Reader {
|
||||
public:
|
||||
virtual ~fex_t();
|
||||
|
||||
// Open/close
|
||||
|
||||
// Opens archive from custom data source. Keeps pointer until close().
|
||||
blargg_err_t open( File_Reader* input, const char* path = NULL );
|
||||
|
||||
// Takes ownership of File_Reader* passed to open(), so that close()
|
||||
// will delete it.
|
||||
void own_file() { own_file_ = reader_; }
|
||||
|
||||
// See fex.h
|
||||
blargg_err_t open( const char path [] );
|
||||
fex_type_t type() const { return type_; }
|
||||
void close();
|
||||
|
||||
// Scanning
|
||||
|
||||
// See fex.h
|
||||
bool done() const { return done_; }
|
||||
blargg_err_t next();
|
||||
blargg_err_t rewind();
|
||||
fex_pos_t tell_arc() const;
|
||||
blargg_err_t seek_arc( fex_pos_t );
|
||||
|
||||
// Info
|
||||
|
||||
// See fex.h
|
||||
const char* name() const { return name_; }
|
||||
const wchar_t* wname() const { return wname_; }
|
||||
blargg_err_t stat();
|
||||
int size() const { assert( stat_called ); return size_; }
|
||||
unsigned int dos_date() const { return date_; }
|
||||
unsigned int crc32() const { return crc32_; }
|
||||
|
||||
// Extraction
|
||||
|
||||
// Data_Reader to current file's data, so standard Data_Reader interface can
|
||||
// be used, rather than having to treat archives specially. stat() must have
|
||||
// been called.
|
||||
Data_Reader& reader() { assert( stat_called ); return *this; }
|
||||
|
||||
// See fex.h
|
||||
blargg_err_t data( const void** data_out );
|
||||
int tell() const { return size_ - remain(); }
|
||||
|
||||
// Derived interface
|
||||
protected:
|
||||
|
||||
// Sets type of object
|
||||
fex_t( fex_type_t );
|
||||
|
||||
// Path to archive file, or "" if none supplied
|
||||
const char* arc_path() const { return path_.begin(); }
|
||||
|
||||
// Opens archive file if it's not already. If unbuffered is true, opens file
|
||||
// without any buffering.
|
||||
blargg_err_t open_arc_file( bool unbuffered = false );
|
||||
|
||||
// Archive file
|
||||
File_Reader& arc() const { return *reader_; }
|
||||
|
||||
// Sets current file name
|
||||
void set_name( const char name [], const wchar_t* wname = NULL );
|
||||
|
||||
// Sets current file information
|
||||
void set_info( int size, unsigned date = 0, unsigned crc = 0 );
|
||||
|
||||
// User overrides
|
||||
|
||||
// Overrides must do indicated task. Non-pure functions have reasonable default
|
||||
// implementation. Overrides should avoid calling public functions like
|
||||
// next() and rewind().
|
||||
|
||||
// Open archive using file_path(). OK to delay actual file opening until later.
|
||||
// Default just calls open_arc_file(), then open_v().
|
||||
virtual blargg_err_t open_path_v();
|
||||
|
||||
// Open archive using file() for source data. If unsupported, return error.
|
||||
virtual blargg_err_t open_v() BLARGG_PURE( ; )
|
||||
|
||||
// Go to next file in archive and call set_name() and optionally set_info()
|
||||
virtual blargg_err_t next_v() BLARGG_PURE( ; )
|
||||
|
||||
// Go back to first file in archive
|
||||
virtual blargg_err_t rewind_v() BLARGG_PURE( ; )
|
||||
|
||||
// Close archive. Called even if open_path_v() or open_v() return unsuccessfully.
|
||||
virtual void close_v() BLARGG_PURE( ; )
|
||||
|
||||
// Clear any fields related to current file
|
||||
virtual void clear_file_v() { }
|
||||
|
||||
// Call set_info() if not already called by next_v()
|
||||
virtual blargg_err_t stat_v() { return blargg_ok; }
|
||||
|
||||
// Return value that allows later return to this file. Result must be >= 0.
|
||||
virtual fex_pos_t tell_arc_v() const;
|
||||
|
||||
// Return to previously saved position
|
||||
virtual blargg_err_t seek_arc_v( fex_pos_t );
|
||||
|
||||
// One or both of the following must be overridden
|
||||
|
||||
// Provide pointer to data for current file in archive
|
||||
virtual blargg_err_t data_v( const void** out );
|
||||
|
||||
// Extract next n bytes
|
||||
virtual blargg_err_t extract_v( void* out, int n );
|
||||
|
||||
// Implementation
|
||||
public:
|
||||
BLARGG_DISABLE_NOTHROW
|
||||
|
||||
private:
|
||||
fex_type_t const type_;
|
||||
|
||||
// Archive file
|
||||
blargg_vector<char> path_;
|
||||
File_Reader* reader_;
|
||||
File_Reader* own_file_;
|
||||
bool opened_;
|
||||
|
||||
// Position in archive
|
||||
fex_pos_t tell_; // only used by default implementation of tell/seek
|
||||
bool done_;
|
||||
|
||||
// Info for current file in archive
|
||||
const char* name_;
|
||||
const wchar_t* wname_;
|
||||
unsigned date_;
|
||||
unsigned crc32_;
|
||||
int size_;
|
||||
bool stat_called;
|
||||
|
||||
// Current file contents
|
||||
void const* data_ptr_; // NULL if not read into memory
|
||||
blargg_vector<char> own_data_;
|
||||
|
||||
bool opened() const { return opened_; }
|
||||
void clear_file();
|
||||
void close_();
|
||||
blargg_err_t set_path( const char* path );
|
||||
blargg_err_t rewind_file();
|
||||
blargg_err_t next_();
|
||||
|
||||
// Data_Reader overrides
|
||||
// TODO: override skip_v?
|
||||
virtual blargg_err_t read_v( void* out, int n );
|
||||
};
|
||||
|
||||
struct fex_type_t_
|
||||
{
|
||||
const char* extension;
|
||||
File_Extractor* (*new_fex)();
|
||||
const char* name;
|
||||
blargg_err_t (*init)(); // Called by fex_init(). Can be NULL.
|
||||
};
|
||||
|
||||
extern const fex_type_t_
|
||||
fex_7z_type [1],
|
||||
fex_gz_type [1],
|
||||
fex_rar_type [1],
|
||||
fex_zip_type [1],
|
||||
fex_bin_type [1];
|
||||
|
||||
inline blargg_err_t File_Extractor::open_v() { return blargg_ok; }
|
||||
inline blargg_err_t File_Extractor::next_v() { return blargg_ok; }
|
||||
inline blargg_err_t File_Extractor::rewind_v() { return blargg_ok; }
|
||||
inline void File_Extractor::close_v() { }
|
||||
|
||||
// Default to Std_File_Reader for archive access
|
||||
#ifndef FEX_FILE_READER
|
||||
#define FEX_FILE_READER Std_File_Reader
|
||||
#elif defined (FEX_FILE_READER_INCLUDE)
|
||||
#include FEX_FILE_READER_INCLUDE
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,98 +1,98 @@
|
|||
// File_Extractor 1.0.0. http://www.slack.net/~ant/
|
||||
|
||||
#include "Gzip_Extractor.h"
|
||||
|
||||
/* Copyright (C) 2005-2009 Shay Green. This module is free software; you
|
||||
can redistribute it and/or modify it under the terms of the GNU Lesser
|
||||
General Public License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version. This
|
||||
module 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 Lesser General Public License for more
|
||||
details. You should have received a copy of the GNU Lesser General Public
|
||||
License along with this module; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
#include "blargg_source.h"
|
||||
|
||||
// TODO: could close file once data has been read into memory
|
||||
|
||||
static blargg_err_t init_gzip_file()
|
||||
{
|
||||
get_crc_table(); // initialize zlib's CRC-32 tables
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
static File_Extractor* new_gzip()
|
||||
{
|
||||
return BLARGG_NEW Gzip_Extractor;
|
||||
}
|
||||
|
||||
fex_type_t_ const fex_gz_type [1] = {{
|
||||
".gz",
|
||||
&new_gzip,
|
||||
"gzipped file",
|
||||
&init_gzip_file
|
||||
}};
|
||||
|
||||
Gzip_Extractor::Gzip_Extractor() :
|
||||
File_Extractor( fex_gz_type )
|
||||
{ }
|
||||
|
||||
Gzip_Extractor::~Gzip_Extractor()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
blargg_err_t Gzip_Extractor::open_path_v()
|
||||
{
|
||||
// skip opening file
|
||||
return open_v();
|
||||
}
|
||||
|
||||
blargg_err_t Gzip_Extractor::stat_v()
|
||||
{
|
||||
RETURN_ERR( open_arc_file( true ) );
|
||||
if ( !gr.opened() || gr.tell() != 0 )
|
||||
RETURN_ERR( gr.open( &arc() ) );
|
||||
|
||||
set_info( gr.remain(), 0, gr.crc32() );
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
blargg_err_t Gzip_Extractor::open_v()
|
||||
{
|
||||
// Remove .gz suffix
|
||||
size_t len = strlen( arc_path() );
|
||||
if ( fex_has_extension( arc_path(), ".gz" ) )
|
||||
len -= 3;
|
||||
|
||||
RETURN_ERR( name.resize( len + 1 ) );
|
||||
memcpy( name.begin(), arc_path(), name.size() );
|
||||
name [name.size() - 1] = '\0';
|
||||
|
||||
set_name( name.begin() );
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
void Gzip_Extractor::close_v()
|
||||
{
|
||||
name.clear();
|
||||
gr.close();
|
||||
}
|
||||
|
||||
blargg_err_t Gzip_Extractor::next_v()
|
||||
{
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
blargg_err_t Gzip_Extractor::rewind_v()
|
||||
{
|
||||
set_name( name.begin() );
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
blargg_err_t Gzip_Extractor::extract_v( void* p, int n )
|
||||
{
|
||||
return gr.read( p, n );
|
||||
}
|
||||
// File_Extractor 1.0.0. http://www.slack.net/~ant/
|
||||
|
||||
#include "Gzip_Extractor.h"
|
||||
|
||||
/* Copyright (C) 2005-2009 Shay Green. This module is free software; you
|
||||
can redistribute it and/or modify it under the terms of the GNU Lesser
|
||||
General Public License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version. This
|
||||
module 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 Lesser General Public License for more
|
||||
details. You should have received a copy of the GNU Lesser General Public
|
||||
License along with this module; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
#include "blargg_source.h"
|
||||
|
||||
// TODO: could close file once data has been read into memory
|
||||
|
||||
static blargg_err_t init_gzip_file()
|
||||
{
|
||||
get_crc_table(); // initialize zlib's CRC-32 tables
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
static File_Extractor* new_gzip()
|
||||
{
|
||||
return BLARGG_NEW Gzip_Extractor;
|
||||
}
|
||||
|
||||
fex_type_t_ const fex_gz_type [1] = {{
|
||||
".gz",
|
||||
&new_gzip,
|
||||
"gzipped file",
|
||||
&init_gzip_file
|
||||
}};
|
||||
|
||||
Gzip_Extractor::Gzip_Extractor() :
|
||||
File_Extractor( fex_gz_type )
|
||||
{ }
|
||||
|
||||
Gzip_Extractor::~Gzip_Extractor()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
blargg_err_t Gzip_Extractor::open_path_v()
|
||||
{
|
||||
// skip opening file
|
||||
return open_v();
|
||||
}
|
||||
|
||||
blargg_err_t Gzip_Extractor::stat_v()
|
||||
{
|
||||
RETURN_ERR( open_arc_file( true ) );
|
||||
if ( !gr.opened() || gr.tell() != 0 )
|
||||
RETURN_ERR( gr.open( &arc() ) );
|
||||
|
||||
set_info( gr.remain(), 0, gr.crc32() );
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
blargg_err_t Gzip_Extractor::open_v()
|
||||
{
|
||||
// Remove .gz suffix
|
||||
size_t len = strlen( arc_path() );
|
||||
if ( fex_has_extension( arc_path(), ".gz" ) )
|
||||
len -= 3;
|
||||
|
||||
RETURN_ERR( name.resize( len + 1 ) );
|
||||
memcpy( name.begin(), arc_path(), name.size() );
|
||||
name [name.size() - 1] = '\0';
|
||||
|
||||
set_name( name.begin() );
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
void Gzip_Extractor::close_v()
|
||||
{
|
||||
name.clear();
|
||||
gr.close();
|
||||
}
|
||||
|
||||
blargg_err_t Gzip_Extractor::next_v()
|
||||
{
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
blargg_err_t Gzip_Extractor::rewind_v()
|
||||
{
|
||||
set_name( name.begin() );
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
blargg_err_t Gzip_Extractor::extract_v( void* p, int n )
|
||||
{
|
||||
return gr.read( p, n );
|
||||
}
|
||||
|
|
|
@ -1,34 +1,34 @@
|
|||
// Presents a gzipped file as an "archive" of just that file.
|
||||
// Also handles non-gzipped files.
|
||||
|
||||
// File_Extractor 1.0.0
|
||||
#ifndef GZIP_EXTRACTOR_H
|
||||
#define GZIP_EXTRACTOR_H
|
||||
|
||||
#include "File_Extractor.h"
|
||||
#include "Gzip_Reader.h"
|
||||
|
||||
class Gzip_Extractor : public File_Extractor {
|
||||
public:
|
||||
Gzip_Extractor();
|
||||
virtual ~Gzip_Extractor();
|
||||
|
||||
protected:
|
||||
virtual blargg_err_t open_path_v();
|
||||
virtual blargg_err_t open_v();
|
||||
virtual void close_v();
|
||||
|
||||
virtual blargg_err_t next_v();
|
||||
virtual blargg_err_t rewind_v();
|
||||
|
||||
virtual blargg_err_t stat_v();
|
||||
virtual blargg_err_t extract_v( void*, int );
|
||||
|
||||
private:
|
||||
Gzip_Reader gr;
|
||||
blargg_vector<char> name;
|
||||
|
||||
void set_info_();
|
||||
};
|
||||
|
||||
#endif
|
||||
// Presents a gzipped file as an "archive" of just that file.
|
||||
// Also handles non-gzipped files.
|
||||
|
||||
// File_Extractor 1.0.0
|
||||
#ifndef GZIP_EXTRACTOR_H
|
||||
#define GZIP_EXTRACTOR_H
|
||||
|
||||
#include "File_Extractor.h"
|
||||
#include "Gzip_Reader.h"
|
||||
|
||||
class Gzip_Extractor : public File_Extractor {
|
||||
public:
|
||||
Gzip_Extractor();
|
||||
virtual ~Gzip_Extractor();
|
||||
|
||||
protected:
|
||||
virtual blargg_err_t open_path_v();
|
||||
virtual blargg_err_t open_v();
|
||||
virtual void close_v();
|
||||
|
||||
virtual blargg_err_t next_v();
|
||||
virtual blargg_err_t rewind_v();
|
||||
|
||||
virtual blargg_err_t stat_v();
|
||||
virtual blargg_err_t extract_v( void*, int );
|
||||
|
||||
private:
|
||||
Gzip_Reader gr;
|
||||
blargg_vector<char> name;
|
||||
|
||||
void set_info_();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,85 +1,85 @@
|
|||
// File_Extractor 1.0.0. http://www.slack.net/~ant/
|
||||
|
||||
#include "Gzip_Reader.h"
|
||||
|
||||
#include "blargg_endian.h"
|
||||
|
||||
/* Copyright (C) 2006-2009 Shay Green. This module is free software; you
|
||||
can redistribute it and/or modify it under the terms of the GNU Lesser
|
||||
General Public License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version. This
|
||||
module 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 Lesser General Public License for more
|
||||
details. You should have received a copy of the GNU Lesser General Public
|
||||
License along with this module; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
#include "blargg_source.h"
|
||||
|
||||
Gzip_Reader::Gzip_Reader()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
Gzip_Reader::~Gzip_Reader()
|
||||
{ }
|
||||
|
||||
static blargg_err_t gzip_reader_read( void* file, void* out, int* count )
|
||||
{
|
||||
return STATIC_CAST(File_Reader*,file)->read_avail( out, count );
|
||||
}
|
||||
|
||||
blargg_err_t Gzip_Reader::calc_size()
|
||||
{
|
||||
size_ = in->size();
|
||||
crc32_ = 0;
|
||||
if ( inflater.deflated() )
|
||||
{
|
||||
byte trailer [8];
|
||||
int old_pos = in->tell();
|
||||
RETURN_ERR( in->seek( size_ - sizeof trailer ) );
|
||||
RETURN_ERR( in->read( trailer, sizeof trailer ) );
|
||||
RETURN_ERR( in->seek( old_pos ) );
|
||||
crc32_ = get_le32( trailer + 0 );
|
||||
|
||||
unsigned n = get_le32( trailer + 4 );
|
||||
if ( n > INT_MAX )
|
||||
return BLARGG_ERR( BLARGG_ERR_FILE_FEATURE, "gzip larger than 2GB" );
|
||||
|
||||
size_ = n;
|
||||
}
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
blargg_err_t Gzip_Reader::open( File_Reader* new_in )
|
||||
{
|
||||
close();
|
||||
|
||||
in = new_in;
|
||||
RETURN_ERR( in->seek( 0 ) );
|
||||
RETURN_ERR( inflater.begin( gzip_reader_read, new_in ) );
|
||||
RETURN_ERR( inflater.set_mode( inflater.mode_auto ) );
|
||||
RETURN_ERR( calc_size() );
|
||||
set_remain( size_ );
|
||||
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
void Gzip_Reader::close()
|
||||
{
|
||||
in = NULL;
|
||||
inflater.end();
|
||||
}
|
||||
|
||||
blargg_err_t Gzip_Reader::read_v( void* out, int count )
|
||||
{
|
||||
assert( in );
|
||||
int actual = count;
|
||||
RETURN_ERR( inflater.read( out, &actual ) );
|
||||
|
||||
if ( actual != count )
|
||||
return blargg_err_file_corrupt;
|
||||
|
||||
return blargg_ok;
|
||||
}
|
||||
// File_Extractor 1.0.0. http://www.slack.net/~ant/
|
||||
|
||||
#include "Gzip_Reader.h"
|
||||
|
||||
#include "blargg_endian.h"
|
||||
|
||||
/* Copyright (C) 2006-2009 Shay Green. This module is free software; you
|
||||
can redistribute it and/or modify it under the terms of the GNU Lesser
|
||||
General Public License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version. This
|
||||
module 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 Lesser General Public License for more
|
||||
details. You should have received a copy of the GNU Lesser General Public
|
||||
License along with this module; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
#include "blargg_source.h"
|
||||
|
||||
Gzip_Reader::Gzip_Reader()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
Gzip_Reader::~Gzip_Reader()
|
||||
{ }
|
||||
|
||||
static blargg_err_t gzip_reader_read( void* file, void* out, int* count )
|
||||
{
|
||||
return STATIC_CAST(File_Reader*,file)->read_avail( out, count );
|
||||
}
|
||||
|
||||
blargg_err_t Gzip_Reader::calc_size()
|
||||
{
|
||||
size_ = in->size();
|
||||
crc32_ = 0;
|
||||
if ( inflater.deflated() )
|
||||
{
|
||||
byte trailer [8];
|
||||
int old_pos = in->tell();
|
||||
RETURN_ERR( in->seek( size_ - sizeof trailer ) );
|
||||
RETURN_ERR( in->read( trailer, sizeof trailer ) );
|
||||
RETURN_ERR( in->seek( old_pos ) );
|
||||
crc32_ = get_le32( trailer + 0 );
|
||||
|
||||
unsigned n = get_le32( trailer + 4 );
|
||||
if ( n > INT_MAX )
|
||||
return BLARGG_ERR( BLARGG_ERR_FILE_FEATURE, "gzip larger than 2GB" );
|
||||
|
||||
size_ = n;
|
||||
}
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
blargg_err_t Gzip_Reader::open( File_Reader* new_in )
|
||||
{
|
||||
close();
|
||||
|
||||
in = new_in;
|
||||
RETURN_ERR( in->seek( 0 ) );
|
||||
RETURN_ERR( inflater.begin( gzip_reader_read, new_in ) );
|
||||
RETURN_ERR( inflater.set_mode( inflater.mode_auto ) );
|
||||
RETURN_ERR( calc_size() );
|
||||
set_remain( size_ );
|
||||
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
void Gzip_Reader::close()
|
||||
{
|
||||
in = NULL;
|
||||
inflater.end();
|
||||
}
|
||||
|
||||
blargg_err_t Gzip_Reader::read_v( void* out, int count )
|
||||
{
|
||||
assert( in );
|
||||
int actual = count;
|
||||
RETURN_ERR( inflater.read( out, &actual ) );
|
||||
|
||||
if ( actual != count )
|
||||
return blargg_err_file_corrupt;
|
||||
|
||||
return blargg_ok;
|
||||
}
|
||||
|
|
|
@ -1,46 +1,46 @@
|
|||
// Transparently decompresses gzip files, as well as uncompressed
|
||||
|
||||
// File_Extractor 1.0.0
|
||||
#ifndef GZIP_READER_H
|
||||
#define GZIP_READER_H
|
||||
|
||||
#include "Data_Reader.h"
|
||||
#include "Zlib_Inflater.h"
|
||||
|
||||
class Gzip_Reader : public Data_Reader {
|
||||
public:
|
||||
// Keeps pointer to reader until close(). If
|
||||
blargg_err_t open( File_Reader* );
|
||||
|
||||
// True if file is open
|
||||
bool opened() const { return in != NULL; }
|
||||
|
||||
// Frees memory
|
||||
void close();
|
||||
|
||||
// True if file is compressed
|
||||
bool deflated() const { return inflater.deflated(); }
|
||||
|
||||
// CRC-32 of data, of 0 if unavailable
|
||||
unsigned int crc32() const { return crc32_; }
|
||||
|
||||
// Number of bytes read since opening
|
||||
int tell() const { return size_ - remain(); }
|
||||
|
||||
public:
|
||||
Gzip_Reader();
|
||||
virtual ~Gzip_Reader();
|
||||
|
||||
protected:
|
||||
virtual blargg_err_t read_v( void*, int );
|
||||
|
||||
private:
|
||||
File_Reader* in;
|
||||
unsigned crc32_;
|
||||
int size_;
|
||||
Zlib_Inflater inflater;
|
||||
|
||||
blargg_err_t calc_size();
|
||||
};
|
||||
|
||||
#endif
|
||||
// Transparently decompresses gzip files, as well as uncompressed
|
||||
|
||||
// File_Extractor 1.0.0
|
||||
#ifndef GZIP_READER_H
|
||||
#define GZIP_READER_H
|
||||
|
||||
#include "Data_Reader.h"
|
||||
#include "Zlib_Inflater.h"
|
||||
|
||||
class Gzip_Reader : public Data_Reader {
|
||||
public:
|
||||
// Keeps pointer to reader until close(). If
|
||||
blargg_err_t open( File_Reader* );
|
||||
|
||||
// True if file is open
|
||||
bool opened() const { return in != NULL; }
|
||||
|
||||
// Frees memory
|
||||
void close();
|
||||
|
||||
// True if file is compressed
|
||||
bool deflated() const { return inflater.deflated(); }
|
||||
|
||||
// CRC-32 of data, of 0 if unavailable
|
||||
unsigned int crc32() const { return crc32_; }
|
||||
|
||||
// Number of bytes read since opening
|
||||
int tell() const { return size_ - remain(); }
|
||||
|
||||
public:
|
||||
Gzip_Reader();
|
||||
virtual ~Gzip_Reader();
|
||||
|
||||
protected:
|
||||
virtual blargg_err_t read_v( void*, int );
|
||||
|
||||
private:
|
||||
File_Reader* in;
|
||||
unsigned crc32_;
|
||||
int size_;
|
||||
Zlib_Inflater inflater;
|
||||
|
||||
blargg_err_t calc_size();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,197 +1,197 @@
|
|||
// File_Extractor 1.0.0. http://www.slack.net/~ant/
|
||||
|
||||
#include "blargg_common.h"
|
||||
|
||||
#if FEX_ENABLE_RAR
|
||||
|
||||
#include "Rar_Extractor.h"
|
||||
|
||||
/* Copyright (C) 2009 Shay Green. This module is free software; you
|
||||
can redistribute it and/or modify it under the terms of the GNU Lesser
|
||||
General Public License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version. This
|
||||
module 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 Lesser General Public License for more
|
||||
details. You should have received a copy of the GNU Lesser General Public
|
||||
License along with this module; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
#include "blargg_source.h"
|
||||
|
||||
static blargg_err_t init_rar()
|
||||
{
|
||||
unrar_init();
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
static File_Extractor* new_rar()
|
||||
{
|
||||
return BLARGG_NEW Rar_Extractor;
|
||||
}
|
||||
|
||||
fex_type_t_ const fex_rar_type [1] = {{
|
||||
".rar",
|
||||
&new_rar,
|
||||
"RAR archive",
|
||||
&init_rar
|
||||
}};
|
||||
|
||||
blargg_err_t Rar_Extractor::convert_err( unrar_err_t err )
|
||||
{
|
||||
blargg_err_t reader_err = reader.err;
|
||||
reader.err = blargg_ok;
|
||||
if ( reader_err )
|
||||
check( err == unrar_next_err );
|
||||
|
||||
switch ( err )
|
||||
{
|
||||
case unrar_ok: return blargg_ok;
|
||||
case unrar_err_memory: return blargg_err_memory;
|
||||
case unrar_err_open: return blargg_err_file_read;
|
||||
case unrar_err_not_arc: return blargg_err_file_type;
|
||||
case unrar_err_corrupt: return blargg_err_file_corrupt;
|
||||
case unrar_err_io: return blargg_err_file_io;
|
||||
case unrar_err_arc_eof: return blargg_err_internal;
|
||||
case unrar_err_encrypted: return BLARGG_ERR( BLARGG_ERR_FILE_FEATURE, "RAR encryption not supported" );
|
||||
case unrar_err_segmented: return BLARGG_ERR( BLARGG_ERR_FILE_FEATURE, "RAR segmentation not supported" );
|
||||
case unrar_err_huge: return BLARGG_ERR( BLARGG_ERR_FILE_FEATURE, "Huge RAR files not supported" );
|
||||
case unrar_err_old_algo: return BLARGG_ERR( BLARGG_ERR_FILE_FEATURE, "Old RAR compression not supported" );
|
||||
case unrar_err_new_algo: return BLARGG_ERR( BLARGG_ERR_FILE_FEATURE, "RAR uses unknown newer compression" );
|
||||
case unrar_next_err: break;
|
||||
default:
|
||||
check( false ); // unhandled RAR error
|
||||
}
|
||||
|
||||
if ( reader_err )
|
||||
return reader_err;
|
||||
|
||||
check( false );
|
||||
return BLARGG_ERR( BLARGG_ERR_INTERNAL, "RAR archive" );
|
||||
}
|
||||
|
||||
static inline unrar_err_t handle_err( Rar_Extractor::read_callback_t* h, blargg_err_t err )
|
||||
{
|
||||
if ( !err )
|
||||
return unrar_ok;
|
||||
|
||||
h->err = err;
|
||||
return unrar_next_err;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
static unrar_err_t my_unrar_read( void* data, void* out, int* count, unrar_pos_t pos )
|
||||
{
|
||||
// TODO: 64-bit file support
|
||||
|
||||
Rar_Extractor::read_callback_t* h = STATIC_CAST(Rar_Extractor::read_callback_t*,data);
|
||||
if ( h->pos != pos )
|
||||
{
|
||||
blargg_err_t err = h->in->seek( pos );
|
||||
if ( err )
|
||||
return handle_err( h, err );
|
||||
|
||||
h->pos = pos;
|
||||
}
|
||||
|
||||
blargg_err_t err = h->in->read_avail( out, count );
|
||||
if ( err )
|
||||
return handle_err( h, err );
|
||||
|
||||
h->pos += *count;
|
||||
|
||||
return unrar_ok;
|
||||
}
|
||||
}
|
||||
|
||||
Rar_Extractor::Rar_Extractor() :
|
||||
File_Extractor( fex_rar_type )
|
||||
{
|
||||
unrar = NULL;
|
||||
}
|
||||
|
||||
Rar_Extractor::~Rar_Extractor()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
blargg_err_t Rar_Extractor::open_v()
|
||||
{
|
||||
reader.pos = 0;
|
||||
reader.in = &arc();
|
||||
reader.err = blargg_ok;
|
||||
|
||||
RETURN_ERR( arc().seek( 0 ) );
|
||||
RETURN_ERR( convert_err( unrar_open_custom( &unrar, &my_unrar_read, &reader ) ) );
|
||||
return skip_unextractables();
|
||||
}
|
||||
|
||||
void Rar_Extractor::close_v()
|
||||
{
|
||||
unrar_close( unrar );
|
||||
|
||||
unrar = NULL;
|
||||
reader.in = NULL;
|
||||
}
|
||||
|
||||
blargg_err_t Rar_Extractor::skip_unextractables()
|
||||
{
|
||||
while ( !unrar_done( unrar ) && unrar_try_extract( unrar ) )
|
||||
RETURN_ERR( next_raw() );
|
||||
|
||||
if ( !unrar_done( unrar ) )
|
||||
{
|
||||
unrar_info_t const* info = unrar_info( unrar );
|
||||
|
||||
set_name( info->name, (info->name_w && *info->name_w) ? info->name_w : NULL );
|
||||
set_info( info->size, info->dos_date, (info->is_crc32 ? info->crc : 0) );
|
||||
}
|
||||
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
blargg_err_t Rar_Extractor::next_raw()
|
||||
{
|
||||
return convert_err( unrar_next( unrar ) );
|
||||
}
|
||||
|
||||
blargg_err_t Rar_Extractor::next_v()
|
||||
{
|
||||
RETURN_ERR( next_raw() );
|
||||
return skip_unextractables();
|
||||
}
|
||||
|
||||
blargg_err_t Rar_Extractor::rewind_v()
|
||||
{
|
||||
RETURN_ERR( convert_err( unrar_rewind( unrar ) ) );
|
||||
return skip_unextractables();
|
||||
}
|
||||
|
||||
fex_pos_t Rar_Extractor::tell_arc_v() const
|
||||
{
|
||||
return unrar_tell( unrar );
|
||||
}
|
||||
|
||||
blargg_err_t Rar_Extractor::seek_arc_v( fex_pos_t pos )
|
||||
{
|
||||
RETURN_ERR( convert_err( unrar_seek( unrar, pos ) ) );
|
||||
return skip_unextractables();
|
||||
}
|
||||
|
||||
blargg_err_t Rar_Extractor::data_v( void const** out )
|
||||
{
|
||||
return convert_err( unrar_extract_mem( unrar, out ) );
|
||||
}
|
||||
|
||||
blargg_err_t Rar_Extractor::extract_v( void* out, int count )
|
||||
{
|
||||
// We can read entire file directly into user buffer
|
||||
if ( count == size() )
|
||||
return convert_err( unrar_extract( unrar, out, count ) );
|
||||
|
||||
// This will call data_v() and copy from that buffer for us
|
||||
return File_Extractor::extract_v( out, count );
|
||||
}
|
||||
|
||||
#endif
|
||||
// File_Extractor 1.0.0. http://www.slack.net/~ant/
|
||||
|
||||
#include "blargg_common.h"
|
||||
|
||||
#if FEX_ENABLE_RAR
|
||||
|
||||
#include "Rar_Extractor.h"
|
||||
|
||||
/* Copyright (C) 2009 Shay Green. This module is free software; you
|
||||
can redistribute it and/or modify it under the terms of the GNU Lesser
|
||||
General Public License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version. This
|
||||
module 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 Lesser General Public License for more
|
||||
details. You should have received a copy of the GNU Lesser General Public
|
||||
License along with this module; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
#include "blargg_source.h"
|
||||
|
||||
static blargg_err_t init_rar()
|
||||
{
|
||||
unrar_init();
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
static File_Extractor* new_rar()
|
||||
{
|
||||
return BLARGG_NEW Rar_Extractor;
|
||||
}
|
||||
|
||||
fex_type_t_ const fex_rar_type [1] = {{
|
||||
".rar",
|
||||
&new_rar,
|
||||
"RAR archive",
|
||||
&init_rar
|
||||
}};
|
||||
|
||||
blargg_err_t Rar_Extractor::convert_err( unrar_err_t err )
|
||||
{
|
||||
blargg_err_t reader_err = reader.err;
|
||||
reader.err = blargg_ok;
|
||||
if ( reader_err )
|
||||
check( err == unrar_next_err );
|
||||
|
||||
switch ( err )
|
||||
{
|
||||
case unrar_ok: return blargg_ok;
|
||||
case unrar_err_memory: return blargg_err_memory;
|
||||
case unrar_err_open: return blargg_err_file_read;
|
||||
case unrar_err_not_arc: return blargg_err_file_type;
|
||||
case unrar_err_corrupt: return blargg_err_file_corrupt;
|
||||
case unrar_err_io: return blargg_err_file_io;
|
||||
case unrar_err_arc_eof: return blargg_err_internal;
|
||||
case unrar_err_encrypted: return BLARGG_ERR( BLARGG_ERR_FILE_FEATURE, "RAR encryption not supported" );
|
||||
case unrar_err_segmented: return BLARGG_ERR( BLARGG_ERR_FILE_FEATURE, "RAR segmentation not supported" );
|
||||
case unrar_err_huge: return BLARGG_ERR( BLARGG_ERR_FILE_FEATURE, "Huge RAR files not supported" );
|
||||
case unrar_err_old_algo: return BLARGG_ERR( BLARGG_ERR_FILE_FEATURE, "Old RAR compression not supported" );
|
||||
case unrar_err_new_algo: return BLARGG_ERR( BLARGG_ERR_FILE_FEATURE, "RAR uses unknown newer compression" );
|
||||
case unrar_next_err: break;
|
||||
default:
|
||||
check( false ); // unhandled RAR error
|
||||
}
|
||||
|
||||
if ( reader_err )
|
||||
return reader_err;
|
||||
|
||||
check( false );
|
||||
return BLARGG_ERR( BLARGG_ERR_INTERNAL, "RAR archive" );
|
||||
}
|
||||
|
||||
static inline unrar_err_t handle_err( Rar_Extractor::read_callback_t* h, blargg_err_t err )
|
||||
{
|
||||
if ( !err )
|
||||
return unrar_ok;
|
||||
|
||||
h->err = err;
|
||||
return unrar_next_err;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
static unrar_err_t my_unrar_read( void* data, void* out, int* count, unrar_pos_t pos )
|
||||
{
|
||||
// TODO: 64-bit file support
|
||||
|
||||
Rar_Extractor::read_callback_t* h = STATIC_CAST(Rar_Extractor::read_callback_t*,data);
|
||||
if ( h->pos != pos )
|
||||
{
|
||||
blargg_err_t err = h->in->seek( pos );
|
||||
if ( err )
|
||||
return handle_err( h, err );
|
||||
|
||||
h->pos = pos;
|
||||
}
|
||||
|
||||
blargg_err_t err = h->in->read_avail( out, count );
|
||||
if ( err )
|
||||
return handle_err( h, err );
|
||||
|
||||
h->pos += *count;
|
||||
|
||||
return unrar_ok;
|
||||
}
|
||||
}
|
||||
|
||||
Rar_Extractor::Rar_Extractor() :
|
||||
File_Extractor( fex_rar_type )
|
||||
{
|
||||
unrar = NULL;
|
||||
}
|
||||
|
||||
Rar_Extractor::~Rar_Extractor()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
blargg_err_t Rar_Extractor::open_v()
|
||||
{
|
||||
reader.pos = 0;
|
||||
reader.in = &arc();
|
||||
reader.err = blargg_ok;
|
||||
|
||||
RETURN_ERR( arc().seek( 0 ) );
|
||||
RETURN_ERR( convert_err( unrar_open_custom( &unrar, &my_unrar_read, &reader ) ) );
|
||||
return skip_unextractables();
|
||||
}
|
||||
|
||||
void Rar_Extractor::close_v()
|
||||
{
|
||||
unrar_close( unrar );
|
||||
|
||||
unrar = NULL;
|
||||
reader.in = NULL;
|
||||
}
|
||||
|
||||
blargg_err_t Rar_Extractor::skip_unextractables()
|
||||
{
|
||||
while ( !unrar_done( unrar ) && unrar_try_extract( unrar ) )
|
||||
RETURN_ERR( next_raw() );
|
||||
|
||||
if ( !unrar_done( unrar ) )
|
||||
{
|
||||
unrar_info_t const* info = unrar_info( unrar );
|
||||
|
||||
set_name( info->name, (info->name_w && *info->name_w) ? info->name_w : NULL );
|
||||
set_info( info->size, info->dos_date, (info->is_crc32 ? info->crc : 0) );
|
||||
}
|
||||
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
blargg_err_t Rar_Extractor::next_raw()
|
||||
{
|
||||
return convert_err( unrar_next( unrar ) );
|
||||
}
|
||||
|
||||
blargg_err_t Rar_Extractor::next_v()
|
||||
{
|
||||
RETURN_ERR( next_raw() );
|
||||
return skip_unextractables();
|
||||
}
|
||||
|
||||
blargg_err_t Rar_Extractor::rewind_v()
|
||||
{
|
||||
RETURN_ERR( convert_err( unrar_rewind( unrar ) ) );
|
||||
return skip_unextractables();
|
||||
}
|
||||
|
||||
fex_pos_t Rar_Extractor::tell_arc_v() const
|
||||
{
|
||||
return unrar_tell( unrar );
|
||||
}
|
||||
|
||||
blargg_err_t Rar_Extractor::seek_arc_v( fex_pos_t pos )
|
||||
{
|
||||
RETURN_ERR( convert_err( unrar_seek( unrar, pos ) ) );
|
||||
return skip_unextractables();
|
||||
}
|
||||
|
||||
blargg_err_t Rar_Extractor::data_v( void const** out )
|
||||
{
|
||||
return convert_err( unrar_extract_mem( unrar, out ) );
|
||||
}
|
||||
|
||||
blargg_err_t Rar_Extractor::extract_v( void* out, int count )
|
||||
{
|
||||
// We can read entire file directly into user buffer
|
||||
if ( count == size() )
|
||||
return convert_err( unrar_extract( unrar, out, count ) );
|
||||
|
||||
// This will call data_v() and copy from that buffer for us
|
||||
return File_Extractor::extract_v( out, count );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,43 +1,43 @@
|
|||
// RAR archive extractor
|
||||
|
||||
// File_Extractor 1.0.0
|
||||
#ifndef RAR_EXTRACTOR_H
|
||||
#define RAR_EXTRACTOR_H
|
||||
|
||||
#include "File_Extractor.h"
|
||||
#include "unrar/unrar.h"
|
||||
|
||||
class Rar_Extractor : public File_Extractor {
|
||||
public:
|
||||
Rar_Extractor();
|
||||
virtual ~Rar_Extractor();
|
||||
|
||||
struct read_callback_t
|
||||
{
|
||||
const char* err;
|
||||
int pos;
|
||||
File_Reader* in;
|
||||
};
|
||||
|
||||
protected:
|
||||
virtual blargg_err_t open_v();
|
||||
virtual void close_v();
|
||||
|
||||
virtual blargg_err_t next_v();
|
||||
virtual blargg_err_t rewind_v();
|
||||
virtual fex_pos_t tell_arc_v() const;
|
||||
virtual blargg_err_t seek_arc_v( fex_pos_t );
|
||||
|
||||
virtual blargg_err_t data_v( void const** );
|
||||
virtual blargg_err_t extract_v( void*, int );
|
||||
|
||||
private:
|
||||
unrar_t* unrar;
|
||||
read_callback_t reader;
|
||||
|
||||
blargg_err_t convert_err( unrar_err_t );
|
||||
blargg_err_t skip_unextractables();
|
||||
blargg_err_t next_raw();
|
||||
};
|
||||
|
||||
#endif
|
||||
// RAR archive extractor
|
||||
|
||||
// File_Extractor 1.0.0
|
||||
#ifndef RAR_EXTRACTOR_H
|
||||
#define RAR_EXTRACTOR_H
|
||||
|
||||
#include "File_Extractor.h"
|
||||
#include "unrar/unrar.h"
|
||||
|
||||
class Rar_Extractor : public File_Extractor {
|
||||
public:
|
||||
Rar_Extractor();
|
||||
virtual ~Rar_Extractor();
|
||||
|
||||
struct read_callback_t
|
||||
{
|
||||
const char* err;
|
||||
int pos;
|
||||
File_Reader* in;
|
||||
};
|
||||
|
||||
protected:
|
||||
virtual blargg_err_t open_v();
|
||||
virtual void close_v();
|
||||
|
||||
virtual blargg_err_t next_v();
|
||||
virtual blargg_err_t rewind_v();
|
||||
virtual fex_pos_t tell_arc_v() const;
|
||||
virtual blargg_err_t seek_arc_v( fex_pos_t );
|
||||
|
||||
virtual blargg_err_t data_v( void const** );
|
||||
virtual blargg_err_t extract_v( void*, int );
|
||||
|
||||
private:
|
||||
unrar_t* unrar;
|
||||
read_callback_t reader;
|
||||
|
||||
blargg_err_t convert_err( unrar_err_t );
|
||||
blargg_err_t skip_unextractables();
|
||||
blargg_err_t next_raw();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,354 +1,354 @@
|
|||
// File_Extractor 1.0.0. http://www.slack.net/~ant/
|
||||
|
||||
#include "Zip7_Extractor.h"
|
||||
|
||||
extern "C" {
|
||||
#include "7z_C/7z.h"
|
||||
#include "7z_C/7zAlloc.h"
|
||||
#include "7z_C/7zCrc.h"
|
||||
}
|
||||
|
||||
#include <time.h>
|
||||
|
||||
/* Copyright (C) 2005-2009 Shay Green. This module is free software; you
|
||||
can redistribute it and/or modify it under the terms of the GNU Lesser
|
||||
General Public License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version. This
|
||||
module 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 Lesser General Public License for more
|
||||
details. You should have received a copy of the GNU Lesser General Public
|
||||
License along with this module; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
#include "blargg_source.h"
|
||||
|
||||
static ISzAlloc zip7_alloc = { SzAlloc, SzFree };
|
||||
static ISzAlloc zip7_alloc_temp = { SzAllocTemp, SzFreeTemp };
|
||||
|
||||
struct Zip7_Extractor_Impl :
|
||||
ISeekInStream
|
||||
{
|
||||
CLookToRead look;
|
||||
CSzArEx db;
|
||||
|
||||
// SzExtract state
|
||||
UInt32 block_index;
|
||||
Byte* buf;
|
||||
size_t buf_size;
|
||||
|
||||
File_Reader* in;
|
||||
const char* in_err;
|
||||
};
|
||||
|
||||
extern "C"
|
||||
{
|
||||
// 7-zip callbacks pass an ISeekInStream* for data, so we must cast it
|
||||
// back to ISeekInStream* FIRST, then cast to our Impl structure
|
||||
|
||||
static SRes zip7_read_( void* vstream, void* out, size_t* size )
|
||||
{
|
||||
assert( out && size );
|
||||
ISeekInStream* stream = STATIC_CAST(ISeekInStream*,vstream);
|
||||
Zip7_Extractor_Impl* impl = STATIC_CAST(Zip7_Extractor_Impl*,stream);
|
||||
|
||||
long lsize = *size;
|
||||
blargg_err_t err = impl->in->read_avail( out, &lsize );
|
||||
if ( err )
|
||||
{
|
||||
*size = 0;
|
||||
impl->in_err = err;
|
||||
return SZ_ERROR_READ;
|
||||
}
|
||||
|
||||
*size = lsize;
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
static SRes zip7_seek_( void* vstream, Int64* pos, ESzSeek mode )
|
||||
{
|
||||
ISeekInStream* stream = STATIC_CAST(ISeekInStream*,vstream);
|
||||
Zip7_Extractor_Impl* impl = STATIC_CAST(Zip7_Extractor_Impl*,stream);
|
||||
|
||||
// assert( mode != SZ_SEEK_CUR ); // never used
|
||||
|
||||
if ( mode == SZ_SEEK_END )
|
||||
{
|
||||
assert( *pos == 0 ); // only used to find file length
|
||||
*pos = impl->in->size();
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
// assert( mode == SZ_SEEK_SET );
|
||||
blargg_err_t err = impl->in->seek( *pos );
|
||||
if ( err )
|
||||
{
|
||||
// don't set in_err in this case, since it might be benign
|
||||
if ( err == blargg_err_file_eof )
|
||||
return SZ_ERROR_INPUT_EOF;
|
||||
|
||||
impl->in_err = err;
|
||||
return SZ_ERROR_READ;
|
||||
}
|
||||
|
||||
return SZ_OK;
|
||||
}
|
||||
}
|
||||
|
||||
blargg_err_t Zip7_Extractor::zip7_err( int err )
|
||||
{
|
||||
// TODO: ignore in_err in some cases? unsure about which error to use
|
||||
blargg_err_t in_err = impl->in_err;
|
||||
impl->in_err = NULL;
|
||||
if ( in_err )
|
||||
{
|
||||
check( err != SZ_OK );
|
||||
return in_err;
|
||||
}
|
||||
|
||||
switch ( err )
|
||||
{
|
||||
case SZ_OK: return blargg_ok;
|
||||
case SZ_ERROR_MEM: return blargg_err_memory;
|
||||
case SZ_ERROR_READ: return blargg_err_file_io;
|
||||
case SZ_ERROR_CRC:
|
||||
case SZ_ERROR_DATA:
|
||||
case SZ_ERROR_INPUT_EOF:
|
||||
case SZ_ERROR_ARCHIVE: return blargg_err_file_corrupt;
|
||||
case SZ_ERROR_UNSUPPORTED: return blargg_err_file_feature;
|
||||
case SZ_ERROR_NO_ARCHIVE: return blargg_err_file_type;
|
||||
}
|
||||
|
||||
return blargg_err_generic;
|
||||
}
|
||||
|
||||
static blargg_err_t init_7z()
|
||||
{
|
||||
static bool inited;
|
||||
if ( !inited )
|
||||
{
|
||||
inited = true;
|
||||
CrcGenerateTable();
|
||||
}
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
static File_Extractor* new_7z()
|
||||
{
|
||||
return BLARGG_NEW Zip7_Extractor;
|
||||
}
|
||||
|
||||
fex_type_t_ const fex_7z_type [1] = {{
|
||||
".7z",
|
||||
&new_7z,
|
||||
"7-zip archive",
|
||||
&init_7z
|
||||
}};
|
||||
|
||||
Zip7_Extractor::Zip7_Extractor() :
|
||||
File_Extractor( fex_7z_type )
|
||||
{
|
||||
impl = NULL;
|
||||
}
|
||||
|
||||
Zip7_Extractor::~Zip7_Extractor()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
blargg_err_t Zip7_Extractor::open_v()
|
||||
{
|
||||
RETURN_ERR( init_7z() );
|
||||
|
||||
if ( !impl )
|
||||
{
|
||||
impl = (Zip7_Extractor_Impl*) malloc( sizeof *impl );
|
||||
CHECK_ALLOC( impl );
|
||||
}
|
||||
|
||||
impl->in = &arc();
|
||||
impl->block_index = (UInt32) -1;
|
||||
impl->buf = NULL;
|
||||
impl->buf_size = 0;
|
||||
|
||||
LookToRead_CreateVTable( &impl->look, false );
|
||||
impl->ISeekInStream::Read = zip7_read_;
|
||||
impl->ISeekInStream::Seek = zip7_seek_;
|
||||
impl->look.realStream = impl;
|
||||
LookToRead_Init( &impl->look );
|
||||
|
||||
SzArEx_Init( &impl->db );
|
||||
|
||||
impl->in_err = NULL;
|
||||
RETURN_ERR( zip7_err( SzArEx_Open( &impl->db, &impl->look.s,
|
||||
&zip7_alloc, &zip7_alloc_temp ) ) );
|
||||
|
||||
return seek_arc_v( 0 );
|
||||
}
|
||||
|
||||
void Zip7_Extractor::close_v()
|
||||
{
|
||||
if ( impl )
|
||||
{
|
||||
if ( impl->in )
|
||||
{
|
||||
impl->in = NULL;
|
||||
SzArEx_Free( &impl->db, &zip7_alloc );
|
||||
}
|
||||
IAlloc_Free( &zip7_alloc, impl->buf );
|
||||
free( impl );
|
||||
impl = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// This method was taken from ogre-7z (thanks), and is thus LGPL
|
||||
bool Zip7_Extractor::utf16ToUtf8( unsigned char* dest, size_t* destLen, const short* src, size_t srcLen )
|
||||
{
|
||||
static const unsigned char sUtf8Limits[5] = { 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
|
||||
|
||||
size_t destPos = 0, srcPos = 0;
|
||||
for(;;)
|
||||
{
|
||||
unsigned int numAdds;
|
||||
unsigned long value;
|
||||
if( srcPos == srcLen )
|
||||
{
|
||||
*destLen = destPos;
|
||||
return true;
|
||||
}
|
||||
|
||||
value = src[srcPos++];
|
||||
if( value < 0x80 )
|
||||
{
|
||||
if( dest )
|
||||
{
|
||||
dest[destPos] = (char)value;
|
||||
}
|
||||
destPos++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if( value >= 0xD800 && value < 0xE000 )
|
||||
{
|
||||
unsigned long c2;
|
||||
if( value >= 0xDC00 || srcPos == srcLen )
|
||||
break;
|
||||
|
||||
c2 = src[srcPos++];
|
||||
if( c2 < 0xDC00 || c2 >= 0xE000 )
|
||||
break;
|
||||
|
||||
value = (((value - 0xD800) << 10) | (c2 - 0xDC00)) + 0x10000;
|
||||
}
|
||||
|
||||
for( numAdds = 1; numAdds < 5; numAdds++ )
|
||||
{
|
||||
if( value < (((UInt32)1) << (numAdds * 5 + 6)) )
|
||||
break;
|
||||
}
|
||||
|
||||
if( dest )
|
||||
{
|
||||
dest[destPos] = (char)(sUtf8Limits[numAdds - 1] + (value >> (6 * numAdds)));
|
||||
}
|
||||
|
||||
destPos++;
|
||||
do
|
||||
{
|
||||
numAdds--;
|
||||
if( dest )
|
||||
{
|
||||
dest[destPos] = (char)(0x80 + ((value >> (6 * numAdds)) & 0x3F));
|
||||
}
|
||||
destPos++;
|
||||
}
|
||||
while( numAdds != 0 );
|
||||
}
|
||||
|
||||
*destLen = destPos;
|
||||
return false;
|
||||
}
|
||||
|
||||
blargg_err_t Zip7_Extractor::next_v()
|
||||
{
|
||||
while ( ++index < (int) impl->db.db.NumFiles )
|
||||
{
|
||||
CSzFileItem const& item = impl->db.db.Files [index];
|
||||
if ( !item.IsDir )
|
||||
{
|
||||
unsigned long date = 0;
|
||||
if ( item.MTimeDefined )
|
||||
{
|
||||
const UInt64 epoch = ((UInt64)0x019db1de << 32) + 0xd53e8000;
|
||||
/* 0x019db1ded53e8000ULL: 1970-01-01 00:00:00 (UTC) */
|
||||
struct tm tm;
|
||||
|
||||
UInt64 time = ((UInt64)item.MTime.High << 32) + item.MTime.Low - epoch;
|
||||
time /= 1000000;
|
||||
|
||||
time_t _time = time;
|
||||
|
||||
#ifdef _WIN32
|
||||
tm = *localtime( &_time );
|
||||
#else
|
||||
localtime_r( &_time, &tm );
|
||||
#endif
|
||||
|
||||
date = (( tm.tm_sec >> 1 ) & 0x1F) |
|
||||
(( tm.tm_min & 0x3F ) << 5 ) |
|
||||
(( tm.tm_hour & 0x1F ) << 11 ) |
|
||||
(( tm.tm_mday & 0x1F ) << 16 ) |
|
||||
(( ( tm.tm_mon + 1 ) & 0x0F ) << 21 ) |
|
||||
(( ( tm.tm_year - 80 ) & 0x7F ) << 25 );
|
||||
}
|
||||
|
||||
size_t name_length = SzArEx_GetFileNameUtf16( &impl->db, index, 0 );
|
||||
size_t utf8_length = 0;
|
||||
name16.resize( name_length );
|
||||
SzArEx_GetFileNameUtf16( &impl->db, index, ( UInt16 * ) name16.begin() );
|
||||
unsigned char temp[1024];
|
||||
utf16ToUtf8( temp, &utf8_length, (const short*)name16.begin(), name_length - 1 );
|
||||
temp[utf8_length] = '\0';
|
||||
|
||||
name8.resize( utf8_length + 1 );
|
||||
memcpy( name8.begin(), temp, utf8_length + 1 );
|
||||
set_name( name8.begin(), name16.begin() );
|
||||
set_info( item.Size, 0, (item.CrcDefined ? item.Crc : 0) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
blargg_err_t Zip7_Extractor::rewind_v()
|
||||
{
|
||||
return seek_arc_v( 0 );
|
||||
}
|
||||
|
||||
fex_pos_t Zip7_Extractor::tell_arc_v() const
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
blargg_err_t Zip7_Extractor::seek_arc_v( fex_pos_t pos )
|
||||
{
|
||||
assert( 0 <= pos && pos <= (int) impl->db.db.NumFiles );
|
||||
|
||||
index = pos - 1;
|
||||
return next_v();
|
||||
}
|
||||
|
||||
blargg_err_t Zip7_Extractor::data_v( void const** out )
|
||||
{
|
||||
impl->in_err = NULL;
|
||||
size_t offset = 0;
|
||||
size_t count = 0;
|
||||
RETURN_ERR( zip7_err( SzArEx_Extract( &impl->db, &impl->look.s, index,
|
||||
&impl->block_index, &impl->buf, &impl->buf_size,
|
||||
&offset, &count, &zip7_alloc, &zip7_alloc_temp ) ) );
|
||||
assert( count == (size_t) size() );
|
||||
|
||||
*out = impl->buf + offset;
|
||||
return blargg_ok;
|
||||
}
|
||||
// File_Extractor 1.0.0. http://www.slack.net/~ant/
|
||||
|
||||
#include "Zip7_Extractor.h"
|
||||
|
||||
extern "C" {
|
||||
#include "7z_C/7z.h"
|
||||
#include "7z_C/7zAlloc.h"
|
||||
#include "7z_C/7zCrc.h"
|
||||
}
|
||||
|
||||
#include <time.h>
|
||||
|
||||
/* Copyright (C) 2005-2009 Shay Green. This module is free software; you
|
||||
can redistribute it and/or modify it under the terms of the GNU Lesser
|
||||
General Public License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version. This
|
||||
module 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 Lesser General Public License for more
|
||||
details. You should have received a copy of the GNU Lesser General Public
|
||||
License along with this module; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
#include "blargg_source.h"
|
||||
|
||||
static ISzAlloc zip7_alloc = { SzAlloc, SzFree };
|
||||
static ISzAlloc zip7_alloc_temp = { SzAllocTemp, SzFreeTemp };
|
||||
|
||||
struct Zip7_Extractor_Impl :
|
||||
ISeekInStream
|
||||
{
|
||||
CLookToRead look;
|
||||
CSzArEx db;
|
||||
|
||||
// SzExtract state
|
||||
UInt32 block_index;
|
||||
Byte* buf;
|
||||
size_t buf_size;
|
||||
|
||||
File_Reader* in;
|
||||
const char* in_err;
|
||||
};
|
||||
|
||||
extern "C"
|
||||
{
|
||||
// 7-zip callbacks pass an ISeekInStream* for data, so we must cast it
|
||||
// back to ISeekInStream* FIRST, then cast to our Impl structure
|
||||
|
||||
static SRes zip7_read_( void* vstream, void* out, size_t* size )
|
||||
{
|
||||
assert( out && size );
|
||||
ISeekInStream* stream = STATIC_CAST(ISeekInStream*,vstream);
|
||||
Zip7_Extractor_Impl* impl = STATIC_CAST(Zip7_Extractor_Impl*,stream);
|
||||
|
||||
long lsize = *size;
|
||||
blargg_err_t err = impl->in->read_avail( out, &lsize );
|
||||
if ( err )
|
||||
{
|
||||
*size = 0;
|
||||
impl->in_err = err;
|
||||
return SZ_ERROR_READ;
|
||||
}
|
||||
|
||||
*size = lsize;
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
static SRes zip7_seek_( void* vstream, Int64* pos, ESzSeek mode )
|
||||
{
|
||||
ISeekInStream* stream = STATIC_CAST(ISeekInStream*,vstream);
|
||||
Zip7_Extractor_Impl* impl = STATIC_CAST(Zip7_Extractor_Impl*,stream);
|
||||
|
||||
// assert( mode != SZ_SEEK_CUR ); // never used
|
||||
|
||||
if ( mode == SZ_SEEK_END )
|
||||
{
|
||||
assert( *pos == 0 ); // only used to find file length
|
||||
*pos = impl->in->size();
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
// assert( mode == SZ_SEEK_SET );
|
||||
blargg_err_t err = impl->in->seek( *pos );
|
||||
if ( err )
|
||||
{
|
||||
// don't set in_err in this case, since it might be benign
|
||||
if ( err == blargg_err_file_eof )
|
||||
return SZ_ERROR_INPUT_EOF;
|
||||
|
||||
impl->in_err = err;
|
||||
return SZ_ERROR_READ;
|
||||
}
|
||||
|
||||
return SZ_OK;
|
||||
}
|
||||
}
|
||||
|
||||
blargg_err_t Zip7_Extractor::zip7_err( int err )
|
||||
{
|
||||
// TODO: ignore in_err in some cases? unsure about which error to use
|
||||
blargg_err_t in_err = impl->in_err;
|
||||
impl->in_err = NULL;
|
||||
if ( in_err )
|
||||
{
|
||||
check( err != SZ_OK );
|
||||
return in_err;
|
||||
}
|
||||
|
||||
switch ( err )
|
||||
{
|
||||
case SZ_OK: return blargg_ok;
|
||||
case SZ_ERROR_MEM: return blargg_err_memory;
|
||||
case SZ_ERROR_READ: return blargg_err_file_io;
|
||||
case SZ_ERROR_CRC:
|
||||
case SZ_ERROR_DATA:
|
||||
case SZ_ERROR_INPUT_EOF:
|
||||
case SZ_ERROR_ARCHIVE: return blargg_err_file_corrupt;
|
||||
case SZ_ERROR_UNSUPPORTED: return blargg_err_file_feature;
|
||||
case SZ_ERROR_NO_ARCHIVE: return blargg_err_file_type;
|
||||
}
|
||||
|
||||
return blargg_err_generic;
|
||||
}
|
||||
|
||||
static blargg_err_t init_7z()
|
||||
{
|
||||
static bool inited;
|
||||
if ( !inited )
|
||||
{
|
||||
inited = true;
|
||||
CrcGenerateTable();
|
||||
}
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
static File_Extractor* new_7z()
|
||||
{
|
||||
return BLARGG_NEW Zip7_Extractor;
|
||||
}
|
||||
|
||||
fex_type_t_ const fex_7z_type [1] = {{
|
||||
".7z",
|
||||
&new_7z,
|
||||
"7-zip archive",
|
||||
&init_7z
|
||||
}};
|
||||
|
||||
Zip7_Extractor::Zip7_Extractor() :
|
||||
File_Extractor( fex_7z_type )
|
||||
{
|
||||
impl = NULL;
|
||||
}
|
||||
|
||||
Zip7_Extractor::~Zip7_Extractor()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
blargg_err_t Zip7_Extractor::open_v()
|
||||
{
|
||||
RETURN_ERR( init_7z() );
|
||||
|
||||
if ( !impl )
|
||||
{
|
||||
impl = (Zip7_Extractor_Impl*) malloc( sizeof *impl );
|
||||
CHECK_ALLOC( impl );
|
||||
}
|
||||
|
||||
impl->in = &arc();
|
||||
impl->block_index = (UInt32) -1;
|
||||
impl->buf = NULL;
|
||||
impl->buf_size = 0;
|
||||
|
||||
LookToRead_CreateVTable( &impl->look, false );
|
||||
impl->ISeekInStream::Read = zip7_read_;
|
||||
impl->ISeekInStream::Seek = zip7_seek_;
|
||||
impl->look.realStream = impl;
|
||||
LookToRead_Init( &impl->look );
|
||||
|
||||
SzArEx_Init( &impl->db );
|
||||
|
||||
impl->in_err = NULL;
|
||||
RETURN_ERR( zip7_err( SzArEx_Open( &impl->db, &impl->look.s,
|
||||
&zip7_alloc, &zip7_alloc_temp ) ) );
|
||||
|
||||
return seek_arc_v( 0 );
|
||||
}
|
||||
|
||||
void Zip7_Extractor::close_v()
|
||||
{
|
||||
if ( impl )
|
||||
{
|
||||
if ( impl->in )
|
||||
{
|
||||
impl->in = NULL;
|
||||
SzArEx_Free( &impl->db, &zip7_alloc );
|
||||
}
|
||||
IAlloc_Free( &zip7_alloc, impl->buf );
|
||||
free( impl );
|
||||
impl = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// This method was taken from ogre-7z (thanks), and is thus LGPL
|
||||
bool Zip7_Extractor::utf16ToUtf8( unsigned char* dest, size_t* destLen, const short* src, size_t srcLen )
|
||||
{
|
||||
static const unsigned char sUtf8Limits[5] = { 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
|
||||
|
||||
size_t destPos = 0, srcPos = 0;
|
||||
for(;;)
|
||||
{
|
||||
unsigned int numAdds;
|
||||
unsigned long value;
|
||||
if( srcPos == srcLen )
|
||||
{
|
||||
*destLen = destPos;
|
||||
return true;
|
||||
}
|
||||
|
||||
value = src[srcPos++];
|
||||
if( value < 0x80 )
|
||||
{
|
||||
if( dest )
|
||||
{
|
||||
dest[destPos] = (char)value;
|
||||
}
|
||||
destPos++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if( value >= 0xD800 && value < 0xE000 )
|
||||
{
|
||||
unsigned long c2;
|
||||
if( value >= 0xDC00 || srcPos == srcLen )
|
||||
break;
|
||||
|
||||
c2 = src[srcPos++];
|
||||
if( c2 < 0xDC00 || c2 >= 0xE000 )
|
||||
break;
|
||||
|
||||
value = (((value - 0xD800) << 10) | (c2 - 0xDC00)) + 0x10000;
|
||||
}
|
||||
|
||||
for( numAdds = 1; numAdds < 5; numAdds++ )
|
||||
{
|
||||
if( value < (((UInt32)1) << (numAdds * 5 + 6)) )
|
||||
break;
|
||||
}
|
||||
|
||||
if( dest )
|
||||
{
|
||||
dest[destPos] = (char)(sUtf8Limits[numAdds - 1] + (value >> (6 * numAdds)));
|
||||
}
|
||||
|
||||
destPos++;
|
||||
do
|
||||
{
|
||||
numAdds--;
|
||||
if( dest )
|
||||
{
|
||||
dest[destPos] = (char)(0x80 + ((value >> (6 * numAdds)) & 0x3F));
|
||||
}
|
||||
destPos++;
|
||||
}
|
||||
while( numAdds != 0 );
|
||||
}
|
||||
|
||||
*destLen = destPos;
|
||||
return false;
|
||||
}
|
||||
|
||||
blargg_err_t Zip7_Extractor::next_v()
|
||||
{
|
||||
while ( ++index < (int) impl->db.db.NumFiles )
|
||||
{
|
||||
CSzFileItem const& item = impl->db.db.Files [index];
|
||||
if ( !item.IsDir )
|
||||
{
|
||||
unsigned long date = 0;
|
||||
if ( item.MTimeDefined )
|
||||
{
|
||||
const UInt64 epoch = ((UInt64)0x019db1de << 32) + 0xd53e8000;
|
||||
/* 0x019db1ded53e8000ULL: 1970-01-01 00:00:00 (UTC) */
|
||||
struct tm tm;
|
||||
|
||||
UInt64 time = ((UInt64)item.MTime.High << 32) + item.MTime.Low - epoch;
|
||||
time /= 1000000;
|
||||
|
||||
time_t _time = time;
|
||||
|
||||
#ifdef _WIN32
|
||||
tm = *localtime( &_time );
|
||||
#else
|
||||
localtime_r( &_time, &tm );
|
||||
#endif
|
||||
|
||||
date = (( tm.tm_sec >> 1 ) & 0x1F) |
|
||||
(( tm.tm_min & 0x3F ) << 5 ) |
|
||||
(( tm.tm_hour & 0x1F ) << 11 ) |
|
||||
(( tm.tm_mday & 0x1F ) << 16 ) |
|
||||
(( ( tm.tm_mon + 1 ) & 0x0F ) << 21 ) |
|
||||
(( ( tm.tm_year - 80 ) & 0x7F ) << 25 );
|
||||
}
|
||||
|
||||
size_t name_length = SzArEx_GetFileNameUtf16( &impl->db, index, 0 );
|
||||
size_t utf8_length = 0;
|
||||
name16.resize( name_length );
|
||||
SzArEx_GetFileNameUtf16( &impl->db, index, ( UInt16 * ) name16.begin() );
|
||||
unsigned char temp[1024];
|
||||
utf16ToUtf8( temp, &utf8_length, (const short*)name16.begin(), name_length - 1 );
|
||||
temp[utf8_length] = '\0';
|
||||
|
||||
name8.resize( utf8_length + 1 );
|
||||
memcpy( name8.begin(), temp, utf8_length + 1 );
|
||||
set_name( name8.begin(), name16.begin() );
|
||||
set_info( item.Size, 0, (item.CrcDefined ? item.Crc : 0) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
blargg_err_t Zip7_Extractor::rewind_v()
|
||||
{
|
||||
return seek_arc_v( 0 );
|
||||
}
|
||||
|
||||
fex_pos_t Zip7_Extractor::tell_arc_v() const
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
blargg_err_t Zip7_Extractor::seek_arc_v( fex_pos_t pos )
|
||||
{
|
||||
assert( 0 <= pos && pos <= (int) impl->db.db.NumFiles );
|
||||
|
||||
index = pos - 1;
|
||||
return next_v();
|
||||
}
|
||||
|
||||
blargg_err_t Zip7_Extractor::data_v( void const** out )
|
||||
{
|
||||
impl->in_err = NULL;
|
||||
size_t offset = 0;
|
||||
size_t count = 0;
|
||||
RETURN_ERR( zip7_err( SzArEx_Extract( &impl->db, &impl->look.s, index,
|
||||
&impl->block_index, &impl->buf, &impl->buf_size,
|
||||
&offset, &count, &zip7_alloc, &zip7_alloc_temp ) ) );
|
||||
assert( count == (size_t) size() );
|
||||
|
||||
*out = impl->buf + offset;
|
||||
return blargg_ok;
|
||||
}
|
||||
|
|
|
@ -1,38 +1,38 @@
|
|||
// 7-zip archive extractor
|
||||
|
||||
// File_Extractor 1.0.0
|
||||
#ifndef ZIP7_EXTRACTOR_H
|
||||
#define ZIP7_EXTRACTOR_H
|
||||
|
||||
#include "File_Extractor.h"
|
||||
|
||||
struct Zip7_Extractor_Impl;
|
||||
|
||||
class Zip7_Extractor : public File_Extractor {
|
||||
public:
|
||||
Zip7_Extractor();
|
||||
virtual ~Zip7_Extractor();
|
||||
|
||||
protected:
|
||||
virtual blargg_err_t open_v();
|
||||
virtual void close_v();
|
||||
|
||||
virtual blargg_err_t next_v();
|
||||
virtual blargg_err_t rewind_v();
|
||||
virtual fex_pos_t tell_arc_v() const;
|
||||
virtual blargg_err_t seek_arc_v( fex_pos_t );
|
||||
|
||||
virtual blargg_err_t data_v( void const** out );
|
||||
|
||||
bool utf16ToUtf8( unsigned char* dest, size_t* destLen, const short* src, size_t srcLen );
|
||||
|
||||
private:
|
||||
Zip7_Extractor_Impl* impl;
|
||||
int index;
|
||||
blargg_vector<char> name8;
|
||||
blargg_vector<wchar_t> name16;
|
||||
|
||||
blargg_err_t zip7_err( int err );
|
||||
};
|
||||
|
||||
#endif
|
||||
// 7-zip archive extractor
|
||||
|
||||
// File_Extractor 1.0.0
|
||||
#ifndef ZIP7_EXTRACTOR_H
|
||||
#define ZIP7_EXTRACTOR_H
|
||||
|
||||
#include "File_Extractor.h"
|
||||
|
||||
struct Zip7_Extractor_Impl;
|
||||
|
||||
class Zip7_Extractor : public File_Extractor {
|
||||
public:
|
||||
Zip7_Extractor();
|
||||
virtual ~Zip7_Extractor();
|
||||
|
||||
protected:
|
||||
virtual blargg_err_t open_v();
|
||||
virtual void close_v();
|
||||
|
||||
virtual blargg_err_t next_v();
|
||||
virtual blargg_err_t rewind_v();
|
||||
virtual fex_pos_t tell_arc_v() const;
|
||||
virtual blargg_err_t seek_arc_v( fex_pos_t );
|
||||
|
||||
virtual blargg_err_t data_v( void const** out );
|
||||
|
||||
bool utf16ToUtf8( unsigned char* dest, size_t* destLen, const short* src, size_t srcLen );
|
||||
|
||||
private:
|
||||
Zip7_Extractor_Impl* impl;
|
||||
int index;
|
||||
blargg_vector<char> name8;
|
||||
blargg_vector<wchar_t> name16;
|
||||
|
||||
blargg_err_t zip7_err( int err );
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,390 +1,390 @@
|
|||
// File_Extractor 1.0.0. http://www.slack.net/~ant/
|
||||
|
||||
#include "Zip_Extractor.h"
|
||||
|
||||
#include "blargg_endian.h"
|
||||
|
||||
/* Copyright (C) 2005-2009 Shay Green. This module is free software; you
|
||||
can redistribute it and/or modify it under the terms of the GNU Lesser
|
||||
General Public License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version. This
|
||||
module 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 Lesser General Public License for more
|
||||
details. You should have received a copy of the GNU Lesser General Public
|
||||
License along with this module; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
/* To avoid copying filename string from catalog, I terminate it by modifying
|
||||
catalog data. This potentially requires moving the first byte of the type
|
||||
of the next entry elsewhere; I move it to the first byte of made_by. Kind
|
||||
of hacky, but I'd rather not have to allocate memory for a copy of it. */
|
||||
|
||||
#include "blargg_source.h"
|
||||
|
||||
/* Reads this much from end of file when first opening. Only this much is
|
||||
searched for the end catalog entry. If whole catalog is within this data,
|
||||
nothing more needs to be read on open. */
|
||||
int const end_read_size = 8 * 1024;
|
||||
|
||||
/* Reads are are made using file offset that's a multiple of this,
|
||||
increasing performance. */
|
||||
int const disk_block_size = 4 * 1024;
|
||||
|
||||
// Read buffer used for extracting file data
|
||||
int const read_buf_size = 16 * 1024;
|
||||
|
||||
struct header_t
|
||||
{
|
||||
char type [4];
|
||||
byte vers [2];
|
||||
byte flags [2];
|
||||
byte method [2];
|
||||
byte date [4];
|
||||
byte crc [4];
|
||||
byte raw_size [4];
|
||||
byte size [4];
|
||||
byte filename_len [2];
|
||||
byte extra_len [2];
|
||||
char filename [2]; // [filename_len]
|
||||
//char extra [extra_len];
|
||||
};
|
||||
int const header_size = 30;
|
||||
|
||||
struct entry_t
|
||||
{
|
||||
char type [4];
|
||||
byte made_by [2];
|
||||
byte vers [2];
|
||||
byte flags [2];
|
||||
byte method [2];
|
||||
byte date [4];
|
||||
byte crc [4];
|
||||
byte raw_size [4];
|
||||
byte size [4];
|
||||
byte filename_len [2];
|
||||
byte extra_len [2];
|
||||
byte comment_len [2];
|
||||
byte disk [2];
|
||||
byte int_attrib [2];
|
||||
byte ext_attrib [4];
|
||||
byte file_offset [4];
|
||||
char filename [2]; // [filename_len]
|
||||
//char extra [extra_len];
|
||||
//char comment [comment_len];
|
||||
};
|
||||
int const entry_size = 46;
|
||||
|
||||
struct end_entry_t
|
||||
{
|
||||
char type [4];
|
||||
byte disk [2];
|
||||
byte first_disk [2];
|
||||
byte disk_entry_count [2];
|
||||
byte entry_count [2];
|
||||
byte dir_size [4];
|
||||
byte dir_offset [4];
|
||||
byte comment_len [2];
|
||||
char comment [2]; // [comment_len]
|
||||
};
|
||||
int const end_entry_size = 22;
|
||||
|
||||
static blargg_err_t init_zip()
|
||||
{
|
||||
get_crc_table(); // initialize zlib's CRC-32 tables
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
static File_Extractor* new_zip()
|
||||
{
|
||||
return BLARGG_NEW Zip_Extractor;
|
||||
}
|
||||
|
||||
fex_type_t_ const fex_zip_type [1] = {{
|
||||
".zip",
|
||||
&new_zip,
|
||||
"ZIP archive",
|
||||
&init_zip
|
||||
}};
|
||||
|
||||
Zip_Extractor::Zip_Extractor() :
|
||||
File_Extractor( fex_zip_type )
|
||||
{
|
||||
Zip_Extractor::clear_file_v();
|
||||
|
||||
// If these fail, structures had extra padding inserted by compiler
|
||||
assert( offsetof (header_t,filename) == header_size );
|
||||
assert( offsetof (entry_t,filename) == entry_size );
|
||||
assert( offsetof (end_entry_t,comment) == end_entry_size );
|
||||
}
|
||||
|
||||
Zip_Extractor::~Zip_Extractor()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
blargg_err_t Zip_Extractor::open_path_v()
|
||||
{
|
||||
RETURN_ERR( open_arc_file( true ) );
|
||||
return File_Extractor::open_path_v();
|
||||
}
|
||||
|
||||
inline
|
||||
void Zip_Extractor::reorder_entry_header( int offset )
|
||||
{
|
||||
catalog [offset + 0] = 0;
|
||||
catalog [offset + 4] = 'P';
|
||||
}
|
||||
|
||||
blargg_err_t Zip_Extractor::open_v()
|
||||
{
|
||||
if ( arc().size() < end_entry_size )
|
||||
return blargg_err_file_type;
|
||||
|
||||
// Read final end_read_size bytes of file
|
||||
int file_pos = max( 0, arc().size() - end_read_size );
|
||||
file_pos -= file_pos % disk_block_size;
|
||||
RETURN_ERR( catalog.resize( arc().size() - file_pos ) );
|
||||
RETURN_ERR( arc().seek( file_pos ) );
|
||||
RETURN_ERR( arc().read( catalog.begin(), catalog.size() ) );
|
||||
|
||||
// Find end-of-catalog entry
|
||||
int end_pos = catalog.size() - end_entry_size;
|
||||
while ( end_pos >= 0 && memcmp( &catalog [end_pos], "PK\5\6", 4 ) )
|
||||
end_pos--;
|
||||
if ( end_pos < 0 )
|
||||
return blargg_err_file_type;
|
||||
end_entry_t const& end_entry = (end_entry_t&) catalog [end_pos];
|
||||
end_pos += file_pos;
|
||||
|
||||
// some idiotic zip compressors add data to end of zip without setting comment len
|
||||
// check( arc().size() == end_pos + end_entry_size + get_le16( end_entry.comment_len ) );
|
||||
|
||||
// Find file offset of beginning of catalog
|
||||
catalog_begin = get_le32( end_entry.dir_offset );
|
||||
int catalog_size = end_pos - catalog_begin;
|
||||
if ( catalog_size < 0 )
|
||||
return blargg_err_file_corrupt;
|
||||
catalog_size += end_entry_size;
|
||||
|
||||
// See if catalog is entirely contained in bytes already read
|
||||
int begin_offset = catalog_begin - file_pos;
|
||||
if ( begin_offset >= 0 )
|
||||
memmove( catalog.begin(), &catalog [begin_offset], catalog_size );
|
||||
|
||||
RETURN_ERR( catalog.resize( catalog_size ) );
|
||||
if ( begin_offset < 0 )
|
||||
{
|
||||
// Catalog begins before bytes read, so it needs to be read
|
||||
RETURN_ERR( arc().seek( catalog_begin ) );
|
||||
RETURN_ERR( arc().read( catalog.begin(), catalog.size() ) );
|
||||
}
|
||||
|
||||
// First entry in catalog should be a file or end of archive
|
||||
if ( memcmp( catalog.begin(), "PK\1\2", 4 ) && memcmp( catalog.begin(), "PK\5\6", 4 ) )
|
||||
return blargg_err_file_type;
|
||||
|
||||
reorder_entry_header( 0 );
|
||||
return rewind_v();
|
||||
}
|
||||
|
||||
void Zip_Extractor::close_v()
|
||||
{
|
||||
catalog.clear();
|
||||
}
|
||||
|
||||
// Scanning
|
||||
|
||||
inline
|
||||
static bool is_normal_file( entry_t const& e, unsigned len )
|
||||
{
|
||||
int last_char = (len ? e.filename [len - 1] : '/');
|
||||
bool is_dir = (last_char == '/' || last_char == '\\');
|
||||
if ( is_dir && get_le32( e.size ) == 0 )
|
||||
return false;
|
||||
check( !is_dir );
|
||||
|
||||
// Mac OS X puts meta-information in separate files with normal extensions,
|
||||
// so they must be filtered out or caller will mistake them for normal files.
|
||||
if ( e.made_by[1] == 3 )
|
||||
{
|
||||
const char* dir = strrchr( e.filename, '/' );
|
||||
if ( dir )
|
||||
dir++;
|
||||
else
|
||||
dir = e.filename;
|
||||
|
||||
if ( *dir == '.' )
|
||||
return false;
|
||||
|
||||
if ( !strcmp( dir, "Icon\x0D" ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
blargg_err_t Zip_Extractor::update_info( bool advance_first )
|
||||
{
|
||||
while ( 1 )
|
||||
{
|
||||
entry_t& e = (entry_t&) catalog [catalog_pos];
|
||||
|
||||
if ( memcmp( e.type, "\0K\1\2P", 5 ) && memcmp( e.type, "PK\1\2", 4 ) )
|
||||
{
|
||||
check( !memcmp( e.type, "\0K\5\6P", 5 ) );
|
||||
break;
|
||||
}
|
||||
|
||||
unsigned len = get_le16( e.filename_len );
|
||||
int next_offset = catalog_pos + entry_size + len + get_le16( e.extra_len ) +
|
||||
get_le16( e.comment_len );
|
||||
if ( (unsigned) next_offset > catalog.size() - end_entry_size )
|
||||
return blargg_err_file_corrupt;
|
||||
|
||||
if ( catalog [next_offset] == 'P' )
|
||||
reorder_entry_header( next_offset );
|
||||
|
||||
if ( !advance_first )
|
||||
{
|
||||
e.filename [len] = 0; // terminate name
|
||||
|
||||
if ( is_normal_file( e, len ) )
|
||||
{
|
||||
set_name( e.filename );
|
||||
set_info( get_le32( e.size ), get_le32( e.date ), get_le32( e.crc ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
catalog_pos = next_offset;
|
||||
advance_first = false;
|
||||
}
|
||||
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
blargg_err_t Zip_Extractor::next_v()
|
||||
{
|
||||
return update_info( true );
|
||||
}
|
||||
|
||||
blargg_err_t Zip_Extractor::rewind_v()
|
||||
{
|
||||
return seek_arc_v( 0 );
|
||||
}
|
||||
|
||||
fex_pos_t Zip_Extractor::tell_arc_v() const
|
||||
{
|
||||
return catalog_pos;
|
||||
}
|
||||
|
||||
blargg_err_t Zip_Extractor::seek_arc_v( fex_pos_t pos )
|
||||
{
|
||||
assert( 0 <= pos && (size_t) pos <= catalog.size() - end_entry_size );
|
||||
|
||||
catalog_pos = pos;
|
||||
return update_info( false );
|
||||
}
|
||||
|
||||
// Reading
|
||||
|
||||
void Zip_Extractor::clear_file_v()
|
||||
{
|
||||
buf.end();
|
||||
}
|
||||
|
||||
blargg_err_t Zip_Extractor::inflater_read( void* data, void* out, int* count )
|
||||
{
|
||||
Zip_Extractor& self = *STATIC_CAST(Zip_Extractor*,data);
|
||||
|
||||
if ( *count > self.raw_remain )
|
||||
*count = self.raw_remain;
|
||||
|
||||
self.raw_remain -= *count;
|
||||
|
||||
return self.arc().read( out, *count );
|
||||
}
|
||||
|
||||
blargg_err_t Zip_Extractor::fill_buf( int offset, int buf_size, int initial_read )
|
||||
{
|
||||
raw_remain = arc().size() - offset;
|
||||
RETURN_ERR( arc().seek( offset ) );
|
||||
return buf.begin( inflater_read, this, buf_size, initial_read );
|
||||
}
|
||||
|
||||
blargg_err_t Zip_Extractor::first_read( int count )
|
||||
{
|
||||
entry_t const& e = (entry_t&) catalog [catalog_pos];
|
||||
|
||||
// Determine compression
|
||||
{
|
||||
int method = get_le16( e.method );
|
||||
if ( (method && method != Z_DEFLATED) || get_le16( e.vers ) > 20 )
|
||||
return BLARGG_ERR( BLARGG_ERR_FILE_FEATURE, "compression method" );
|
||||
file_deflated = (method != 0);
|
||||
}
|
||||
|
||||
int raw_size = get_le32( e.raw_size );
|
||||
|
||||
int file_offset = get_le32( e.file_offset );
|
||||
int align = file_offset % disk_block_size;
|
||||
{
|
||||
// read header
|
||||
int buf_size = 3 * disk_block_size - 1 + raw_size; // space for all raw data
|
||||
buf_size -= buf_size % disk_block_size;
|
||||
int initial_read = buf_size;
|
||||
if ( !file_deflated || count < size() )
|
||||
{
|
||||
buf_size = read_buf_size;
|
||||
initial_read = disk_block_size * 2;
|
||||
}
|
||||
// TODO: avoid re-reading if buffer already has data we want?
|
||||
RETURN_ERR( fill_buf( file_offset - align, buf_size, initial_read ) );
|
||||
}
|
||||
header_t const& h = (header_t&) buf.data() [align];
|
||||
if ( buf.filled() < align + header_size || memcmp( h.type, "PK\3\4", 4 ) )
|
||||
return blargg_err_file_corrupt;
|
||||
|
||||
// CRCs of header and file data
|
||||
correct_crc = get_le32( h.crc );
|
||||
if ( !correct_crc )
|
||||
correct_crc = get_le32( e.crc );
|
||||
check( correct_crc == get_le32( e.crc ) ); // catalog CRC should match
|
||||
crc = ::crc32( 0, NULL, 0 );
|
||||
|
||||
// Data offset
|
||||
int data_offset = file_offset + header_size +
|
||||
get_le16( h.filename_len ) + get_le16( h.extra_len );
|
||||
if ( data_offset + raw_size > catalog_begin )
|
||||
return blargg_err_file_corrupt;
|
||||
|
||||
// Refill buffer if there's lots of extra data after header
|
||||
int buf_offset = data_offset - file_offset + align;
|
||||
if ( buf_offset > buf.filled() )
|
||||
{
|
||||
// TODO: this will almost never occur, making it a good place for bugs
|
||||
buf_offset = data_offset % disk_block_size;
|
||||
RETURN_ERR( fill_buf( data_offset - buf_offset, read_buf_size, disk_block_size ) );
|
||||
}
|
||||
|
||||
raw_remain = raw_size - (buf.filled() - buf_offset);
|
||||
return buf.set_mode( (file_deflated ? buf.mode_raw_deflate : buf.mode_copy), buf_offset );
|
||||
}
|
||||
|
||||
blargg_err_t Zip_Extractor::extract_v( void* out, int count )
|
||||
{
|
||||
if ( tell() == 0 )
|
||||
RETURN_ERR( first_read( count ) );
|
||||
|
||||
int actual = count;
|
||||
RETURN_ERR( buf.read( out, &actual ) );
|
||||
if ( actual < count )
|
||||
return blargg_err_file_corrupt;
|
||||
|
||||
crc = ::crc32( crc, (byte const*) out, count );
|
||||
if ( count == reader().remain() && crc != correct_crc )
|
||||
return blargg_err_file_corrupt;
|
||||
|
||||
return blargg_ok;
|
||||
}
|
||||
// File_Extractor 1.0.0. http://www.slack.net/~ant/
|
||||
|
||||
#include "Zip_Extractor.h"
|
||||
|
||||
#include "blargg_endian.h"
|
||||
|
||||
/* Copyright (C) 2005-2009 Shay Green. This module is free software; you
|
||||
can redistribute it and/or modify it under the terms of the GNU Lesser
|
||||
General Public License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version. This
|
||||
module 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 Lesser General Public License for more
|
||||
details. You should have received a copy of the GNU Lesser General Public
|
||||
License along with this module; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
/* To avoid copying filename string from catalog, I terminate it by modifying
|
||||
catalog data. This potentially requires moving the first byte of the type
|
||||
of the next entry elsewhere; I move it to the first byte of made_by. Kind
|
||||
of hacky, but I'd rather not have to allocate memory for a copy of it. */
|
||||
|
||||
#include "blargg_source.h"
|
||||
|
||||
/* Reads this much from end of file when first opening. Only this much is
|
||||
searched for the end catalog entry. If whole catalog is within this data,
|
||||
nothing more needs to be read on open. */
|
||||
int const end_read_size = 8 * 1024;
|
||||
|
||||
/* Reads are are made using file offset that's a multiple of this,
|
||||
increasing performance. */
|
||||
int const disk_block_size = 4 * 1024;
|
||||
|
||||
// Read buffer used for extracting file data
|
||||
int const read_buf_size = 16 * 1024;
|
||||
|
||||
struct header_t
|
||||
{
|
||||
char type [4];
|
||||
byte vers [2];
|
||||
byte flags [2];
|
||||
byte method [2];
|
||||
byte date [4];
|
||||
byte crc [4];
|
||||
byte raw_size [4];
|
||||
byte size [4];
|
||||
byte filename_len [2];
|
||||
byte extra_len [2];
|
||||
char filename [2]; // [filename_len]
|
||||
//char extra [extra_len];
|
||||
};
|
||||
int const header_size = 30;
|
||||
|
||||
struct entry_t
|
||||
{
|
||||
char type [4];
|
||||
byte made_by [2];
|
||||
byte vers [2];
|
||||
byte flags [2];
|
||||
byte method [2];
|
||||
byte date [4];
|
||||
byte crc [4];
|
||||
byte raw_size [4];
|
||||
byte size [4];
|
||||
byte filename_len [2];
|
||||
byte extra_len [2];
|
||||
byte comment_len [2];
|
||||
byte disk [2];
|
||||
byte int_attrib [2];
|
||||
byte ext_attrib [4];
|
||||
byte file_offset [4];
|
||||
char filename [2]; // [filename_len]
|
||||
//char extra [extra_len];
|
||||
//char comment [comment_len];
|
||||
};
|
||||
int const entry_size = 46;
|
||||
|
||||
struct end_entry_t
|
||||
{
|
||||
char type [4];
|
||||
byte disk [2];
|
||||
byte first_disk [2];
|
||||
byte disk_entry_count [2];
|
||||
byte entry_count [2];
|
||||
byte dir_size [4];
|
||||
byte dir_offset [4];
|
||||
byte comment_len [2];
|
||||
char comment [2]; // [comment_len]
|
||||
};
|
||||
int const end_entry_size = 22;
|
||||
|
||||
static blargg_err_t init_zip()
|
||||
{
|
||||
get_crc_table(); // initialize zlib's CRC-32 tables
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
static File_Extractor* new_zip()
|
||||
{
|
||||
return BLARGG_NEW Zip_Extractor;
|
||||
}
|
||||
|
||||
fex_type_t_ const fex_zip_type [1] = {{
|
||||
".zip",
|
||||
&new_zip,
|
||||
"ZIP archive",
|
||||
&init_zip
|
||||
}};
|
||||
|
||||
Zip_Extractor::Zip_Extractor() :
|
||||
File_Extractor( fex_zip_type )
|
||||
{
|
||||
Zip_Extractor::clear_file_v();
|
||||
|
||||
// If these fail, structures had extra padding inserted by compiler
|
||||
assert( offsetof (header_t,filename) == header_size );
|
||||
assert( offsetof (entry_t,filename) == entry_size );
|
||||
assert( offsetof (end_entry_t,comment) == end_entry_size );
|
||||
}
|
||||
|
||||
Zip_Extractor::~Zip_Extractor()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
blargg_err_t Zip_Extractor::open_path_v()
|
||||
{
|
||||
RETURN_ERR( open_arc_file( true ) );
|
||||
return File_Extractor::open_path_v();
|
||||
}
|
||||
|
||||
inline
|
||||
void Zip_Extractor::reorder_entry_header( int offset )
|
||||
{
|
||||
catalog [offset + 0] = 0;
|
||||
catalog [offset + 4] = 'P';
|
||||
}
|
||||
|
||||
blargg_err_t Zip_Extractor::open_v()
|
||||
{
|
||||
if ( arc().size() < end_entry_size )
|
||||
return blargg_err_file_type;
|
||||
|
||||
// Read final end_read_size bytes of file
|
||||
int file_pos = max( 0, arc().size() - end_read_size );
|
||||
file_pos -= file_pos % disk_block_size;
|
||||
RETURN_ERR( catalog.resize( arc().size() - file_pos ) );
|
||||
RETURN_ERR( arc().seek( file_pos ) );
|
||||
RETURN_ERR( arc().read( catalog.begin(), catalog.size() ) );
|
||||
|
||||
// Find end-of-catalog entry
|
||||
int end_pos = catalog.size() - end_entry_size;
|
||||
while ( end_pos >= 0 && memcmp( &catalog [end_pos], "PK\5\6", 4 ) )
|
||||
end_pos--;
|
||||
if ( end_pos < 0 )
|
||||
return blargg_err_file_type;
|
||||
end_entry_t const& end_entry = (end_entry_t&) catalog [end_pos];
|
||||
end_pos += file_pos;
|
||||
|
||||
// some idiotic zip compressors add data to end of zip without setting comment len
|
||||
// check( arc().size() == end_pos + end_entry_size + get_le16( end_entry.comment_len ) );
|
||||
|
||||
// Find file offset of beginning of catalog
|
||||
catalog_begin = get_le32( end_entry.dir_offset );
|
||||
int catalog_size = end_pos - catalog_begin;
|
||||
if ( catalog_size < 0 )
|
||||
return blargg_err_file_corrupt;
|
||||
catalog_size += end_entry_size;
|
||||
|
||||
// See if catalog is entirely contained in bytes already read
|
||||
int begin_offset = catalog_begin - file_pos;
|
||||
if ( begin_offset >= 0 )
|
||||
memmove( catalog.begin(), &catalog [begin_offset], catalog_size );
|
||||
|
||||
RETURN_ERR( catalog.resize( catalog_size ) );
|
||||
if ( begin_offset < 0 )
|
||||
{
|
||||
// Catalog begins before bytes read, so it needs to be read
|
||||
RETURN_ERR( arc().seek( catalog_begin ) );
|
||||
RETURN_ERR( arc().read( catalog.begin(), catalog.size() ) );
|
||||
}
|
||||
|
||||
// First entry in catalog should be a file or end of archive
|
||||
if ( memcmp( catalog.begin(), "PK\1\2", 4 ) && memcmp( catalog.begin(), "PK\5\6", 4 ) )
|
||||
return blargg_err_file_type;
|
||||
|
||||
reorder_entry_header( 0 );
|
||||
return rewind_v();
|
||||
}
|
||||
|
||||
void Zip_Extractor::close_v()
|
||||
{
|
||||
catalog.clear();
|
||||
}
|
||||
|
||||
// Scanning
|
||||
|
||||
inline
|
||||
static bool is_normal_file( entry_t const& e, unsigned len )
|
||||
{
|
||||
int last_char = (len ? e.filename [len - 1] : '/');
|
||||
bool is_dir = (last_char == '/' || last_char == '\\');
|
||||
if ( is_dir && get_le32( e.size ) == 0 )
|
||||
return false;
|
||||
check( !is_dir );
|
||||
|
||||
// Mac OS X puts meta-information in separate files with normal extensions,
|
||||
// so they must be filtered out or caller will mistake them for normal files.
|
||||
if ( e.made_by[1] == 3 )
|
||||
{
|
||||
const char* dir = strrchr( e.filename, '/' );
|
||||
if ( dir )
|
||||
dir++;
|
||||
else
|
||||
dir = e.filename;
|
||||
|
||||
if ( *dir == '.' )
|
||||
return false;
|
||||
|
||||
if ( !strcmp( dir, "Icon\x0D" ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
blargg_err_t Zip_Extractor::update_info( bool advance_first )
|
||||
{
|
||||
while ( 1 )
|
||||
{
|
||||
entry_t& e = (entry_t&) catalog [catalog_pos];
|
||||
|
||||
if ( memcmp( e.type, "\0K\1\2P", 5 ) && memcmp( e.type, "PK\1\2", 4 ) )
|
||||
{
|
||||
check( !memcmp( e.type, "\0K\5\6P", 5 ) );
|
||||
break;
|
||||
}
|
||||
|
||||
unsigned len = get_le16( e.filename_len );
|
||||
int next_offset = catalog_pos + entry_size + len + get_le16( e.extra_len ) +
|
||||
get_le16( e.comment_len );
|
||||
if ( (unsigned) next_offset > catalog.size() - end_entry_size )
|
||||
return blargg_err_file_corrupt;
|
||||
|
||||
if ( catalog [next_offset] == 'P' )
|
||||
reorder_entry_header( next_offset );
|
||||
|
||||
if ( !advance_first )
|
||||
{
|
||||
e.filename [len] = 0; // terminate name
|
||||
|
||||
if ( is_normal_file( e, len ) )
|
||||
{
|
||||
set_name( e.filename );
|
||||
set_info( get_le32( e.size ), get_le32( e.date ), get_le32( e.crc ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
catalog_pos = next_offset;
|
||||
advance_first = false;
|
||||
}
|
||||
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
blargg_err_t Zip_Extractor::next_v()
|
||||
{
|
||||
return update_info( true );
|
||||
}
|
||||
|
||||
blargg_err_t Zip_Extractor::rewind_v()
|
||||
{
|
||||
return seek_arc_v( 0 );
|
||||
}
|
||||
|
||||
fex_pos_t Zip_Extractor::tell_arc_v() const
|
||||
{
|
||||
return catalog_pos;
|
||||
}
|
||||
|
||||
blargg_err_t Zip_Extractor::seek_arc_v( fex_pos_t pos )
|
||||
{
|
||||
assert( 0 <= pos && (size_t) pos <= catalog.size() - end_entry_size );
|
||||
|
||||
catalog_pos = pos;
|
||||
return update_info( false );
|
||||
}
|
||||
|
||||
// Reading
|
||||
|
||||
void Zip_Extractor::clear_file_v()
|
||||
{
|
||||
buf.end();
|
||||
}
|
||||
|
||||
blargg_err_t Zip_Extractor::inflater_read( void* data, void* out, int* count )
|
||||
{
|
||||
Zip_Extractor& self = *STATIC_CAST(Zip_Extractor*,data);
|
||||
|
||||
if ( *count > self.raw_remain )
|
||||
*count = self.raw_remain;
|
||||
|
||||
self.raw_remain -= *count;
|
||||
|
||||
return self.arc().read( out, *count );
|
||||
}
|
||||
|
||||
blargg_err_t Zip_Extractor::fill_buf( int offset, int buf_size, int initial_read )
|
||||
{
|
||||
raw_remain = arc().size() - offset;
|
||||
RETURN_ERR( arc().seek( offset ) );
|
||||
return buf.begin( inflater_read, this, buf_size, initial_read );
|
||||
}
|
||||
|
||||
blargg_err_t Zip_Extractor::first_read( int count )
|
||||
{
|
||||
entry_t const& e = (entry_t&) catalog [catalog_pos];
|
||||
|
||||
// Determine compression
|
||||
{
|
||||
int method = get_le16( e.method );
|
||||
if ( (method && method != Z_DEFLATED) || get_le16( e.vers ) > 20 )
|
||||
return BLARGG_ERR( BLARGG_ERR_FILE_FEATURE, "compression method" );
|
||||
file_deflated = (method != 0);
|
||||
}
|
||||
|
||||
int raw_size = get_le32( e.raw_size );
|
||||
|
||||
int file_offset = get_le32( e.file_offset );
|
||||
int align = file_offset % disk_block_size;
|
||||
{
|
||||
// read header
|
||||
int buf_size = 3 * disk_block_size - 1 + raw_size; // space for all raw data
|
||||
buf_size -= buf_size % disk_block_size;
|
||||
int initial_read = buf_size;
|
||||
if ( !file_deflated || count < size() )
|
||||
{
|
||||
buf_size = read_buf_size;
|
||||
initial_read = disk_block_size * 2;
|
||||
}
|
||||
// TODO: avoid re-reading if buffer already has data we want?
|
||||
RETURN_ERR( fill_buf( file_offset - align, buf_size, initial_read ) );
|
||||
}
|
||||
header_t const& h = (header_t&) buf.data() [align];
|
||||
if ( buf.filled() < align + header_size || memcmp( h.type, "PK\3\4", 4 ) )
|
||||
return blargg_err_file_corrupt;
|
||||
|
||||
// CRCs of header and file data
|
||||
correct_crc = get_le32( h.crc );
|
||||
if ( !correct_crc )
|
||||
correct_crc = get_le32( e.crc );
|
||||
check( correct_crc == get_le32( e.crc ) ); // catalog CRC should match
|
||||
crc = ::crc32( 0, NULL, 0 );
|
||||
|
||||
// Data offset
|
||||
int data_offset = file_offset + header_size +
|
||||
get_le16( h.filename_len ) + get_le16( h.extra_len );
|
||||
if ( data_offset + raw_size > catalog_begin )
|
||||
return blargg_err_file_corrupt;
|
||||
|
||||
// Refill buffer if there's lots of extra data after header
|
||||
int buf_offset = data_offset - file_offset + align;
|
||||
if ( buf_offset > buf.filled() )
|
||||
{
|
||||
// TODO: this will almost never occur, making it a good place for bugs
|
||||
buf_offset = data_offset % disk_block_size;
|
||||
RETURN_ERR( fill_buf( data_offset - buf_offset, read_buf_size, disk_block_size ) );
|
||||
}
|
||||
|
||||
raw_remain = raw_size - (buf.filled() - buf_offset);
|
||||
return buf.set_mode( (file_deflated ? buf.mode_raw_deflate : buf.mode_copy), buf_offset );
|
||||
}
|
||||
|
||||
blargg_err_t Zip_Extractor::extract_v( void* out, int count )
|
||||
{
|
||||
if ( tell() == 0 )
|
||||
RETURN_ERR( first_read( count ) );
|
||||
|
||||
int actual = count;
|
||||
RETURN_ERR( buf.read( out, &actual ) );
|
||||
if ( actual < count )
|
||||
return blargg_err_file_corrupt;
|
||||
|
||||
crc = ::crc32( crc, (byte const*) out, count );
|
||||
if ( count == reader().remain() && crc != correct_crc )
|
||||
return blargg_err_file_corrupt;
|
||||
|
||||
return blargg_ok;
|
||||
}
|
||||
|
|
|
@ -1,45 +1,45 @@
|
|||
// ZIP archive extractor. Only supports deflation and store (no compression).
|
||||
|
||||
// File_Extractor 1.0.0
|
||||
#ifndef ZIP_EXTRACTOR_H
|
||||
#define ZIP_EXTRACTOR_H
|
||||
|
||||
#include "File_Extractor.h"
|
||||
#include "Zlib_Inflater.h"
|
||||
|
||||
class Zip_Extractor : public File_Extractor {
|
||||
public:
|
||||
Zip_Extractor();
|
||||
virtual ~Zip_Extractor();
|
||||
|
||||
protected:
|
||||
virtual blargg_err_t open_path_v();
|
||||
virtual blargg_err_t open_v();
|
||||
virtual void close_v();
|
||||
|
||||
virtual void clear_file_v();
|
||||
virtual blargg_err_t next_v();
|
||||
virtual blargg_err_t rewind_v();
|
||||
virtual fex_pos_t tell_arc_v() const;
|
||||
virtual blargg_err_t seek_arc_v( fex_pos_t );
|
||||
|
||||
virtual blargg_err_t extract_v( void*, int );
|
||||
|
||||
private:
|
||||
blargg_vector<char> catalog;
|
||||
int catalog_begin; // offset of first catalog entry in file (to detect corruption)
|
||||
int catalog_pos; // position of current entry in catalog
|
||||
int raw_remain; // bytes remaining to be read from zip file for current file
|
||||
unsigned crc; // ongoing CRC of extracted bytes
|
||||
unsigned correct_crc;
|
||||
bool file_deflated;
|
||||
Zlib_Inflater buf;
|
||||
|
||||
blargg_err_t fill_buf( int offset, int buf_size, int initial_read );
|
||||
blargg_err_t update_info( bool advance_first );
|
||||
blargg_err_t first_read( int count );
|
||||
void reorder_entry_header( int offset );
|
||||
static blargg_err_t inflater_read( void* data, void* out, int* count );
|
||||
};
|
||||
|
||||
#endif
|
||||
// ZIP archive extractor. Only supports deflation and store (no compression).
|
||||
|
||||
// File_Extractor 1.0.0
|
||||
#ifndef ZIP_EXTRACTOR_H
|
||||
#define ZIP_EXTRACTOR_H
|
||||
|
||||
#include "File_Extractor.h"
|
||||
#include "Zlib_Inflater.h"
|
||||
|
||||
class Zip_Extractor : public File_Extractor {
|
||||
public:
|
||||
Zip_Extractor();
|
||||
virtual ~Zip_Extractor();
|
||||
|
||||
protected:
|
||||
virtual blargg_err_t open_path_v();
|
||||
virtual blargg_err_t open_v();
|
||||
virtual void close_v();
|
||||
|
||||
virtual void clear_file_v();
|
||||
virtual blargg_err_t next_v();
|
||||
virtual blargg_err_t rewind_v();
|
||||
virtual fex_pos_t tell_arc_v() const;
|
||||
virtual blargg_err_t seek_arc_v( fex_pos_t );
|
||||
|
||||
virtual blargg_err_t extract_v( void*, int );
|
||||
|
||||
private:
|
||||
blargg_vector<char> catalog;
|
||||
int catalog_begin; // offset of first catalog entry in file (to detect corruption)
|
||||
int catalog_pos; // position of current entry in catalog
|
||||
int raw_remain; // bytes remaining to be read from zip file for current file
|
||||
unsigned crc; // ongoing CRC of extracted bytes
|
||||
unsigned correct_crc;
|
||||
bool file_deflated;
|
||||
Zlib_Inflater buf;
|
||||
|
||||
blargg_err_t fill_buf( int offset, int buf_size, int initial_read );
|
||||
blargg_err_t update_info( bool advance_first );
|
||||
blargg_err_t first_read( int count );
|
||||
void reorder_entry_header( int offset );
|
||||
static blargg_err_t inflater_read( void* data, void* out, int* count );
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,257 +1,257 @@
|
|||
// File_Extractor 1.0.0. http://www.slack.net/~ant/
|
||||
|
||||
#include "Zlib_Inflater.h"
|
||||
|
||||
/* Copyright (C) 2006-2009 Shay Green. This module is free software; you
|
||||
can redistribute it and/or modify it under the terms of the GNU Lesser
|
||||
General Public License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version. This
|
||||
module 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 Lesser General Public License for more
|
||||
details. You should have received a copy of the GNU Lesser General Public
|
||||
License along with this module; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
#include "blargg_source.h"
|
||||
|
||||
int const block_size = 4096;
|
||||
|
||||
static const char* get_zlib_err( int code )
|
||||
{
|
||||
assert( code != Z_OK );
|
||||
switch ( code )
|
||||
{
|
||||
case Z_MEM_ERROR: return blargg_err_memory;
|
||||
case Z_DATA_ERROR: return blargg_err_file_corrupt;
|
||||
// TODO: handle more error codes
|
||||
}
|
||||
|
||||
const char* str = zError( code );
|
||||
if ( !str )
|
||||
str = BLARGG_ERR( BLARGG_ERR_GENERIC, "problem unzipping data" );
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
void Zlib_Inflater::end()
|
||||
{
|
||||
if ( deflated_ )
|
||||
{
|
||||
deflated_ = false;
|
||||
if ( inflateEnd( &zbuf ) )
|
||||
check( false );
|
||||
}
|
||||
buf.clear();
|
||||
|
||||
static z_stream const empty = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
memcpy( &zbuf, &empty, sizeof zbuf );
|
||||
}
|
||||
|
||||
Zlib_Inflater::Zlib_Inflater()
|
||||
{
|
||||
deflated_ = false;
|
||||
end(); // initialize things
|
||||
}
|
||||
|
||||
Zlib_Inflater::~Zlib_Inflater()
|
||||
{
|
||||
end();
|
||||
}
|
||||
|
||||
blargg_err_t Zlib_Inflater::fill_buf( int count )
|
||||
{
|
||||
byte* out = buf.end() - count;
|
||||
RETURN_ERR( callback( user_data, out, &count ) );
|
||||
zbuf.avail_in = count;
|
||||
zbuf.next_in = out;
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
blargg_err_t Zlib_Inflater::begin( callback_t new_callback, void* new_user_data,
|
||||
int new_buf_size, int initial_read )
|
||||
{
|
||||
callback = new_callback;
|
||||
user_data = new_user_data;
|
||||
|
||||
end();
|
||||
|
||||
// TODO: decide whether using different size on alloc failure is a good idea
|
||||
//RETURN_ERR( buf.resize( new_buf_size ? new_buf_size : 4 * block_size ) );
|
||||
if ( new_buf_size && buf.resize( new_buf_size ) )
|
||||
{
|
||||
ACK_FAILURE();
|
||||
new_buf_size = 0;
|
||||
}
|
||||
|
||||
if ( !new_buf_size )
|
||||
{
|
||||
RETURN_ERR( buf.resize( 4 * block_size ) );
|
||||
initial_read = 0;
|
||||
}
|
||||
|
||||
// Fill buffer with some data, less than normal buffer size since caller might
|
||||
// just be examining beginning of file.
|
||||
return fill_buf( initial_read ? initial_read : block_size );
|
||||
}
|
||||
|
||||
blargg_err_t Zlib_Inflater::set_mode( mode_t mode, int data_offset )
|
||||
{
|
||||
zbuf.next_in += data_offset;
|
||||
zbuf.avail_in -= data_offset;
|
||||
|
||||
if ( mode == mode_auto )
|
||||
{
|
||||
// examine buffer for gzip header
|
||||
mode = mode_copy;
|
||||
unsigned const min_gzip_size = 2 + 8 + 8;
|
||||
if ( zbuf.avail_in >= min_gzip_size &&
|
||||
zbuf.next_in [0] == 0x1F && zbuf.next_in [1] == 0x8B )
|
||||
mode = mode_ungz;
|
||||
}
|
||||
|
||||
if ( mode != mode_copy )
|
||||
{
|
||||
int wb = MAX_WBITS + 16; // have zlib handle gzip header
|
||||
if ( mode == mode_raw_deflate )
|
||||
wb = -MAX_WBITS;
|
||||
|
||||
int zerr = inflateInit2( &zbuf, wb );
|
||||
if ( zerr )
|
||||
{
|
||||
zbuf.next_in = NULL;
|
||||
return get_zlib_err( zerr );
|
||||
}
|
||||
|
||||
deflated_ = true;
|
||||
}
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
/*
|
||||
// Reads/inflates entire stream. All input must be in buffer, and count must be total
|
||||
// of all output.
|
||||
blargg_err_t read_all( void* out, int count );
|
||||
|
||||
|
||||
// zlib automatically applies this optimization (uses inflateFast)
|
||||
// TODO: remove
|
||||
blargg_err_t Zlib_Inflater::read_all( void* out, int count )
|
||||
{
|
||||
if ( deflated_ )
|
||||
{
|
||||
zbuf.next_out = (Bytef*) out;
|
||||
zbuf.avail_out = count;
|
||||
|
||||
int err = inflate( &zbuf, Z_FINISH );
|
||||
|
||||
if ( zbuf.avail_out || err != Z_STREAM_END )
|
||||
return blargg_err_file_corrupt;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( zbuf.avail_in < count )
|
||||
return blargg_err_file_corrupt;
|
||||
|
||||
memcpy( out, zbuf.next_in, count );
|
||||
|
||||
zbuf.next_in += count;
|
||||
zbuf.avail_in -= count;
|
||||
}
|
||||
|
||||
return blargg_ok;
|
||||
}
|
||||
*/
|
||||
|
||||
blargg_err_t Zlib_Inflater::read( void* out, int* count_io )
|
||||
{
|
||||
int remain = *count_io;
|
||||
if ( remain && zbuf.next_in )
|
||||
{
|
||||
if ( deflated_ )
|
||||
{
|
||||
zbuf.next_out = (Bytef*) out;
|
||||
zbuf.avail_out = remain;
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
uInt old_avail_in = zbuf.avail_in;
|
||||
int err = inflate( &zbuf, Z_NO_FLUSH );
|
||||
if ( err == Z_STREAM_END )
|
||||
{
|
||||
remain = zbuf.avail_out;
|
||||
end();
|
||||
break; // no more data to inflate
|
||||
}
|
||||
|
||||
if ( err && (err != Z_BUF_ERROR || old_avail_in) )
|
||||
return get_zlib_err( err );
|
||||
|
||||
if ( !zbuf.avail_out )
|
||||
{
|
||||
remain = 0;
|
||||
break; // requested number of bytes inflated
|
||||
}
|
||||
|
||||
if ( zbuf.avail_in )
|
||||
{
|
||||
// inflate() should never leave input if there's still space for output
|
||||
check( false );
|
||||
return blargg_err_file_corrupt;
|
||||
}
|
||||
|
||||
RETURN_ERR( fill_buf( buf.size() ) );
|
||||
if ( !zbuf.avail_in )
|
||||
return blargg_err_file_corrupt; // stream didn't end but there's no more data
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while ( 1 )
|
||||
{
|
||||
// copy buffered data
|
||||
if ( zbuf.avail_in )
|
||||
{
|
||||
long count = zbuf.avail_in;
|
||||
if ( count > remain )
|
||||
count = remain;
|
||||
memcpy( out, zbuf.next_in, count );
|
||||
zbuf.total_out += count;
|
||||
out = (char*) out + count;
|
||||
remain -= count;
|
||||
zbuf.next_in += count;
|
||||
zbuf.avail_in -= count;
|
||||
}
|
||||
|
||||
if ( !zbuf.avail_in && zbuf.next_in < buf.end() )
|
||||
{
|
||||
end();
|
||||
break;
|
||||
}
|
||||
|
||||
// read large request directly
|
||||
if ( remain + zbuf.total_out % block_size >= buf.size() )
|
||||
{
|
||||
int count = remain;
|
||||
RETURN_ERR( callback( user_data, out, &count ) );
|
||||
zbuf.total_out += count;
|
||||
out = (char*) out + count;
|
||||
remain -= count;
|
||||
|
||||
if ( remain )
|
||||
{
|
||||
end();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !remain )
|
||||
break;
|
||||
|
||||
RETURN_ERR( fill_buf( buf.size() - zbuf.total_out % block_size ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
*count_io -= remain;
|
||||
return blargg_ok;
|
||||
}
|
||||
// File_Extractor 1.0.0. http://www.slack.net/~ant/
|
||||
|
||||
#include "Zlib_Inflater.h"
|
||||
|
||||
/* Copyright (C) 2006-2009 Shay Green. This module is free software; you
|
||||
can redistribute it and/or modify it under the terms of the GNU Lesser
|
||||
General Public License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version. This
|
||||
module 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 Lesser General Public License for more
|
||||
details. You should have received a copy of the GNU Lesser General Public
|
||||
License along with this module; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
#include "blargg_source.h"
|
||||
|
||||
int const block_size = 4096;
|
||||
|
||||
static const char* get_zlib_err( int code )
|
||||
{
|
||||
assert( code != Z_OK );
|
||||
switch ( code )
|
||||
{
|
||||
case Z_MEM_ERROR: return blargg_err_memory;
|
||||
case Z_DATA_ERROR: return blargg_err_file_corrupt;
|
||||
// TODO: handle more error codes
|
||||
}
|
||||
|
||||
const char* str = zError( code );
|
||||
if ( !str )
|
||||
str = BLARGG_ERR( BLARGG_ERR_GENERIC, "problem unzipping data" );
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
void Zlib_Inflater::end()
|
||||
{
|
||||
if ( deflated_ )
|
||||
{
|
||||
deflated_ = false;
|
||||
if ( inflateEnd( &zbuf ) )
|
||||
check( false );
|
||||
}
|
||||
buf.clear();
|
||||
|
||||
static z_stream const empty = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
memcpy( &zbuf, &empty, sizeof zbuf );
|
||||
}
|
||||
|
||||
Zlib_Inflater::Zlib_Inflater()
|
||||
{
|
||||
deflated_ = false;
|
||||
end(); // initialize things
|
||||
}
|
||||
|
||||
Zlib_Inflater::~Zlib_Inflater()
|
||||
{
|
||||
end();
|
||||
}
|
||||
|
||||
blargg_err_t Zlib_Inflater::fill_buf( int count )
|
||||
{
|
||||
byte* out = buf.end() - count;
|
||||
RETURN_ERR( callback( user_data, out, &count ) );
|
||||
zbuf.avail_in = count;
|
||||
zbuf.next_in = out;
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
blargg_err_t Zlib_Inflater::begin( callback_t new_callback, void* new_user_data,
|
||||
int new_buf_size, int initial_read )
|
||||
{
|
||||
callback = new_callback;
|
||||
user_data = new_user_data;
|
||||
|
||||
end();
|
||||
|
||||
// TODO: decide whether using different size on alloc failure is a good idea
|
||||
//RETURN_ERR( buf.resize( new_buf_size ? new_buf_size : 4 * block_size ) );
|
||||
if ( new_buf_size && buf.resize( new_buf_size ) )
|
||||
{
|
||||
ACK_FAILURE();
|
||||
new_buf_size = 0;
|
||||
}
|
||||
|
||||
if ( !new_buf_size )
|
||||
{
|
||||
RETURN_ERR( buf.resize( 4 * block_size ) );
|
||||
initial_read = 0;
|
||||
}
|
||||
|
||||
// Fill buffer with some data, less than normal buffer size since caller might
|
||||
// just be examining beginning of file.
|
||||
return fill_buf( initial_read ? initial_read : block_size );
|
||||
}
|
||||
|
||||
blargg_err_t Zlib_Inflater::set_mode( mode_t mode, int data_offset )
|
||||
{
|
||||
zbuf.next_in += data_offset;
|
||||
zbuf.avail_in -= data_offset;
|
||||
|
||||
if ( mode == mode_auto )
|
||||
{
|
||||
// examine buffer for gzip header
|
||||
mode = mode_copy;
|
||||
unsigned const min_gzip_size = 2 + 8 + 8;
|
||||
if ( zbuf.avail_in >= min_gzip_size &&
|
||||
zbuf.next_in [0] == 0x1F && zbuf.next_in [1] == 0x8B )
|
||||
mode = mode_ungz;
|
||||
}
|
||||
|
||||
if ( mode != mode_copy )
|
||||
{
|
||||
int wb = MAX_WBITS + 16; // have zlib handle gzip header
|
||||
if ( mode == mode_raw_deflate )
|
||||
wb = -MAX_WBITS;
|
||||
|
||||
int zerr = inflateInit2( &zbuf, wb );
|
||||
if ( zerr )
|
||||
{
|
||||
zbuf.next_in = NULL;
|
||||
return get_zlib_err( zerr );
|
||||
}
|
||||
|
||||
deflated_ = true;
|
||||
}
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
/*
|
||||
// Reads/inflates entire stream. All input must be in buffer, and count must be total
|
||||
// of all output.
|
||||
blargg_err_t read_all( void* out, int count );
|
||||
|
||||
|
||||
// zlib automatically applies this optimization (uses inflateFast)
|
||||
// TODO: remove
|
||||
blargg_err_t Zlib_Inflater::read_all( void* out, int count )
|
||||
{
|
||||
if ( deflated_ )
|
||||
{
|
||||
zbuf.next_out = (Bytef*) out;
|
||||
zbuf.avail_out = count;
|
||||
|
||||
int err = inflate( &zbuf, Z_FINISH );
|
||||
|
||||
if ( zbuf.avail_out || err != Z_STREAM_END )
|
||||
return blargg_err_file_corrupt;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( zbuf.avail_in < count )
|
||||
return blargg_err_file_corrupt;
|
||||
|
||||
memcpy( out, zbuf.next_in, count );
|
||||
|
||||
zbuf.next_in += count;
|
||||
zbuf.avail_in -= count;
|
||||
}
|
||||
|
||||
return blargg_ok;
|
||||
}
|
||||
*/
|
||||
|
||||
blargg_err_t Zlib_Inflater::read( void* out, int* count_io )
|
||||
{
|
||||
int remain = *count_io;
|
||||
if ( remain && zbuf.next_in )
|
||||
{
|
||||
if ( deflated_ )
|
||||
{
|
||||
zbuf.next_out = (Bytef*) out;
|
||||
zbuf.avail_out = remain;
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
uInt old_avail_in = zbuf.avail_in;
|
||||
int err = inflate( &zbuf, Z_NO_FLUSH );
|
||||
if ( err == Z_STREAM_END )
|
||||
{
|
||||
remain = zbuf.avail_out;
|
||||
end();
|
||||
break; // no more data to inflate
|
||||
}
|
||||
|
||||
if ( err && (err != Z_BUF_ERROR || old_avail_in) )
|
||||
return get_zlib_err( err );
|
||||
|
||||
if ( !zbuf.avail_out )
|
||||
{
|
||||
remain = 0;
|
||||
break; // requested number of bytes inflated
|
||||
}
|
||||
|
||||
if ( zbuf.avail_in )
|
||||
{
|
||||
// inflate() should never leave input if there's still space for output
|
||||
check( false );
|
||||
return blargg_err_file_corrupt;
|
||||
}
|
||||
|
||||
RETURN_ERR( fill_buf( buf.size() ) );
|
||||
if ( !zbuf.avail_in )
|
||||
return blargg_err_file_corrupt; // stream didn't end but there's no more data
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while ( 1 )
|
||||
{
|
||||
// copy buffered data
|
||||
if ( zbuf.avail_in )
|
||||
{
|
||||
long count = zbuf.avail_in;
|
||||
if ( count > remain )
|
||||
count = remain;
|
||||
memcpy( out, zbuf.next_in, count );
|
||||
zbuf.total_out += count;
|
||||
out = (char*) out + count;
|
||||
remain -= count;
|
||||
zbuf.next_in += count;
|
||||
zbuf.avail_in -= count;
|
||||
}
|
||||
|
||||
if ( !zbuf.avail_in && zbuf.next_in < buf.end() )
|
||||
{
|
||||
end();
|
||||
break;
|
||||
}
|
||||
|
||||
// read large request directly
|
||||
if ( remain + zbuf.total_out % block_size >= buf.size() )
|
||||
{
|
||||
int count = remain;
|
||||
RETURN_ERR( callback( user_data, out, &count ) );
|
||||
zbuf.total_out += count;
|
||||
out = (char*) out + count;
|
||||
remain -= count;
|
||||
|
||||
if ( remain )
|
||||
{
|
||||
end();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !remain )
|
||||
break;
|
||||
|
||||
RETURN_ERR( fill_buf( buf.size() - zbuf.total_out % block_size ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
*count_io -= remain;
|
||||
return blargg_ok;
|
||||
}
|
||||
|
|
|
@ -1,70 +1,70 @@
|
|||
// Simplifies use of zlib for inflating data
|
||||
|
||||
// File_Extractor 1.0.0
|
||||
#ifndef ZLIB_INFLATER_H
|
||||
#define ZLIB_INFLATER_H
|
||||
|
||||
#include "blargg_common.h"
|
||||
#include "Data_Reader.h"
|
||||
#include "zlib.h"
|
||||
|
||||
class Zlib_Inflater {
|
||||
public:
|
||||
|
||||
// Reads at most min(*count,bytes_until_eof()) bytes into *out and set *count
|
||||
// to that number, or returns error if that many can't be read.
|
||||
typedef blargg_err_t (*callback_t)( void* user_data, void* out, int* count );
|
||||
|
||||
// Begins by setting callback and filling buffer. Default buffer is 16K and
|
||||
// filled to 4K, or specify buf_size and initial_read for custom buffer size
|
||||
// and how much to read initially.
|
||||
blargg_err_t begin( callback_t, void* user_data,
|
||||
int buf_size = 0, int initial_read = 0 );
|
||||
|
||||
// Data read into buffer by begin()
|
||||
const unsigned char* data() const { return zbuf.next_in; }
|
||||
int filled() const { return zbuf.avail_in; }
|
||||
|
||||
// Begins inflation using specified mode. Using mode_auto selects between
|
||||
// mode_copy and mode_ungz by examining first two bytes of buffer. Use
|
||||
// buf_offset to specify where data begins in buffer, in case there is
|
||||
// header data that should be skipped.
|
||||
enum mode_t { mode_copy, mode_ungz, mode_raw_deflate, mode_auto };
|
||||
blargg_err_t set_mode( mode_t, int buf_offset = 0 );
|
||||
|
||||
// True if set_mode() has been called with mode_ungz or mode_raw_deflate
|
||||
bool deflated() const { return deflated_; }
|
||||
|
||||
// Reads/inflates at most *count_io bytes into *out and sets *count_io to actual
|
||||
// number of bytes read (less than requested if end of data was reached).
|
||||
// Buffers source data internally, even in copy mode, so input file can be
|
||||
// unbuffered without sacrificing performance.
|
||||
blargg_err_t read( void* out, int* count_io );
|
||||
|
||||
// Total number of bytes read since begin()
|
||||
int tell() const { return zbuf.total_out; }
|
||||
|
||||
// Ends inflation and frees memory
|
||||
void end();
|
||||
|
||||
private:
|
||||
// noncopyable
|
||||
Zlib_Inflater( const Zlib_Inflater& );
|
||||
Zlib_Inflater& operator = ( const Zlib_Inflater& );
|
||||
|
||||
// Implementation
|
||||
public:
|
||||
Zlib_Inflater();
|
||||
~Zlib_Inflater();
|
||||
|
||||
private:
|
||||
z_stream_s zbuf;
|
||||
blargg_vector<unsigned char> buf;
|
||||
bool deflated_;
|
||||
callback_t callback;
|
||||
void* user_data;
|
||||
|
||||
blargg_err_t fill_buf( int count );
|
||||
};
|
||||
|
||||
#endif
|
||||
// Simplifies use of zlib for inflating data
|
||||
|
||||
// File_Extractor 1.0.0
|
||||
#ifndef ZLIB_INFLATER_H
|
||||
#define ZLIB_INFLATER_H
|
||||
|
||||
#include "blargg_common.h"
|
||||
#include "Data_Reader.h"
|
||||
#include "zlib.h"
|
||||
|
||||
class Zlib_Inflater {
|
||||
public:
|
||||
|
||||
// Reads at most min(*count,bytes_until_eof()) bytes into *out and set *count
|
||||
// to that number, or returns error if that many can't be read.
|
||||
typedef blargg_err_t (*callback_t)( void* user_data, void* out, int* count );
|
||||
|
||||
// Begins by setting callback and filling buffer. Default buffer is 16K and
|
||||
// filled to 4K, or specify buf_size and initial_read for custom buffer size
|
||||
// and how much to read initially.
|
||||
blargg_err_t begin( callback_t, void* user_data,
|
||||
int buf_size = 0, int initial_read = 0 );
|
||||
|
||||
// Data read into buffer by begin()
|
||||
const unsigned char* data() const { return zbuf.next_in; }
|
||||
int filled() const { return zbuf.avail_in; }
|
||||
|
||||
// Begins inflation using specified mode. Using mode_auto selects between
|
||||
// mode_copy and mode_ungz by examining first two bytes of buffer. Use
|
||||
// buf_offset to specify where data begins in buffer, in case there is
|
||||
// header data that should be skipped.
|
||||
enum mode_t { mode_copy, mode_ungz, mode_raw_deflate, mode_auto };
|
||||
blargg_err_t set_mode( mode_t, int buf_offset = 0 );
|
||||
|
||||
// True if set_mode() has been called with mode_ungz or mode_raw_deflate
|
||||
bool deflated() const { return deflated_; }
|
||||
|
||||
// Reads/inflates at most *count_io bytes into *out and sets *count_io to actual
|
||||
// number of bytes read (less than requested if end of data was reached).
|
||||
// Buffers source data internally, even in copy mode, so input file can be
|
||||
// unbuffered without sacrificing performance.
|
||||
blargg_err_t read( void* out, int* count_io );
|
||||
|
||||
// Total number of bytes read since begin()
|
||||
int tell() const { return zbuf.total_out; }
|
||||
|
||||
// Ends inflation and frees memory
|
||||
void end();
|
||||
|
||||
private:
|
||||
// noncopyable
|
||||
Zlib_Inflater( const Zlib_Inflater& );
|
||||
Zlib_Inflater& operator = ( const Zlib_Inflater& );
|
||||
|
||||
// Implementation
|
||||
public:
|
||||
Zlib_Inflater();
|
||||
~Zlib_Inflater();
|
||||
|
||||
private:
|
||||
z_stream_s zbuf;
|
||||
blargg_vector<unsigned char> buf;
|
||||
bool deflated_;
|
||||
callback_t callback;
|
||||
void* user_data;
|
||||
|
||||
blargg_err_t fill_buf( int count );
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,51 +1,51 @@
|
|||
// File_Extractor 1.0.0. http://www.slack.net/~ant/
|
||||
|
||||
#include "blargg_common.h"
|
||||
|
||||
/* Copyright (C) 2008-2009 Shay Green. This module is free software; you
|
||||
can redistribute it and/or modify it under the terms of the GNU Lesser
|
||||
General Public License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version. This
|
||||
module 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 Lesser General Public License for more
|
||||
details. You should have received a copy of the GNU Lesser General Public
|
||||
License along with this module; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
#include "blargg_source.h"
|
||||
|
||||
void blargg_vector_::init()
|
||||
{
|
||||
begin_ = NULL;
|
||||
size_ = 0;
|
||||
}
|
||||
|
||||
void blargg_vector_::clear()
|
||||
{
|
||||
void* p = begin_;
|
||||
begin_ = NULL;
|
||||
size_ = 0;
|
||||
free( p );
|
||||
}
|
||||
|
||||
blargg_err_t blargg_vector_::resize_( size_t n, size_t elem_size )
|
||||
{
|
||||
if ( n != size_ )
|
||||
{
|
||||
if ( n == 0 )
|
||||
{
|
||||
// Simpler to handle explicitly. Realloc will handle a size of 0,
|
||||
// but then we have to avoid raising an error for a NULL return.
|
||||
clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
void* p = realloc( begin_, n * elem_size );
|
||||
CHECK_ALLOC( p );
|
||||
begin_ = p;
|
||||
size_ = n;
|
||||
}
|
||||
}
|
||||
return blargg_ok;
|
||||
}
|
||||
// File_Extractor 1.0.0. http://www.slack.net/~ant/
|
||||
|
||||
#include "blargg_common.h"
|
||||
|
||||
/* Copyright (C) 2008-2009 Shay Green. This module is free software; you
|
||||
can redistribute it and/or modify it under the terms of the GNU Lesser
|
||||
General Public License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version. This
|
||||
module 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 Lesser General Public License for more
|
||||
details. You should have received a copy of the GNU Lesser General Public
|
||||
License along with this module; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
#include "blargg_source.h"
|
||||
|
||||
void blargg_vector_::init()
|
||||
{
|
||||
begin_ = NULL;
|
||||
size_ = 0;
|
||||
}
|
||||
|
||||
void blargg_vector_::clear()
|
||||
{
|
||||
void* p = begin_;
|
||||
begin_ = NULL;
|
||||
size_ = 0;
|
||||
free( p );
|
||||
}
|
||||
|
||||
blargg_err_t blargg_vector_::resize_( size_t n, size_t elem_size )
|
||||
{
|
||||
if ( n != size_ )
|
||||
{
|
||||
if ( n == 0 )
|
||||
{
|
||||
// Simpler to handle explicitly. Realloc will handle a size of 0,
|
||||
// but then we have to avoid raising an error for a NULL return.
|
||||
clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
void* p = realloc( begin_, n * elem_size );
|
||||
CHECK_ALLOC( p );
|
||||
begin_ = p;
|
||||
size_ = n;
|
||||
}
|
||||
}
|
||||
return blargg_ok;
|
||||
}
|
||||
|
|
|
@ -1,201 +1,201 @@
|
|||
// Sets up common environment for Shay Green's libraries.
|
||||
// To change configuration options, modify blargg_config.h, not this file.
|
||||
|
||||
// File_Extractor 1.0.0
|
||||
#ifndef BLARGG_COMMON_H
|
||||
#define BLARGG_COMMON_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
|
||||
typedef const char* blargg_err_t; // 0 on success, otherwise error string
|
||||
|
||||
// Success; no error
|
||||
int const blargg_ok = 0;
|
||||
|
||||
// BLARGG_RESTRICT: equivalent to C99's restrict, where supported
|
||||
#if __GNUC__ >= 3 || _MSC_VER >= 1100
|
||||
#define BLARGG_RESTRICT __restrict
|
||||
#else
|
||||
#define BLARGG_RESTRICT
|
||||
#endif
|
||||
|
||||
#if __cplusplus >= 199711
|
||||
#define BLARGG_MUTABLE mutable
|
||||
#else
|
||||
#define BLARGG_MUTABLE
|
||||
#endif
|
||||
|
||||
/* BLARGG_4CHAR('a','b','c','d') = 'abcd' (four character integer constant).
|
||||
I don't just use 'abcd' because that's implementation-dependent. */
|
||||
#define BLARGG_4CHAR( a, b, c, d ) \
|
||||
((a&0xFF)*0x1000000 + (b&0xFF)*0x10000 + (c&0xFF)*0x100 + (d&0xFF))
|
||||
|
||||
/* BLARGG_STATIC_ASSERT( expr ): Generates compile error if expr is 0.
|
||||
Can be used at file, function, or class scope. */
|
||||
#ifdef _MSC_VER
|
||||
// MSVC6 (_MSC_VER < 1300) __LINE__ fails when /Zl is specified
|
||||
#define BLARGG_STATIC_ASSERT( expr ) \
|
||||
void blargg_failed_( int (*arg) [2 / (int) !!(expr) - 1] )
|
||||
#else
|
||||
// Others fail when declaring same function multiple times in class,
|
||||
// so differentiate them by line
|
||||
#define BLARGG_STATIC_ASSERT( expr ) \
|
||||
void blargg_failed_( int (*arg) [2 / !!(expr) - 1] [__LINE__] )
|
||||
#endif
|
||||
|
||||
/* Pure virtual functions cause a vtable entry to a "called pure virtual"
|
||||
error handler, requiring linkage to the C++ runtime library. This macro is
|
||||
used in place of the "= 0", and simply expands to its argument. During
|
||||
development, it expands to "= 0", allowing detection of missing overrides. */
|
||||
#define BLARGG_PURE( def ) def
|
||||
|
||||
/* My code depends on ASCII anywhere a character or string constant is
|
||||
compared with data read from a file, and anywhere file data is read and
|
||||
treated as a string. */
|
||||
#if '\n'!=0x0A || ' '!=0x20 || '0'!=0x30 || 'A'!=0x41 || 'a'!=0x61
|
||||
#error "ASCII character set required"
|
||||
#endif
|
||||
|
||||
/* My code depends on int being at least 32 bits. Almost everything these days
|
||||
uses at least 32-bit ints, so it's hard to even find a system with 16-bit ints
|
||||
to test with. The issue can't be gotten around by using a suitable blargg_int
|
||||
everywhere either, because int is often converted to implicitly when doing
|
||||
arithmetic on smaller types. */
|
||||
#if UINT_MAX < 0xFFFFFFFF
|
||||
#error "int must be at least 32 bits"
|
||||
#endif
|
||||
|
||||
// In case compiler doesn't support these properly. Used rarely.
|
||||
#define STATIC_CAST(T,expr) static_cast<T> (expr)
|
||||
#define CONST_CAST( T,expr) const_cast<T> (expr)
|
||||
|
||||
// User configuration can override the above macros if necessary
|
||||
#include "blargg_config.h"
|
||||
|
||||
/* BLARGG_DEPRECATED [_TEXT] for any declarations/text to be removed in a
|
||||
future version. In GCC, we can let the compiler warn. In other compilers,
|
||||
we strip it out unless BLARGG_LEGACY is true. */
|
||||
#if BLARGG_LEGACY
|
||||
// Allow old client code to work without warnings
|
||||
#define BLARGG_DEPRECATED_TEXT( text ) text
|
||||
#define BLARGG_DEPRECATED( text ) text
|
||||
#elif __GNUC__ >= 4
|
||||
// In GCC, we can mark declarations and let the compiler warn
|
||||
#define BLARGG_DEPRECATED_TEXT( text ) text
|
||||
#define BLARGG_DEPRECATED( text ) __attribute__ ((deprecated)) text
|
||||
#else
|
||||
// By default, deprecated items are removed, to avoid use in new code
|
||||
#define BLARGG_DEPRECATED_TEXT( text )
|
||||
#define BLARGG_DEPRECATED( text )
|
||||
#endif
|
||||
|
||||
/* BOOST::int8_t, BOOST::int32_t, etc.
|
||||
I used BOOST since I originally was going to allow use of the boost library
|
||||
for prividing the definitions. If I'm defining them, they must be scoped or
|
||||
else they could conflict with the standard ones at global scope. Even if
|
||||
HAVE_STDINT_H isn't defined, I can't assume the typedefs won't exist at
|
||||
global scope already. */
|
||||
#if defined (HAVE_STDINT_H) || \
|
||||
UCHAR_MAX != 0xFF || USHRT_MAX != 0xFFFF || UINT_MAX != 0xFFFFFFFF
|
||||
#include <stdint.h>
|
||||
#define BOOST
|
||||
#else
|
||||
struct BOOST
|
||||
{
|
||||
typedef signed char int8_t;
|
||||
typedef unsigned char uint8_t;
|
||||
typedef short int16_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef int int32_t;
|
||||
typedef unsigned int uint32_t;
|
||||
};
|
||||
#endif
|
||||
|
||||
/* My code is not written with exceptions in mind, so either uses new (nothrow)
|
||||
OR overrides operator new in my classes. The former is best since clients
|
||||
creating objects will get standard exceptions on failure, but that causes it
|
||||
to require the standard C++ library. So, when the client is using the C
|
||||
interface, I override operator new to use malloc. */
|
||||
|
||||
// BLARGG_DISABLE_NOTHROW is put inside classes
|
||||
#ifndef BLARGG_DISABLE_NOTHROW
|
||||
// throw spec mandatory in ISO C++ if NULL can be returned
|
||||
#if __cplusplus >= 199711 || __GNUC__ >= 3 || _MSC_VER >= 1300
|
||||
#define BLARGG_THROWS_NOTHING throw ()
|
||||
#else
|
||||
#define BLARGG_THROWS_NOTHING
|
||||
#endif
|
||||
|
||||
#define BLARGG_DISABLE_NOTHROW \
|
||||
void* operator new ( size_t s ) BLARGG_THROWS_NOTHING { return malloc( s ); }\
|
||||
void operator delete( void* p ) BLARGG_THROWS_NOTHING { free( p ); }
|
||||
|
||||
#define BLARGG_NEW new
|
||||
#else
|
||||
// BLARGG_NEW is used in place of new in library code
|
||||
#include <new>
|
||||
#define BLARGG_NEW new (std::nothrow)
|
||||
#endif
|
||||
|
||||
class blargg_vector_ {
|
||||
protected:
|
||||
void* begin_;
|
||||
size_t size_;
|
||||
void init();
|
||||
blargg_err_t resize_( size_t n, size_t elem_size );
|
||||
public:
|
||||
size_t size() const { return size_; }
|
||||
void clear();
|
||||
};
|
||||
|
||||
// Very lightweight vector for POD types (no constructor/destructor)
|
||||
template<class T>
|
||||
class blargg_vector : public blargg_vector_ {
|
||||
union T_must_be_pod { T t; }; // fails if T is not POD
|
||||
public:
|
||||
blargg_vector() { init(); }
|
||||
~blargg_vector() { clear(); }
|
||||
|
||||
blargg_err_t resize( size_t n ) { return resize_( n, sizeof (T) ); }
|
||||
|
||||
T* begin() { return static_cast<T*> (begin_); }
|
||||
const T* begin() const { return static_cast<T*> (begin_); }
|
||||
|
||||
T* end() { return static_cast<T*> (begin_) + size_; }
|
||||
const T* end() const { return static_cast<T*> (begin_) + size_; }
|
||||
|
||||
T& operator [] ( size_t n )
|
||||
{
|
||||
assert( n < size_ );
|
||||
return static_cast<T*> (begin_) [n];
|
||||
}
|
||||
|
||||
const T& operator [] ( size_t n ) const
|
||||
{
|
||||
assert( n < size_ );
|
||||
return static_cast<T*> (begin_) [n];
|
||||
}
|
||||
};
|
||||
|
||||
// Callback function with user data.
|
||||
// blargg_callback<T> set_callback; // for user, this acts like...
|
||||
// void set_callback( T func, void* user_data = NULL ); // ...this
|
||||
// To call function, do set_callback.f( .. set_callback.data ... );
|
||||
template<class T>
|
||||
struct blargg_callback
|
||||
{
|
||||
T f;
|
||||
void* data;
|
||||
blargg_callback() { f = NULL; }
|
||||
void operator () ( T callback, void* user_data = NULL ) { f = callback; data = user_data; }
|
||||
};
|
||||
|
||||
BLARGG_DEPRECATED( typedef signed int blargg_long; )
|
||||
BLARGG_DEPRECATED( typedef unsigned int blargg_ulong; )
|
||||
#if BLARGG_LEGACY
|
||||
#define BOOST_STATIC_ASSERT BLARGG_STATIC_ASSERT
|
||||
#endif
|
||||
|
||||
#endif
|
||||
// Sets up common environment for Shay Green's libraries.
|
||||
// To change configuration options, modify blargg_config.h, not this file.
|
||||
|
||||
// File_Extractor 1.0.0
|
||||
#ifndef BLARGG_COMMON_H
|
||||
#define BLARGG_COMMON_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
|
||||
typedef const char* blargg_err_t; // 0 on success, otherwise error string
|
||||
|
||||
// Success; no error
|
||||
int const blargg_ok = 0;
|
||||
|
||||
// BLARGG_RESTRICT: equivalent to C99's restrict, where supported
|
||||
#if __GNUC__ >= 3 || _MSC_VER >= 1100
|
||||
#define BLARGG_RESTRICT __restrict
|
||||
#else
|
||||
#define BLARGG_RESTRICT
|
||||
#endif
|
||||
|
||||
#if __cplusplus >= 199711
|
||||
#define BLARGG_MUTABLE mutable
|
||||
#else
|
||||
#define BLARGG_MUTABLE
|
||||
#endif
|
||||
|
||||
/* BLARGG_4CHAR('a','b','c','d') = 'abcd' (four character integer constant).
|
||||
I don't just use 'abcd' because that's implementation-dependent. */
|
||||
#define BLARGG_4CHAR( a, b, c, d ) \
|
||||
((a&0xFF)*0x1000000 + (b&0xFF)*0x10000 + (c&0xFF)*0x100 + (d&0xFF))
|
||||
|
||||
/* BLARGG_STATIC_ASSERT( expr ): Generates compile error if expr is 0.
|
||||
Can be used at file, function, or class scope. */
|
||||
#ifdef _MSC_VER
|
||||
// MSVC6 (_MSC_VER < 1300) __LINE__ fails when /Zl is specified
|
||||
#define BLARGG_STATIC_ASSERT( expr ) \
|
||||
void blargg_failed_( int (*arg) [2 / (int) !!(expr) - 1] )
|
||||
#else
|
||||
// Others fail when declaring same function multiple times in class,
|
||||
// so differentiate them by line
|
||||
#define BLARGG_STATIC_ASSERT( expr ) \
|
||||
void blargg_failed_( int (*arg) [2 / !!(expr) - 1] [__LINE__] )
|
||||
#endif
|
||||
|
||||
/* Pure virtual functions cause a vtable entry to a "called pure virtual"
|
||||
error handler, requiring linkage to the C++ runtime library. This macro is
|
||||
used in place of the "= 0", and simply expands to its argument. During
|
||||
development, it expands to "= 0", allowing detection of missing overrides. */
|
||||
#define BLARGG_PURE( def ) def
|
||||
|
||||
/* My code depends on ASCII anywhere a character or string constant is
|
||||
compared with data read from a file, and anywhere file data is read and
|
||||
treated as a string. */
|
||||
#if '\n'!=0x0A || ' '!=0x20 || '0'!=0x30 || 'A'!=0x41 || 'a'!=0x61
|
||||
#error "ASCII character set required"
|
||||
#endif
|
||||
|
||||
/* My code depends on int being at least 32 bits. Almost everything these days
|
||||
uses at least 32-bit ints, so it's hard to even find a system with 16-bit ints
|
||||
to test with. The issue can't be gotten around by using a suitable blargg_int
|
||||
everywhere either, because int is often converted to implicitly when doing
|
||||
arithmetic on smaller types. */
|
||||
#if UINT_MAX < 0xFFFFFFFF
|
||||
#error "int must be at least 32 bits"
|
||||
#endif
|
||||
|
||||
// In case compiler doesn't support these properly. Used rarely.
|
||||
#define STATIC_CAST(T,expr) static_cast<T> (expr)
|
||||
#define CONST_CAST( T,expr) const_cast<T> (expr)
|
||||
|
||||
// User configuration can override the above macros if necessary
|
||||
#include "blargg_config.h"
|
||||
|
||||
/* BLARGG_DEPRECATED [_TEXT] for any declarations/text to be removed in a
|
||||
future version. In GCC, we can let the compiler warn. In other compilers,
|
||||
we strip it out unless BLARGG_LEGACY is true. */
|
||||
#if BLARGG_LEGACY
|
||||
// Allow old client code to work without warnings
|
||||
#define BLARGG_DEPRECATED_TEXT( text ) text
|
||||
#define BLARGG_DEPRECATED( text ) text
|
||||
#elif __GNUC__ >= 4
|
||||
// In GCC, we can mark declarations and let the compiler warn
|
||||
#define BLARGG_DEPRECATED_TEXT( text ) text
|
||||
#define BLARGG_DEPRECATED( text ) __attribute__ ((deprecated)) text
|
||||
#else
|
||||
// By default, deprecated items are removed, to avoid use in new code
|
||||
#define BLARGG_DEPRECATED_TEXT( text )
|
||||
#define BLARGG_DEPRECATED( text )
|
||||
#endif
|
||||
|
||||
/* BOOST::int8_t, BOOST::int32_t, etc.
|
||||
I used BOOST since I originally was going to allow use of the boost library
|
||||
for prividing the definitions. If I'm defining them, they must be scoped or
|
||||
else they could conflict with the standard ones at global scope. Even if
|
||||
HAVE_STDINT_H isn't defined, I can't assume the typedefs won't exist at
|
||||
global scope already. */
|
||||
#if defined (HAVE_STDINT_H) || \
|
||||
UCHAR_MAX != 0xFF || USHRT_MAX != 0xFFFF || UINT_MAX != 0xFFFFFFFF
|
||||
#include <stdint.h>
|
||||
#define BOOST
|
||||
#else
|
||||
struct BOOST
|
||||
{
|
||||
typedef signed char int8_t;
|
||||
typedef unsigned char uint8_t;
|
||||
typedef short int16_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef int int32_t;
|
||||
typedef unsigned int uint32_t;
|
||||
};
|
||||
#endif
|
||||
|
||||
/* My code is not written with exceptions in mind, so either uses new (nothrow)
|
||||
OR overrides operator new in my classes. The former is best since clients
|
||||
creating objects will get standard exceptions on failure, but that causes it
|
||||
to require the standard C++ library. So, when the client is using the C
|
||||
interface, I override operator new to use malloc. */
|
||||
|
||||
// BLARGG_DISABLE_NOTHROW is put inside classes
|
||||
#ifndef BLARGG_DISABLE_NOTHROW
|
||||
// throw spec mandatory in ISO C++ if NULL can be returned
|
||||
#if __cplusplus >= 199711 || __GNUC__ >= 3 || _MSC_VER >= 1300
|
||||
#define BLARGG_THROWS_NOTHING throw ()
|
||||
#else
|
||||
#define BLARGG_THROWS_NOTHING
|
||||
#endif
|
||||
|
||||
#define BLARGG_DISABLE_NOTHROW \
|
||||
void* operator new ( size_t s ) BLARGG_THROWS_NOTHING { return malloc( s ); }\
|
||||
void operator delete( void* p ) BLARGG_THROWS_NOTHING { free( p ); }
|
||||
|
||||
#define BLARGG_NEW new
|
||||
#else
|
||||
// BLARGG_NEW is used in place of new in library code
|
||||
#include <new>
|
||||
#define BLARGG_NEW new (std::nothrow)
|
||||
#endif
|
||||
|
||||
class blargg_vector_ {
|
||||
protected:
|
||||
void* begin_;
|
||||
size_t size_;
|
||||
void init();
|
||||
blargg_err_t resize_( size_t n, size_t elem_size );
|
||||
public:
|
||||
size_t size() const { return size_; }
|
||||
void clear();
|
||||
};
|
||||
|
||||
// Very lightweight vector for POD types (no constructor/destructor)
|
||||
template<class T>
|
||||
class blargg_vector : public blargg_vector_ {
|
||||
union T_must_be_pod { T t; }; // fails if T is not POD
|
||||
public:
|
||||
blargg_vector() { init(); }
|
||||
~blargg_vector() { clear(); }
|
||||
|
||||
blargg_err_t resize( size_t n ) { return resize_( n, sizeof (T) ); }
|
||||
|
||||
T* begin() { return static_cast<T*> (begin_); }
|
||||
const T* begin() const { return static_cast<T*> (begin_); }
|
||||
|
||||
T* end() { return static_cast<T*> (begin_) + size_; }
|
||||
const T* end() const { return static_cast<T*> (begin_) + size_; }
|
||||
|
||||
T& operator [] ( size_t n )
|
||||
{
|
||||
assert( n < size_ );
|
||||
return static_cast<T*> (begin_) [n];
|
||||
}
|
||||
|
||||
const T& operator [] ( size_t n ) const
|
||||
{
|
||||
assert( n < size_ );
|
||||
return static_cast<T*> (begin_) [n];
|
||||
}
|
||||
};
|
||||
|
||||
// Callback function with user data.
|
||||
// blargg_callback<T> set_callback; // for user, this acts like...
|
||||
// void set_callback( T func, void* user_data = NULL ); // ...this
|
||||
// To call function, do set_callback.f( .. set_callback.data ... );
|
||||
template<class T>
|
||||
struct blargg_callback
|
||||
{
|
||||
T f;
|
||||
void* data;
|
||||
blargg_callback() { f = NULL; }
|
||||
void operator () ( T callback, void* user_data = NULL ) { f = callback; data = user_data; }
|
||||
};
|
||||
|
||||
BLARGG_DEPRECATED( typedef signed int blargg_long; )
|
||||
BLARGG_DEPRECATED( typedef unsigned int blargg_ulong; )
|
||||
#if BLARGG_LEGACY
|
||||
#define BOOST_STATIC_ASSERT BLARGG_STATIC_ASSERT
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,31 +1,31 @@
|
|||
// Library configuration. Modify this file as necessary.
|
||||
|
||||
// File_Extractor 1.0.0
|
||||
#ifndef BLARGG_CONFIG_H
|
||||
#define BLARGG_CONFIG_H
|
||||
|
||||
// Uncomment a #define line below to have effect described.
|
||||
|
||||
// Enable RAR archive support. Doing so adds extra licensing restrictions
|
||||
// to this library (see unrar/readme.txt for more information).
|
||||
//#define FEX_ENABLE_RAR 1
|
||||
|
||||
// Accept file paths encoded as UTF-8. Currently only affects Windows,
|
||||
// as Unix/Linux/Mac OS X already use UTF-8 paths.
|
||||
//#define BLARGG_UTF8_PATHS 1
|
||||
|
||||
// Enable support for as building DLL on Windows.
|
||||
//#define BLARGG_BUILD_DLL 1
|
||||
|
||||
// Support only the listed archive types. Remove any you don't need.
|
||||
#define FEX_TYPE_LIST \
|
||||
fex_7z_type,\
|
||||
fex_gz_type,\
|
||||
fex_zip_type,
|
||||
|
||||
// Use standard config.h if present
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
// Library configuration. Modify this file as necessary.
|
||||
|
||||
// File_Extractor 1.0.0
|
||||
#ifndef BLARGG_CONFIG_H
|
||||
#define BLARGG_CONFIG_H
|
||||
|
||||
// Uncomment a #define line below to have effect described.
|
||||
|
||||
// Enable RAR archive support. Doing so adds extra licensing restrictions
|
||||
// to this library (see unrar/readme.txt for more information).
|
||||
//#define FEX_ENABLE_RAR 1
|
||||
|
||||
// Accept file paths encoded as UTF-8. Currently only affects Windows,
|
||||
// as Unix/Linux/Mac OS X already use UTF-8 paths.
|
||||
//#define BLARGG_UTF8_PATHS 1
|
||||
|
||||
// Enable support for as building DLL on Windows.
|
||||
//#define BLARGG_BUILD_DLL 1
|
||||
|
||||
// Support only the listed archive types. Remove any you don't need.
|
||||
#define FEX_TYPE_LIST \
|
||||
fex_7z_type,\
|
||||
fex_gz_type,\
|
||||
fex_zip_type,
|
||||
|
||||
// Use standard config.h if present
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,185 +1,185 @@
|
|||
// CPU Byte Order Utilities
|
||||
|
||||
// File_Extractor 1.0.0
|
||||
#ifndef BLARGG_ENDIAN_H
|
||||
#define BLARGG_ENDIAN_H
|
||||
|
||||
#include "blargg_common.h"
|
||||
|
||||
// BLARGG_CPU_CISC: Defined if CPU has very few general-purpose registers (< 16)
|
||||
#if defined (__i386__) || defined (__x86_64__) || defined (_M_IX86) || defined (_M_X64)
|
||||
#define BLARGG_CPU_X86 1
|
||||
#define BLARGG_CPU_CISC 1
|
||||
#endif
|
||||
|
||||
#if defined (__powerpc__) || defined (__ppc__) || defined (__ppc64__) || \
|
||||
defined (__POWERPC__) || defined (__powerc)
|
||||
#define BLARGG_CPU_POWERPC 1
|
||||
#define BLARGG_CPU_RISC 1
|
||||
#endif
|
||||
|
||||
// BLARGG_BIG_ENDIAN, BLARGG_LITTLE_ENDIAN: Determined automatically, otherwise only
|
||||
// one may be #defined to 1. Only needed if something actually depends on byte order.
|
||||
#if !defined (BLARGG_BIG_ENDIAN) && !defined (BLARGG_LITTLE_ENDIAN)
|
||||
#ifdef __GLIBC__
|
||||
// GCC handles this for us
|
||||
#include <endian.h>
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#define BLARGG_LITTLE_ENDIAN 1
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
#define BLARGG_BIG_ENDIAN 1
|
||||
#endif
|
||||
#else
|
||||
|
||||
#if defined (LSB_FIRST) || defined (__LITTLE_ENDIAN__) || BLARGG_CPU_X86 || \
|
||||
(defined (LITTLE_ENDIAN) && LITTLE_ENDIAN+0 != 1234)
|
||||
#define BLARGG_LITTLE_ENDIAN 1
|
||||
#endif
|
||||
|
||||
#if defined (MSB_FIRST) || defined (__BIG_ENDIAN__) || defined (WORDS_BIGENDIAN) || \
|
||||
defined (__sparc__) || BLARGG_CPU_POWERPC || \
|
||||
(defined (BIG_ENDIAN) && BIG_ENDIAN+0 != 4321)
|
||||
#define BLARGG_BIG_ENDIAN 1
|
||||
#elif !defined (__mips__)
|
||||
// No endian specified; assume little-endian, since it's most common
|
||||
#define BLARGG_LITTLE_ENDIAN 1
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if BLARGG_LITTLE_ENDIAN && BLARGG_BIG_ENDIAN
|
||||
#undef BLARGG_LITTLE_ENDIAN
|
||||
#undef BLARGG_BIG_ENDIAN
|
||||
#endif
|
||||
|
||||
inline void blargg_verify_byte_order()
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
#if BLARGG_BIG_ENDIAN
|
||||
volatile int i = 1;
|
||||
assert( *(volatile char*) &i == 0 );
|
||||
#elif BLARGG_LITTLE_ENDIAN
|
||||
volatile int i = 1;
|
||||
assert( *(volatile char*) &i != 0 );
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
inline unsigned get_le16( void const* p )
|
||||
{
|
||||
return (unsigned) ((unsigned char const*) p) [1] << 8 |
|
||||
(unsigned) ((unsigned char const*) p) [0];
|
||||
}
|
||||
|
||||
inline unsigned get_be16( void const* p )
|
||||
{
|
||||
return (unsigned) ((unsigned char const*) p) [0] << 8 |
|
||||
(unsigned) ((unsigned char const*) p) [1];
|
||||
}
|
||||
|
||||
inline unsigned get_le32( void const* p )
|
||||
{
|
||||
return (unsigned) ((unsigned char const*) p) [3] << 24 |
|
||||
(unsigned) ((unsigned char const*) p) [2] << 16 |
|
||||
(unsigned) ((unsigned char const*) p) [1] << 8 |
|
||||
(unsigned) ((unsigned char const*) p) [0];
|
||||
}
|
||||
|
||||
inline unsigned get_be32( void const* p )
|
||||
{
|
||||
return (unsigned) ((unsigned char const*) p) [0] << 24 |
|
||||
(unsigned) ((unsigned char const*) p) [1] << 16 |
|
||||
(unsigned) ((unsigned char const*) p) [2] << 8 |
|
||||
(unsigned) ((unsigned char const*) p) [3];
|
||||
}
|
||||
|
||||
inline void set_le16( void* p, unsigned n )
|
||||
{
|
||||
((unsigned char*) p) [1] = (unsigned char) (n >> 8);
|
||||
((unsigned char*) p) [0] = (unsigned char) n;
|
||||
}
|
||||
|
||||
inline void set_be16( void* p, unsigned n )
|
||||
{
|
||||
((unsigned char*) p) [0] = (unsigned char) (n >> 8);
|
||||
((unsigned char*) p) [1] = (unsigned char) n;
|
||||
}
|
||||
|
||||
inline void set_le32( void* p, unsigned n )
|
||||
{
|
||||
((unsigned char*) p) [0] = (unsigned char) n;
|
||||
((unsigned char*) p) [1] = (unsigned char) (n >> 8);
|
||||
((unsigned char*) p) [2] = (unsigned char) (n >> 16);
|
||||
((unsigned char*) p) [3] = (unsigned char) (n >> 24);
|
||||
}
|
||||
|
||||
inline void set_be32( void* p, unsigned n )
|
||||
{
|
||||
((unsigned char*) p) [3] = (unsigned char) n;
|
||||
((unsigned char*) p) [2] = (unsigned char) (n >> 8);
|
||||
((unsigned char*) p) [1] = (unsigned char) (n >> 16);
|
||||
((unsigned char*) p) [0] = (unsigned char) (n >> 24);
|
||||
}
|
||||
|
||||
#if BLARGG_NONPORTABLE
|
||||
// Optimized implementation if byte order is known
|
||||
#if BLARGG_LITTLE_ENDIAN
|
||||
#define GET_LE16( addr ) (*(BOOST::uint16_t const*) (addr))
|
||||
#define GET_LE32( addr ) (*(BOOST::uint32_t const*) (addr))
|
||||
#define SET_LE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data))
|
||||
#define SET_LE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data))
|
||||
#elif BLARGG_BIG_ENDIAN
|
||||
#define GET_BE16( addr ) (*(BOOST::uint16_t const*) (addr))
|
||||
#define GET_BE32( addr ) (*(BOOST::uint32_t const*) (addr))
|
||||
#define SET_BE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data))
|
||||
#define SET_BE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data))
|
||||
|
||||
#if BLARGG_CPU_POWERPC
|
||||
// PowerPC has special byte-reversed instructions
|
||||
#if defined (__MWERKS__)
|
||||
#define GET_LE16( addr ) (__lhbrx( addr, 0 ))
|
||||
#define GET_LE32( addr ) (__lwbrx( addr, 0 ))
|
||||
#define SET_LE16( addr, in ) (__sthbrx( in, addr, 0 ))
|
||||
#define SET_LE32( addr, in ) (__stwbrx( in, addr, 0 ))
|
||||
#elif defined (__GNUC__)
|
||||
#define GET_LE16( addr ) ({unsigned short ppc_lhbrx_; __asm__ volatile( "lhbrx %0,0,%1" : "=r" (ppc_lhbrx_) : "r" (addr) : "memory" ); ppc_lhbrx_;})
|
||||
#define GET_LE32( addr ) ({unsigned short ppc_lwbrx_; __asm__ volatile( "lwbrx %0,0,%1" : "=r" (ppc_lwbrx_) : "r" (addr) : "memory" ); ppc_lwbrx_;})
|
||||
#define SET_LE16( addr, in ) ({__asm__ volatile( "sthbrx %0,0,%1" : : "r" (in), "r" (addr) : "memory" );})
|
||||
#define SET_LE32( addr, in ) ({__asm__ volatile( "stwbrx %0,0,%1" : : "r" (in), "r" (addr) : "memory" );})
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef GET_LE16
|
||||
#define GET_LE16( addr ) get_le16( addr )
|
||||
#define SET_LE16( addr, data ) set_le16( addr, data )
|
||||
#endif
|
||||
|
||||
#ifndef GET_LE32
|
||||
#define GET_LE32( addr ) get_le32( addr )
|
||||
#define SET_LE32( addr, data ) set_le32( addr, data )
|
||||
#endif
|
||||
|
||||
#ifndef GET_BE16
|
||||
#define GET_BE16( addr ) get_be16( addr )
|
||||
#define SET_BE16( addr, data ) set_be16( addr, data )
|
||||
#endif
|
||||
|
||||
#ifndef GET_BE32
|
||||
#define GET_BE32( addr ) get_be32( addr )
|
||||
#define SET_BE32( addr, data ) set_be32( addr, data )
|
||||
#endif
|
||||
|
||||
// auto-selecting versions
|
||||
|
||||
inline void set_le( BOOST::uint16_t* p, unsigned n ) { SET_LE16( p, n ); }
|
||||
inline void set_le( BOOST::uint32_t* p, unsigned n ) { SET_LE32( p, n ); }
|
||||
inline void set_be( BOOST::uint16_t* p, unsigned n ) { SET_BE16( p, n ); }
|
||||
inline void set_be( BOOST::uint32_t* p, unsigned n ) { SET_BE32( p, n ); }
|
||||
inline unsigned get_le( BOOST::uint16_t const* p ) { return GET_LE16( p ); }
|
||||
inline unsigned get_le( BOOST::uint32_t const* p ) { return GET_LE32( p ); }
|
||||
inline unsigned get_be( BOOST::uint16_t const* p ) { return GET_BE16( p ); }
|
||||
inline unsigned get_be( BOOST::uint32_t const* p ) { return GET_BE32( p ); }
|
||||
|
||||
#endif
|
||||
// CPU Byte Order Utilities
|
||||
|
||||
// File_Extractor 1.0.0
|
||||
#ifndef BLARGG_ENDIAN_H
|
||||
#define BLARGG_ENDIAN_H
|
||||
|
||||
#include "blargg_common.h"
|
||||
|
||||
// BLARGG_CPU_CISC: Defined if CPU has very few general-purpose registers (< 16)
|
||||
#if defined (__i386__) || defined (__x86_64__) || defined (_M_IX86) || defined (_M_X64)
|
||||
#define BLARGG_CPU_X86 1
|
||||
#define BLARGG_CPU_CISC 1
|
||||
#endif
|
||||
|
||||
#if defined (__powerpc__) || defined (__ppc__) || defined (__ppc64__) || \
|
||||
defined (__POWERPC__) || defined (__powerc)
|
||||
#define BLARGG_CPU_POWERPC 1
|
||||
#define BLARGG_CPU_RISC 1
|
||||
#endif
|
||||
|
||||
// BLARGG_BIG_ENDIAN, BLARGG_LITTLE_ENDIAN: Determined automatically, otherwise only
|
||||
// one may be #defined to 1. Only needed if something actually depends on byte order.
|
||||
#if !defined (BLARGG_BIG_ENDIAN) && !defined (BLARGG_LITTLE_ENDIAN)
|
||||
#ifdef __GLIBC__
|
||||
// GCC handles this for us
|
||||
#include <endian.h>
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#define BLARGG_LITTLE_ENDIAN 1
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
#define BLARGG_BIG_ENDIAN 1
|
||||
#endif
|
||||
#else
|
||||
|
||||
#if defined (LSB_FIRST) || defined (__LITTLE_ENDIAN__) || BLARGG_CPU_X86 || \
|
||||
(defined (LITTLE_ENDIAN) && LITTLE_ENDIAN+0 != 1234)
|
||||
#define BLARGG_LITTLE_ENDIAN 1
|
||||
#endif
|
||||
|
||||
#if defined (MSB_FIRST) || defined (__BIG_ENDIAN__) || defined (WORDS_BIGENDIAN) || \
|
||||
defined (__sparc__) || BLARGG_CPU_POWERPC || \
|
||||
(defined (BIG_ENDIAN) && BIG_ENDIAN+0 != 4321)
|
||||
#define BLARGG_BIG_ENDIAN 1
|
||||
#elif !defined (__mips__)
|
||||
// No endian specified; assume little-endian, since it's most common
|
||||
#define BLARGG_LITTLE_ENDIAN 1
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if BLARGG_LITTLE_ENDIAN && BLARGG_BIG_ENDIAN
|
||||
#undef BLARGG_LITTLE_ENDIAN
|
||||
#undef BLARGG_BIG_ENDIAN
|
||||
#endif
|
||||
|
||||
inline void blargg_verify_byte_order()
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
#if BLARGG_BIG_ENDIAN
|
||||
volatile int i = 1;
|
||||
assert( *(volatile char*) &i == 0 );
|
||||
#elif BLARGG_LITTLE_ENDIAN
|
||||
volatile int i = 1;
|
||||
assert( *(volatile char*) &i != 0 );
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
inline unsigned get_le16( void const* p )
|
||||
{
|
||||
return (unsigned) ((unsigned char const*) p) [1] << 8 |
|
||||
(unsigned) ((unsigned char const*) p) [0];
|
||||
}
|
||||
|
||||
inline unsigned get_be16( void const* p )
|
||||
{
|
||||
return (unsigned) ((unsigned char const*) p) [0] << 8 |
|
||||
(unsigned) ((unsigned char const*) p) [1];
|
||||
}
|
||||
|
||||
inline unsigned get_le32( void const* p )
|
||||
{
|
||||
return (unsigned) ((unsigned char const*) p) [3] << 24 |
|
||||
(unsigned) ((unsigned char const*) p) [2] << 16 |
|
||||
(unsigned) ((unsigned char const*) p) [1] << 8 |
|
||||
(unsigned) ((unsigned char const*) p) [0];
|
||||
}
|
||||
|
||||
inline unsigned get_be32( void const* p )
|
||||
{
|
||||
return (unsigned) ((unsigned char const*) p) [0] << 24 |
|
||||
(unsigned) ((unsigned char const*) p) [1] << 16 |
|
||||
(unsigned) ((unsigned char const*) p) [2] << 8 |
|
||||
(unsigned) ((unsigned char const*) p) [3];
|
||||
}
|
||||
|
||||
inline void set_le16( void* p, unsigned n )
|
||||
{
|
||||
((unsigned char*) p) [1] = (unsigned char) (n >> 8);
|
||||
((unsigned char*) p) [0] = (unsigned char) n;
|
||||
}
|
||||
|
||||
inline void set_be16( void* p, unsigned n )
|
||||
{
|
||||
((unsigned char*) p) [0] = (unsigned char) (n >> 8);
|
||||
((unsigned char*) p) [1] = (unsigned char) n;
|
||||
}
|
||||
|
||||
inline void set_le32( void* p, unsigned n )
|
||||
{
|
||||
((unsigned char*) p) [0] = (unsigned char) n;
|
||||
((unsigned char*) p) [1] = (unsigned char) (n >> 8);
|
||||
((unsigned char*) p) [2] = (unsigned char) (n >> 16);
|
||||
((unsigned char*) p) [3] = (unsigned char) (n >> 24);
|
||||
}
|
||||
|
||||
inline void set_be32( void* p, unsigned n )
|
||||
{
|
||||
((unsigned char*) p) [3] = (unsigned char) n;
|
||||
((unsigned char*) p) [2] = (unsigned char) (n >> 8);
|
||||
((unsigned char*) p) [1] = (unsigned char) (n >> 16);
|
||||
((unsigned char*) p) [0] = (unsigned char) (n >> 24);
|
||||
}
|
||||
|
||||
#if BLARGG_NONPORTABLE
|
||||
// Optimized implementation if byte order is known
|
||||
#if BLARGG_LITTLE_ENDIAN
|
||||
#define GET_LE16( addr ) (*(BOOST::uint16_t const*) (addr))
|
||||
#define GET_LE32( addr ) (*(BOOST::uint32_t const*) (addr))
|
||||
#define SET_LE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data))
|
||||
#define SET_LE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data))
|
||||
#elif BLARGG_BIG_ENDIAN
|
||||
#define GET_BE16( addr ) (*(BOOST::uint16_t const*) (addr))
|
||||
#define GET_BE32( addr ) (*(BOOST::uint32_t const*) (addr))
|
||||
#define SET_BE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data))
|
||||
#define SET_BE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data))
|
||||
|
||||
#if BLARGG_CPU_POWERPC
|
||||
// PowerPC has special byte-reversed instructions
|
||||
#if defined (__MWERKS__)
|
||||
#define GET_LE16( addr ) (__lhbrx( addr, 0 ))
|
||||
#define GET_LE32( addr ) (__lwbrx( addr, 0 ))
|
||||
#define SET_LE16( addr, in ) (__sthbrx( in, addr, 0 ))
|
||||
#define SET_LE32( addr, in ) (__stwbrx( in, addr, 0 ))
|
||||
#elif defined (__GNUC__)
|
||||
#define GET_LE16( addr ) ({unsigned short ppc_lhbrx_; __asm__ volatile( "lhbrx %0,0,%1" : "=r" (ppc_lhbrx_) : "r" (addr) : "memory" ); ppc_lhbrx_;})
|
||||
#define GET_LE32( addr ) ({unsigned short ppc_lwbrx_; __asm__ volatile( "lwbrx %0,0,%1" : "=r" (ppc_lwbrx_) : "r" (addr) : "memory" ); ppc_lwbrx_;})
|
||||
#define SET_LE16( addr, in ) ({__asm__ volatile( "sthbrx %0,0,%1" : : "r" (in), "r" (addr) : "memory" );})
|
||||
#define SET_LE32( addr, in ) ({__asm__ volatile( "stwbrx %0,0,%1" : : "r" (in), "r" (addr) : "memory" );})
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef GET_LE16
|
||||
#define GET_LE16( addr ) get_le16( addr )
|
||||
#define SET_LE16( addr, data ) set_le16( addr, data )
|
||||
#endif
|
||||
|
||||
#ifndef GET_LE32
|
||||
#define GET_LE32( addr ) get_le32( addr )
|
||||
#define SET_LE32( addr, data ) set_le32( addr, data )
|
||||
#endif
|
||||
|
||||
#ifndef GET_BE16
|
||||
#define GET_BE16( addr ) get_be16( addr )
|
||||
#define SET_BE16( addr, data ) set_be16( addr, data )
|
||||
#endif
|
||||
|
||||
#ifndef GET_BE32
|
||||
#define GET_BE32( addr ) get_be32( addr )
|
||||
#define SET_BE32( addr, data ) set_be32( addr, data )
|
||||
#endif
|
||||
|
||||
// auto-selecting versions
|
||||
|
||||
inline void set_le( BOOST::uint16_t* p, unsigned n ) { SET_LE16( p, n ); }
|
||||
inline void set_le( BOOST::uint32_t* p, unsigned n ) { SET_LE32( p, n ); }
|
||||
inline void set_be( BOOST::uint16_t* p, unsigned n ) { SET_BE16( p, n ); }
|
||||
inline void set_be( BOOST::uint32_t* p, unsigned n ) { SET_BE32( p, n ); }
|
||||
inline unsigned get_le( BOOST::uint16_t const* p ) { return GET_LE16( p ); }
|
||||
inline unsigned get_le( BOOST::uint32_t const* p ) { return GET_LE32( p ); }
|
||||
inline unsigned get_be( BOOST::uint16_t const* p ) { return GET_BE16( p ); }
|
||||
inline unsigned get_be( BOOST::uint32_t const* p ) { return GET_BE32( p ); }
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,113 +1,113 @@
|
|||
// File_Extractor 1.0.0. http://www.slack.net/~ant/
|
||||
|
||||
#include "blargg_errors.h"
|
||||
|
||||
/* Copyright (C) 2009 Shay Green. This module is free software; you
|
||||
can redistribute it and/or modify it under the terms of the GNU Lesser
|
||||
General Public License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version. This
|
||||
module 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 Lesser General Public License for more
|
||||
details. You should have received a copy of the GNU Lesser General Public
|
||||
License along with this module; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
#include "blargg_source.h"
|
||||
|
||||
blargg_err_def_t blargg_err_generic = BLARGG_ERR_GENERIC;
|
||||
blargg_err_def_t blargg_err_memory = BLARGG_ERR_MEMORY;
|
||||
blargg_err_def_t blargg_err_caller = BLARGG_ERR_CALLER;
|
||||
blargg_err_def_t blargg_err_internal = BLARGG_ERR_INTERNAL;
|
||||
blargg_err_def_t blargg_err_limitation = BLARGG_ERR_LIMITATION;
|
||||
|
||||
blargg_err_def_t blargg_err_file_missing = BLARGG_ERR_FILE_MISSING;
|
||||
blargg_err_def_t blargg_err_file_read = BLARGG_ERR_FILE_READ;
|
||||
blargg_err_def_t blargg_err_file_write = BLARGG_ERR_FILE_WRITE;
|
||||
blargg_err_def_t blargg_err_file_io = BLARGG_ERR_FILE_IO;
|
||||
blargg_err_def_t blargg_err_file_full = BLARGG_ERR_FILE_FULL;
|
||||
blargg_err_def_t blargg_err_file_eof = BLARGG_ERR_FILE_EOF;
|
||||
|
||||
blargg_err_def_t blargg_err_file_type = BLARGG_ERR_FILE_TYPE;
|
||||
blargg_err_def_t blargg_err_file_feature = BLARGG_ERR_FILE_FEATURE;
|
||||
blargg_err_def_t blargg_err_file_corrupt = BLARGG_ERR_FILE_CORRUPT;
|
||||
|
||||
const char* blargg_err_str( blargg_err_t err )
|
||||
{
|
||||
if ( !err )
|
||||
return "";
|
||||
|
||||
if ( *err == BLARGG_ERR_TYPE("")[0] )
|
||||
return err + 1;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
bool blargg_is_err_type( blargg_err_t err, const char type [] )
|
||||
{
|
||||
if ( err )
|
||||
{
|
||||
// True if first strlen(type) characters of err match type
|
||||
char const* p = err;
|
||||
while ( *type && *type == *p )
|
||||
{
|
||||
type++;
|
||||
p++;
|
||||
}
|
||||
|
||||
if ( !*type )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* blargg_err_details( blargg_err_t err )
|
||||
{
|
||||
const char* p = err;
|
||||
if ( !p )
|
||||
{
|
||||
p = "";
|
||||
}
|
||||
else if ( *p == BLARGG_ERR_TYPE("")[0] )
|
||||
{
|
||||
while ( *p && *p != ';' )
|
||||
p++;
|
||||
|
||||
// Skip ; and space after it
|
||||
if ( *p )
|
||||
{
|
||||
p++;
|
||||
|
||||
check( *p == ' ' );
|
||||
if ( *p )
|
||||
p++;
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
int blargg_err_to_code( blargg_err_t err, blargg_err_to_code_t const codes [] )
|
||||
{
|
||||
if ( !err )
|
||||
return 0;
|
||||
|
||||
while ( codes->str && !blargg_is_err_type( err, codes->str ) )
|
||||
codes++;
|
||||
|
||||
return codes->code;
|
||||
}
|
||||
|
||||
blargg_err_t blargg_code_to_err( int code, blargg_err_to_code_t const codes [] )
|
||||
{
|
||||
if ( !code )
|
||||
return blargg_ok;
|
||||
|
||||
while ( codes->str && codes->code != code )
|
||||
codes++;
|
||||
|
||||
if ( !codes->str )
|
||||
return blargg_err_generic;
|
||||
|
||||
return codes->str;
|
||||
}
|
||||
// File_Extractor 1.0.0. http://www.slack.net/~ant/
|
||||
|
||||
#include "blargg_errors.h"
|
||||
|
||||
/* Copyright (C) 2009 Shay Green. This module is free software; you
|
||||
can redistribute it and/or modify it under the terms of the GNU Lesser
|
||||
General Public License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version. This
|
||||
module 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 Lesser General Public License for more
|
||||
details. You should have received a copy of the GNU Lesser General Public
|
||||
License along with this module; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
#include "blargg_source.h"
|
||||
|
||||
blargg_err_def_t blargg_err_generic = BLARGG_ERR_GENERIC;
|
||||
blargg_err_def_t blargg_err_memory = BLARGG_ERR_MEMORY;
|
||||
blargg_err_def_t blargg_err_caller = BLARGG_ERR_CALLER;
|
||||
blargg_err_def_t blargg_err_internal = BLARGG_ERR_INTERNAL;
|
||||
blargg_err_def_t blargg_err_limitation = BLARGG_ERR_LIMITATION;
|
||||
|
||||
blargg_err_def_t blargg_err_file_missing = BLARGG_ERR_FILE_MISSING;
|
||||
blargg_err_def_t blargg_err_file_read = BLARGG_ERR_FILE_READ;
|
||||
blargg_err_def_t blargg_err_file_write = BLARGG_ERR_FILE_WRITE;
|
||||
blargg_err_def_t blargg_err_file_io = BLARGG_ERR_FILE_IO;
|
||||
blargg_err_def_t blargg_err_file_full = BLARGG_ERR_FILE_FULL;
|
||||
blargg_err_def_t blargg_err_file_eof = BLARGG_ERR_FILE_EOF;
|
||||
|
||||
blargg_err_def_t blargg_err_file_type = BLARGG_ERR_FILE_TYPE;
|
||||
blargg_err_def_t blargg_err_file_feature = BLARGG_ERR_FILE_FEATURE;
|
||||
blargg_err_def_t blargg_err_file_corrupt = BLARGG_ERR_FILE_CORRUPT;
|
||||
|
||||
const char* blargg_err_str( blargg_err_t err )
|
||||
{
|
||||
if ( !err )
|
||||
return "";
|
||||
|
||||
if ( *err == BLARGG_ERR_TYPE("")[0] )
|
||||
return err + 1;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
bool blargg_is_err_type( blargg_err_t err, const char type [] )
|
||||
{
|
||||
if ( err )
|
||||
{
|
||||
// True if first strlen(type) characters of err match type
|
||||
char const* p = err;
|
||||
while ( *type && *type == *p )
|
||||
{
|
||||
type++;
|
||||
p++;
|
||||
}
|
||||
|
||||
if ( !*type )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* blargg_err_details( blargg_err_t err )
|
||||
{
|
||||
const char* p = err;
|
||||
if ( !p )
|
||||
{
|
||||
p = "";
|
||||
}
|
||||
else if ( *p == BLARGG_ERR_TYPE("")[0] )
|
||||
{
|
||||
while ( *p && *p != ';' )
|
||||
p++;
|
||||
|
||||
// Skip ; and space after it
|
||||
if ( *p )
|
||||
{
|
||||
p++;
|
||||
|
||||
check( *p == ' ' );
|
||||
if ( *p )
|
||||
p++;
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
int blargg_err_to_code( blargg_err_t err, blargg_err_to_code_t const codes [] )
|
||||
{
|
||||
if ( !err )
|
||||
return 0;
|
||||
|
||||
while ( codes->str && !blargg_is_err_type( err, codes->str ) )
|
||||
codes++;
|
||||
|
||||
return codes->code;
|
||||
}
|
||||
|
||||
blargg_err_t blargg_code_to_err( int code, blargg_err_to_code_t const codes [] )
|
||||
{
|
||||
if ( !code )
|
||||
return blargg_ok;
|
||||
|
||||
while ( codes->str && codes->code != code )
|
||||
codes++;
|
||||
|
||||
if ( !codes->str )
|
||||
return blargg_err_generic;
|
||||
|
||||
return codes->str;
|
||||
}
|
||||
|
|
|
@ -1,80 +1,80 @@
|
|||
// Error strings and conversion functions
|
||||
|
||||
// File_Extractor 1.0.0
|
||||
#ifndef BLARGG_ERRORS_H
|
||||
#define BLARGG_ERRORS_H
|
||||
|
||||
#ifndef BLARGG_COMMON_H
|
||||
#include "blargg_common.h"
|
||||
#endif
|
||||
|
||||
typedef const char blargg_err_def_t [];
|
||||
|
||||
// Basic errors
|
||||
extern blargg_err_def_t blargg_err_generic;
|
||||
extern blargg_err_def_t blargg_err_memory;
|
||||
extern blargg_err_def_t blargg_err_caller;
|
||||
extern blargg_err_def_t blargg_err_internal;
|
||||
extern blargg_err_def_t blargg_err_limitation;
|
||||
|
||||
// File low-level
|
||||
extern blargg_err_def_t blargg_err_file_missing; // not found
|
||||
extern blargg_err_def_t blargg_err_file_read;
|
||||
extern blargg_err_def_t blargg_err_file_write;
|
||||
extern blargg_err_def_t blargg_err_file_io;
|
||||
extern blargg_err_def_t blargg_err_file_full;
|
||||
extern blargg_err_def_t blargg_err_file_eof;
|
||||
|
||||
// File high-level
|
||||
extern blargg_err_def_t blargg_err_file_type; // wrong file type
|
||||
extern blargg_err_def_t blargg_err_file_feature;
|
||||
extern blargg_err_def_t blargg_err_file_corrupt;
|
||||
|
||||
// C string describing error, or "" if err == NULL
|
||||
const char* blargg_err_str( blargg_err_t err );
|
||||
|
||||
// True iff error is of given type, or false if err == NULL
|
||||
bool blargg_is_err_type( blargg_err_t, const char type [] );
|
||||
|
||||
// Details of error without describing main cause, or "" if err == NULL
|
||||
const char* blargg_err_details( blargg_err_t err );
|
||||
|
||||
// Converts error string to integer code using mapping table. Calls blargg_is_err_type()
|
||||
// for each str and returns code on first match. Returns 0 if err == NULL.
|
||||
struct blargg_err_to_code_t {
|
||||
const char* str;
|
||||
int code;
|
||||
};
|
||||
int blargg_err_to_code( blargg_err_t err, blargg_err_to_code_t const [] );
|
||||
|
||||
// Converts error code back to string. If code == 0, returns NULL. If not in table,
|
||||
// returns blargg_err_generic.
|
||||
blargg_err_t blargg_code_to_err( int code, blargg_err_to_code_t const [] );
|
||||
|
||||
// Generates error string literal with details of cause
|
||||
#define BLARGG_ERR( type, str ) (type "; " str)
|
||||
|
||||
// Extra space to make it clear when blargg_err_str() isn't called to get
|
||||
// printable version of error. At some point, I might prefix error strings
|
||||
// with a code, to speed conversion to a code.
|
||||
#define BLARGG_ERR_TYPE( str ) " " str
|
||||
|
||||
// Error types to pass to BLARGG_ERR macro
|
||||
#define BLARGG_ERR_GENERIC BLARGG_ERR_TYPE( "operation failed" )
|
||||
#define BLARGG_ERR_MEMORY BLARGG_ERR_TYPE( "out of memory" )
|
||||
#define BLARGG_ERR_CALLER BLARGG_ERR_TYPE( "internal usage bug" )
|
||||
#define BLARGG_ERR_INTERNAL BLARGG_ERR_TYPE( "internal bug" )
|
||||
#define BLARGG_ERR_LIMITATION BLARGG_ERR_TYPE( "exceeded limitation" )
|
||||
|
||||
#define BLARGG_ERR_FILE_MISSING BLARGG_ERR_TYPE( "file not found" )
|
||||
#define BLARGG_ERR_FILE_READ BLARGG_ERR_TYPE( "couldn't open file" )
|
||||
#define BLARGG_ERR_FILE_WRITE BLARGG_ERR_TYPE( "couldn't modify file" )
|
||||
#define BLARGG_ERR_FILE_IO BLARGG_ERR_TYPE( "read/write error" )
|
||||
#define BLARGG_ERR_FILE_FULL BLARGG_ERR_TYPE( "disk full" )
|
||||
#define BLARGG_ERR_FILE_EOF BLARGG_ERR_TYPE( "truncated file" )
|
||||
|
||||
#define BLARGG_ERR_FILE_TYPE BLARGG_ERR_TYPE( "wrong file type" )
|
||||
#define BLARGG_ERR_FILE_FEATURE BLARGG_ERR_TYPE( "unsupported file feature" )
|
||||
#define BLARGG_ERR_FILE_CORRUPT BLARGG_ERR_TYPE( "corrupt file" )
|
||||
|
||||
#endif
|
||||
// Error strings and conversion functions
|
||||
|
||||
// File_Extractor 1.0.0
|
||||
#ifndef BLARGG_ERRORS_H
|
||||
#define BLARGG_ERRORS_H
|
||||
|
||||
#ifndef BLARGG_COMMON_H
|
||||
#include "blargg_common.h"
|
||||
#endif
|
||||
|
||||
typedef const char blargg_err_def_t [];
|
||||
|
||||
// Basic errors
|
||||
extern blargg_err_def_t blargg_err_generic;
|
||||
extern blargg_err_def_t blargg_err_memory;
|
||||
extern blargg_err_def_t blargg_err_caller;
|
||||
extern blargg_err_def_t blargg_err_internal;
|
||||
extern blargg_err_def_t blargg_err_limitation;
|
||||
|
||||
// File low-level
|
||||
extern blargg_err_def_t blargg_err_file_missing; // not found
|
||||
extern blargg_err_def_t blargg_err_file_read;
|
||||
extern blargg_err_def_t blargg_err_file_write;
|
||||
extern blargg_err_def_t blargg_err_file_io;
|
||||
extern blargg_err_def_t blargg_err_file_full;
|
||||
extern blargg_err_def_t blargg_err_file_eof;
|
||||
|
||||
// File high-level
|
||||
extern blargg_err_def_t blargg_err_file_type; // wrong file type
|
||||
extern blargg_err_def_t blargg_err_file_feature;
|
||||
extern blargg_err_def_t blargg_err_file_corrupt;
|
||||
|
||||
// C string describing error, or "" if err == NULL
|
||||
const char* blargg_err_str( blargg_err_t err );
|
||||
|
||||
// True iff error is of given type, or false if err == NULL
|
||||
bool blargg_is_err_type( blargg_err_t, const char type [] );
|
||||
|
||||
// Details of error without describing main cause, or "" if err == NULL
|
||||
const char* blargg_err_details( blargg_err_t err );
|
||||
|
||||
// Converts error string to integer code using mapping table. Calls blargg_is_err_type()
|
||||
// for each str and returns code on first match. Returns 0 if err == NULL.
|
||||
struct blargg_err_to_code_t {
|
||||
const char* str;
|
||||
int code;
|
||||
};
|
||||
int blargg_err_to_code( blargg_err_t err, blargg_err_to_code_t const [] );
|
||||
|
||||
// Converts error code back to string. If code == 0, returns NULL. If not in table,
|
||||
// returns blargg_err_generic.
|
||||
blargg_err_t blargg_code_to_err( int code, blargg_err_to_code_t const [] );
|
||||
|
||||
// Generates error string literal with details of cause
|
||||
#define BLARGG_ERR( type, str ) (type "; " str)
|
||||
|
||||
// Extra space to make it clear when blargg_err_str() isn't called to get
|
||||
// printable version of error. At some point, I might prefix error strings
|
||||
// with a code, to speed conversion to a code.
|
||||
#define BLARGG_ERR_TYPE( str ) " " str
|
||||
|
||||
// Error types to pass to BLARGG_ERR macro
|
||||
#define BLARGG_ERR_GENERIC BLARGG_ERR_TYPE( "operation failed" )
|
||||
#define BLARGG_ERR_MEMORY BLARGG_ERR_TYPE( "out of memory" )
|
||||
#define BLARGG_ERR_CALLER BLARGG_ERR_TYPE( "internal usage bug" )
|
||||
#define BLARGG_ERR_INTERNAL BLARGG_ERR_TYPE( "internal bug" )
|
||||
#define BLARGG_ERR_LIMITATION BLARGG_ERR_TYPE( "exceeded limitation" )
|
||||
|
||||
#define BLARGG_ERR_FILE_MISSING BLARGG_ERR_TYPE( "file not found" )
|
||||
#define BLARGG_ERR_FILE_READ BLARGG_ERR_TYPE( "couldn't open file" )
|
||||
#define BLARGG_ERR_FILE_WRITE BLARGG_ERR_TYPE( "couldn't modify file" )
|
||||
#define BLARGG_ERR_FILE_IO BLARGG_ERR_TYPE( "read/write error" )
|
||||
#define BLARGG_ERR_FILE_FULL BLARGG_ERR_TYPE( "disk full" )
|
||||
#define BLARGG_ERR_FILE_EOF BLARGG_ERR_TYPE( "truncated file" )
|
||||
|
||||
#define BLARGG_ERR_FILE_TYPE BLARGG_ERR_TYPE( "wrong file type" )
|
||||
#define BLARGG_ERR_FILE_FEATURE BLARGG_ERR_TYPE( "unsupported file feature" )
|
||||
#define BLARGG_ERR_FILE_CORRUPT BLARGG_ERR_TYPE( "corrupt file" )
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,125 +1,125 @@
|
|||
/* Included at the beginning of library source files, AFTER all other #include
|
||||
lines. Sets up helpful macros and services used in my source code. Since this
|
||||
is only "active" in my source code, I don't have to worry about polluting the
|
||||
global namespace with unprefixed names. */
|
||||
|
||||
// File_Extractor 1.0.0
|
||||
#ifndef BLARGG_SOURCE_H
|
||||
#define BLARGG_SOURCE_H
|
||||
|
||||
#ifndef BLARGG_COMMON_H // optimization only
|
||||
#include "blargg_common.h"
|
||||
#endif
|
||||
#include "blargg_errors.h"
|
||||
|
||||
#include <string.h> /* memcpy(), memset(), memmove() */
|
||||
#include <stddef.h> /* offsetof() */
|
||||
|
||||
/* The following four macros are for debugging only. Some or all might be
|
||||
defined to do nothing, depending on the circumstances. Described is what
|
||||
happens when a particular macro is defined to do something. When defined to
|
||||
do nothing, the macros do NOT evaluate their argument(s). */
|
||||
|
||||
/* If expr is false, prints file and line number, then aborts program. Meant
|
||||
for checking internal state and consistency. A failed assertion indicates a bug
|
||||
in MY code.
|
||||
|
||||
void assert( bool expr ); */
|
||||
#include <assert.h>
|
||||
|
||||
/* If expr is false, prints file and line number, then aborts program. Meant
|
||||
for checking caller-supplied parameters and operations that are outside the
|
||||
control of the module. A failed requirement probably indicates a bug in YOUR
|
||||
code.
|
||||
|
||||
void require( bool expr ); */
|
||||
#undef require
|
||||
#define require( expr ) assert( expr )
|
||||
|
||||
/* Like printf() except output goes to debugging console/file.
|
||||
|
||||
void dprintf( const char format [], ... ); */
|
||||
static inline void blargg_dprintf_( const char [], ... ) { }
|
||||
#undef dprintf
|
||||
#define dprintf (1) ? (void) 0 : blargg_dprintf_
|
||||
|
||||
/* If expr is false, prints file and line number to debug console/log, then
|
||||
continues execution normally. Meant for flagging potential problems or things
|
||||
that should be looked into, but that aren't serious problems.
|
||||
|
||||
void check( bool expr ); */
|
||||
#undef check
|
||||
#define check( expr ) ((void) 0)
|
||||
|
||||
/* If expr yields non-NULL error string, returns it from current function,
|
||||
otherwise continues normally. */
|
||||
#undef RETURN_ERR
|
||||
#define RETURN_ERR( expr ) \
|
||||
do {\
|
||||
blargg_err_t blargg_return_err_ = (expr);\
|
||||
if ( blargg_return_err_ )\
|
||||
return blargg_return_err_;\
|
||||
} while ( 0 )
|
||||
|
||||
/* If ptr is NULL, returns out-of-memory error, otherwise continues normally. */
|
||||
#undef CHECK_ALLOC
|
||||
#define CHECK_ALLOC( ptr ) \
|
||||
do {\
|
||||
if ( !(ptr) )\
|
||||
return blargg_err_memory;\
|
||||
} while ( 0 )
|
||||
|
||||
/* The usual min/max functions for built-in types.
|
||||
|
||||
template<typename T> T min( T x, T y ) { return x < y ? x : y; }
|
||||
template<typename T> T max( T x, T y ) { return x > y ? x : y; } */
|
||||
#define BLARGG_DEF_MIN_MAX( type ) \
|
||||
static inline type blargg_min( type x, type y ) { if ( y < x ) x = y; return x; }\
|
||||
static inline type blargg_max( type x, type y ) { if ( x < y ) x = y; return x; }
|
||||
|
||||
BLARGG_DEF_MIN_MAX( int )
|
||||
BLARGG_DEF_MIN_MAX( unsigned )
|
||||
BLARGG_DEF_MIN_MAX( long )
|
||||
BLARGG_DEF_MIN_MAX( unsigned long )
|
||||
BLARGG_DEF_MIN_MAX( float )
|
||||
BLARGG_DEF_MIN_MAX( double )
|
||||
|
||||
#undef min
|
||||
#define min blargg_min
|
||||
|
||||
#undef max
|
||||
#define max blargg_max
|
||||
|
||||
// typedef unsigned char byte;
|
||||
typedef unsigned char blargg_byte;
|
||||
#undef byte
|
||||
#define byte blargg_byte
|
||||
|
||||
#ifndef BLARGG_EXPORT
|
||||
#if defined (_WIN32) && BLARGG_BUILD_DLL
|
||||
#define BLARGG_EXPORT __declspec(dllexport)
|
||||
#elif defined (__GNUC__)
|
||||
// can always set visibility, even when not building DLL
|
||||
#define BLARGG_EXPORT __attribute__ ((visibility ("default")))
|
||||
#else
|
||||
#define BLARGG_EXPORT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if BLARGG_LEGACY
|
||||
#define BLARGG_CHECK_ALLOC CHECK_ALLOC
|
||||
#define BLARGG_RETURN_ERR RETURN_ERR
|
||||
#endif
|
||||
|
||||
// Called after failed operation when overall operation may still complete OK.
|
||||
// Only used by unit testing framework.
|
||||
#undef ACK_FAILURE
|
||||
#define ACK_FAILURE() ((void)0)
|
||||
|
||||
/* BLARGG_SOURCE_BEGIN: If defined, #included, allowing redefition of dprintf etc.
|
||||
and check */
|
||||
#ifdef BLARGG_SOURCE_BEGIN
|
||||
#include BLARGG_SOURCE_BEGIN
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/* Included at the beginning of library source files, AFTER all other #include
|
||||
lines. Sets up helpful macros and services used in my source code. Since this
|
||||
is only "active" in my source code, I don't have to worry about polluting the
|
||||
global namespace with unprefixed names. */
|
||||
|
||||
// File_Extractor 1.0.0
|
||||
#ifndef BLARGG_SOURCE_H
|
||||
#define BLARGG_SOURCE_H
|
||||
|
||||
#ifndef BLARGG_COMMON_H // optimization only
|
||||
#include "blargg_common.h"
|
||||
#endif
|
||||
#include "blargg_errors.h"
|
||||
|
||||
#include <string.h> /* memcpy(), memset(), memmove() */
|
||||
#include <stddef.h> /* offsetof() */
|
||||
|
||||
/* The following four macros are for debugging only. Some or all might be
|
||||
defined to do nothing, depending on the circumstances. Described is what
|
||||
happens when a particular macro is defined to do something. When defined to
|
||||
do nothing, the macros do NOT evaluate their argument(s). */
|
||||
|
||||
/* If expr is false, prints file and line number, then aborts program. Meant
|
||||
for checking internal state and consistency. A failed assertion indicates a bug
|
||||
in MY code.
|
||||
|
||||
void assert( bool expr ); */
|
||||
#include <assert.h>
|
||||
|
||||
/* If expr is false, prints file and line number, then aborts program. Meant
|
||||
for checking caller-supplied parameters and operations that are outside the
|
||||
control of the module. A failed requirement probably indicates a bug in YOUR
|
||||
code.
|
||||
|
||||
void require( bool expr ); */
|
||||
#undef require
|
||||
#define require( expr ) assert( expr )
|
||||
|
||||
/* Like printf() except output goes to debugging console/file.
|
||||
|
||||
void dprintf( const char format [], ... ); */
|
||||
static inline void blargg_dprintf_( const char [], ... ) { }
|
||||
#undef dprintf
|
||||
#define dprintf (1) ? (void) 0 : blargg_dprintf_
|
||||
|
||||
/* If expr is false, prints file and line number to debug console/log, then
|
||||
continues execution normally. Meant for flagging potential problems or things
|
||||
that should be looked into, but that aren't serious problems.
|
||||
|
||||
void check( bool expr ); */
|
||||
#undef check
|
||||
#define check( expr ) ((void) 0)
|
||||
|
||||
/* If expr yields non-NULL error string, returns it from current function,
|
||||
otherwise continues normally. */
|
||||
#undef RETURN_ERR
|
||||
#define RETURN_ERR( expr ) \
|
||||
do {\
|
||||
blargg_err_t blargg_return_err_ = (expr);\
|
||||
if ( blargg_return_err_ )\
|
||||
return blargg_return_err_;\
|
||||
} while ( 0 )
|
||||
|
||||
/* If ptr is NULL, returns out-of-memory error, otherwise continues normally. */
|
||||
#undef CHECK_ALLOC
|
||||
#define CHECK_ALLOC( ptr ) \
|
||||
do {\
|
||||
if ( !(ptr) )\
|
||||
return blargg_err_memory;\
|
||||
} while ( 0 )
|
||||
|
||||
/* The usual min/max functions for built-in types.
|
||||
|
||||
template<typename T> T min( T x, T y ) { return x < y ? x : y; }
|
||||
template<typename T> T max( T x, T y ) { return x > y ? x : y; } */
|
||||
#define BLARGG_DEF_MIN_MAX( type ) \
|
||||
static inline type blargg_min( type x, type y ) { if ( y < x ) x = y; return x; }\
|
||||
static inline type blargg_max( type x, type y ) { if ( x < y ) x = y; return x; }
|
||||
|
||||
BLARGG_DEF_MIN_MAX( int )
|
||||
BLARGG_DEF_MIN_MAX( unsigned )
|
||||
BLARGG_DEF_MIN_MAX( long )
|
||||
BLARGG_DEF_MIN_MAX( unsigned long )
|
||||
BLARGG_DEF_MIN_MAX( float )
|
||||
BLARGG_DEF_MIN_MAX( double )
|
||||
|
||||
#undef min
|
||||
#define min blargg_min
|
||||
|
||||
#undef max
|
||||
#define max blargg_max
|
||||
|
||||
// typedef unsigned char byte;
|
||||
typedef unsigned char blargg_byte;
|
||||
#undef byte
|
||||
#define byte blargg_byte
|
||||
|
||||
#ifndef BLARGG_EXPORT
|
||||
#if defined (_WIN32) && BLARGG_BUILD_DLL
|
||||
#define BLARGG_EXPORT __declspec(dllexport)
|
||||
#elif defined (__GNUC__)
|
||||
// can always set visibility, even when not building DLL
|
||||
#define BLARGG_EXPORT __attribute__ ((visibility ("default")))
|
||||
#else
|
||||
#define BLARGG_EXPORT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if BLARGG_LEGACY
|
||||
#define BLARGG_CHECK_ALLOC CHECK_ALLOC
|
||||
#define BLARGG_RETURN_ERR RETURN_ERR
|
||||
#endif
|
||||
|
||||
// Called after failed operation when overall operation may still complete OK.
|
||||
// Only used by unit testing framework.
|
||||
#undef ACK_FAILURE
|
||||
#define ACK_FAILURE() ((void)0)
|
||||
|
||||
/* BLARGG_SOURCE_BEGIN: If defined, #included, allowing redefition of dprintf etc.
|
||||
and check */
|
||||
#ifdef BLARGG_SOURCE_BEGIN
|
||||
#include BLARGG_SOURCE_BEGIN
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
642
fex/fex/fex.cpp
642
fex/fex/fex.cpp
|
@ -1,321 +1,321 @@
|
|||
// File_Extractor 1.0.0. http://www.slack.net/~ant/
|
||||
|
||||
#include "fex.h"
|
||||
|
||||
#include "File_Extractor.h"
|
||||
#include "blargg_endian.h"
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/* Copyright (C) 2005-2009 Shay Green. This module is free software; you
|
||||
can redistribute it and/or modify it under the terms of the GNU Lesser
|
||||
General Public License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version. This
|
||||
module 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 Lesser General Public License for more
|
||||
details. You should have received a copy of the GNU Lesser General Public
|
||||
License along with this module; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
#include "blargg_source.h"
|
||||
|
||||
|
||||
//// Types
|
||||
|
||||
BLARGG_EXPORT const fex_type_t* fex_type_list( void )
|
||||
{
|
||||
static fex_type_t const fex_type_list_ [] =
|
||||
{
|
||||
#ifdef FEX_TYPE_LIST
|
||||
FEX_TYPE_LIST
|
||||
#else
|
||||
// Modify blargg_config.h to change type list, NOT this file
|
||||
fex_7z_type,
|
||||
fex_gz_type,
|
||||
#if FEX_ENABLE_RAR
|
||||
fex_rar_type,
|
||||
#endif
|
||||
fex_zip_type,
|
||||
#endif
|
||||
fex_bin_type,
|
||||
NULL
|
||||
};
|
||||
|
||||
return fex_type_list_;
|
||||
}
|
||||
|
||||
BLARGG_EXPORT fex_err_t fex_init( void )
|
||||
{
|
||||
static bool inited;
|
||||
if ( !inited )
|
||||
{
|
||||
for ( fex_type_t const* t = fex_type_list(); *t != NULL; ++t )
|
||||
{
|
||||
if ( (*t)->init )
|
||||
RETURN_ERR( (*t)->init() );
|
||||
}
|
||||
inited = true;
|
||||
}
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
BLARGG_EXPORT const char* fex_identify_header( void const* header )
|
||||
{
|
||||
unsigned four = get_be32( header );
|
||||
switch ( four )
|
||||
{
|
||||
case 0x52457E5E:
|
||||
case 0x52617221: return ".rar";
|
||||
|
||||
case 0x377ABCAF: return ".7z";
|
||||
|
||||
case 0x504B0304:
|
||||
case 0x504B0506: return ".zip";
|
||||
|
||||
case 0x53495421: return ".sit";
|
||||
case 0x41724301: return ".arc";
|
||||
case 0x4D534346: return ".cab";
|
||||
case 0x5A4F4F20: return ".zoo";
|
||||
}
|
||||
|
||||
unsigned three = four >> 8;
|
||||
switch ( three )
|
||||
{
|
||||
case 0x425A68: return ".bz2";
|
||||
}
|
||||
|
||||
unsigned two = four >> 16;
|
||||
switch ( two )
|
||||
{
|
||||
case 0x1F8B: return ".gz";
|
||||
case 0x60EA: return ".arj";
|
||||
}
|
||||
|
||||
unsigned skip_first_two = four & 0xFFFF;
|
||||
if ( skip_first_two == 0x2D6C )
|
||||
return ".lha";
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
static int fex_has_extension_( const char str [], const char suffix [], size_t str_len )
|
||||
{
|
||||
size_t suffix_len = strlen( suffix );
|
||||
if ( str_len >= suffix_len )
|
||||
{
|
||||
str += str_len - suffix_len;
|
||||
while ( *str && tolower( (unsigned char) *str ) == *suffix )
|
||||
{
|
||||
str++;
|
||||
suffix++;
|
||||
}
|
||||
}
|
||||
return *suffix == 0;
|
||||
}
|
||||
|
||||
BLARGG_EXPORT int fex_has_extension( const char str [], const char suffix [] )
|
||||
{
|
||||
return fex_has_extension_( str, suffix, strlen( str ) );
|
||||
}
|
||||
|
||||
static int is_archive_extension( const char str [] )
|
||||
{
|
||||
static const char exts [] [6] = {
|
||||
".7z",
|
||||
".arc",
|
||||
".arj",
|
||||
".bz2",
|
||||
".cab",
|
||||
".dmg",
|
||||
".gz",
|
||||
".lha",
|
||||
".lz",
|
||||
".lzh",
|
||||
".lzma",
|
||||
".lzo",
|
||||
".lzx",
|
||||
".pea",
|
||||
".rar",
|
||||
".sit",
|
||||
".sitx",
|
||||
".tgz",
|
||||
".tlz",
|
||||
".z",
|
||||
".zip",
|
||||
".zoo",
|
||||
""
|
||||
};
|
||||
|
||||
size_t str_len = strlen( str );
|
||||
const char (*ext) [6] = exts;
|
||||
for ( ; **ext; ext++ )
|
||||
{
|
||||
if ( fex_has_extension_( str, *ext, str_len ) )
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
BLARGG_EXPORT fex_type_t fex_identify_extension( const char str [] )
|
||||
{
|
||||
size_t str_len = strlen( str );
|
||||
for ( fex_type_t const* types = fex_type_list(); *types; types++ )
|
||||
{
|
||||
if ( fex_has_extension_( str, (*types)->extension, str_len ) )
|
||||
{
|
||||
// Avoid treating known archive type as binary
|
||||
if ( *(*types)->extension || !is_archive_extension( str ) )
|
||||
return *types;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BLARGG_EXPORT fex_err_t fex_identify_file( fex_type_t* type_out, const char path [] )
|
||||
{
|
||||
*type_out = NULL;
|
||||
|
||||
fex_type_t type = fex_identify_extension( path );
|
||||
|
||||
// Unsupported extension?
|
||||
if ( !type )
|
||||
return blargg_ok; // reject
|
||||
|
||||
// Unknown/no extension?
|
||||
if ( !*(type->extension) )
|
||||
{
|
||||
// Examine header
|
||||
FEX_FILE_READER in;
|
||||
RETURN_ERR( in.open( path ) );
|
||||
if ( in.remain() >= fex_identify_header_size )
|
||||
{
|
||||
char h [fex_identify_header_size];
|
||||
RETURN_ERR( in.read( h, sizeof h ) );
|
||||
|
||||
type = fex_identify_extension( fex_identify_header( h ) );
|
||||
}
|
||||
}
|
||||
|
||||
*type_out = type;
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
BLARGG_EXPORT fex_err_t fex_open_type( fex_t** fe_out, const char path [], fex_type_t type )
|
||||
{
|
||||
*fe_out = NULL;
|
||||
|
||||
if ( !type )
|
||||
return blargg_err_file_type;
|
||||
|
||||
fex_t* fe = type->new_fex();
|
||||
CHECK_ALLOC( fe );
|
||||
|
||||
fex_err_t err = fe->open( path );
|
||||
if ( err )
|
||||
{
|
||||
delete fe;
|
||||
return err;
|
||||
}
|
||||
|
||||
*fe_out = fe;
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
BLARGG_EXPORT fex_err_t fex_open( fex_t** fe_out, const char path [] )
|
||||
{
|
||||
*fe_out = NULL;
|
||||
|
||||
fex_type_t type;
|
||||
RETURN_ERR( fex_identify_file( &type, path ) );
|
||||
|
||||
return fex_open_type( fe_out, path, type );
|
||||
}
|
||||
|
||||
|
||||
//// Wide paths
|
||||
|
||||
char* fex_wide_to_path( const wchar_t* wide )
|
||||
{
|
||||
return blargg_to_utf8( wide );
|
||||
}
|
||||
|
||||
void fex_free_path( char* path )
|
||||
{
|
||||
free( path );
|
||||
}
|
||||
|
||||
|
||||
//// Errors
|
||||
|
||||
#define ENTRY( name ) { blargg_err_##name, fex_err_##name }
|
||||
static blargg_err_to_code_t const fex_codes [] =
|
||||
{
|
||||
ENTRY( generic ),
|
||||
ENTRY( memory ),
|
||||
ENTRY( caller ),
|
||||
ENTRY( internal ),
|
||||
ENTRY( limitation ),
|
||||
|
||||
ENTRY( file_missing ),
|
||||
ENTRY( file_read ),
|
||||
ENTRY( file_io ),
|
||||
ENTRY( file_eof ),
|
||||
|
||||
ENTRY( file_type ),
|
||||
ENTRY( file_feature ),
|
||||
ENTRY( file_corrupt ),
|
||||
|
||||
{ 0, -1 }
|
||||
};
|
||||
#undef ENTRY
|
||||
|
||||
static int err_code( fex_err_t err )
|
||||
{
|
||||
return blargg_err_to_code( err, fex_codes );
|
||||
}
|
||||
|
||||
BLARGG_EXPORT int fex_err_code( fex_err_t err )
|
||||
{
|
||||
int code = err_code( err );
|
||||
return (code >= 0 ? code : fex_err_generic);
|
||||
}
|
||||
|
||||
BLARGG_EXPORT fex_err_t fex_code_to_err( int code )
|
||||
{
|
||||
return blargg_code_to_err( code, fex_codes );
|
||||
}
|
||||
|
||||
BLARGG_EXPORT const char* fex_err_details( fex_err_t err )
|
||||
{
|
||||
// If we don't have error code assigned, return entire string
|
||||
return (err_code( err ) >= 0 ? blargg_err_details( err ) : blargg_err_str( err ));
|
||||
}
|
||||
|
||||
|
||||
//// Wrappers
|
||||
|
||||
BLARGG_EXPORT fex_err_t fex_read( fex_t* fe, void* out, int count )
|
||||
{
|
||||
RETURN_ERR( fe->stat() );
|
||||
return fe->reader().read( out, count );
|
||||
}
|
||||
|
||||
BLARGG_EXPORT void fex_close ( fex_t* fe ) { delete fe; }
|
||||
BLARGG_EXPORT fex_type_t fex_type ( const fex_t* fe ) { return fe->type(); }
|
||||
BLARGG_EXPORT int fex_done ( const fex_t* fe ) { return fe->done(); }
|
||||
BLARGG_EXPORT const char* fex_name ( const fex_t* fe ) { return fe->name(); }
|
||||
BLARGG_EXPORT const wchar_t* fex_wname ( const fex_t* fe ) { return fe->wname(); }
|
||||
BLARGG_EXPORT int fex_size ( const fex_t* fe ) { return fe->size(); }
|
||||
BLARGG_EXPORT unsigned fex_dos_date ( const fex_t* fe ) { return fe->dos_date(); }
|
||||
BLARGG_EXPORT unsigned fex_crc32 ( const fex_t* fe ) { return fe->crc32(); }
|
||||
BLARGG_EXPORT fex_err_t fex_stat ( fex_t* fe ) { return fe->stat(); }
|
||||
BLARGG_EXPORT fex_err_t fex_next ( fex_t* fe ) { return fe->next(); }
|
||||
BLARGG_EXPORT fex_err_t fex_rewind ( fex_t* fe ) { return fe->rewind(); }
|
||||
BLARGG_EXPORT int fex_tell ( const fex_t* fe ) { return fe->tell(); }
|
||||
BLARGG_EXPORT fex_pos_t fex_tell_arc ( const fex_t* fe ) { return fe->tell_arc(); }
|
||||
BLARGG_EXPORT fex_err_t fex_seek_arc ( fex_t* fe, fex_pos_t pos ) { return fe->seek_arc( pos ); }
|
||||
BLARGG_EXPORT const char* fex_type_extension ( fex_type_t t ) { return t->extension; }
|
||||
BLARGG_EXPORT const char* fex_type_name ( fex_type_t t ) { return t->name; }
|
||||
BLARGG_EXPORT fex_err_t fex_data ( fex_t* fe, const void** data_out ) { return fe->data( data_out ); }
|
||||
BLARGG_EXPORT const char* fex_err_str ( fex_err_t err ) { return blargg_err_str( err ); }
|
||||
// File_Extractor 1.0.0. http://www.slack.net/~ant/
|
||||
|
||||
#include "fex.h"
|
||||
|
||||
#include "File_Extractor.h"
|
||||
#include "blargg_endian.h"
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/* Copyright (C) 2005-2009 Shay Green. This module is free software; you
|
||||
can redistribute it and/or modify it under the terms of the GNU Lesser
|
||||
General Public License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version. This
|
||||
module 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 Lesser General Public License for more
|
||||
details. You should have received a copy of the GNU Lesser General Public
|
||||
License along with this module; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
#include "blargg_source.h"
|
||||
|
||||
|
||||
//// Types
|
||||
|
||||
BLARGG_EXPORT const fex_type_t* fex_type_list( void )
|
||||
{
|
||||
static fex_type_t const fex_type_list_ [] =
|
||||
{
|
||||
#ifdef FEX_TYPE_LIST
|
||||
FEX_TYPE_LIST
|
||||
#else
|
||||
// Modify blargg_config.h to change type list, NOT this file
|
||||
fex_7z_type,
|
||||
fex_gz_type,
|
||||
#if FEX_ENABLE_RAR
|
||||
fex_rar_type,
|
||||
#endif
|
||||
fex_zip_type,
|
||||
#endif
|
||||
fex_bin_type,
|
||||
NULL
|
||||
};
|
||||
|
||||
return fex_type_list_;
|
||||
}
|
||||
|
||||
BLARGG_EXPORT fex_err_t fex_init( void )
|
||||
{
|
||||
static bool inited;
|
||||
if ( !inited )
|
||||
{
|
||||
for ( fex_type_t const* t = fex_type_list(); *t != NULL; ++t )
|
||||
{
|
||||
if ( (*t)->init )
|
||||
RETURN_ERR( (*t)->init() );
|
||||
}
|
||||
inited = true;
|
||||
}
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
BLARGG_EXPORT const char* fex_identify_header( void const* header )
|
||||
{
|
||||
unsigned four = get_be32( header );
|
||||
switch ( four )
|
||||
{
|
||||
case 0x52457E5E:
|
||||
case 0x52617221: return ".rar";
|
||||
|
||||
case 0x377ABCAF: return ".7z";
|
||||
|
||||
case 0x504B0304:
|
||||
case 0x504B0506: return ".zip";
|
||||
|
||||
case 0x53495421: return ".sit";
|
||||
case 0x41724301: return ".arc";
|
||||
case 0x4D534346: return ".cab";
|
||||
case 0x5A4F4F20: return ".zoo";
|
||||
}
|
||||
|
||||
unsigned three = four >> 8;
|
||||
switch ( three )
|
||||
{
|
||||
case 0x425A68: return ".bz2";
|
||||
}
|
||||
|
||||
unsigned two = four >> 16;
|
||||
switch ( two )
|
||||
{
|
||||
case 0x1F8B: return ".gz";
|
||||
case 0x60EA: return ".arj";
|
||||
}
|
||||
|
||||
unsigned skip_first_two = four & 0xFFFF;
|
||||
if ( skip_first_two == 0x2D6C )
|
||||
return ".lha";
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
static int fex_has_extension_( const char str [], const char suffix [], size_t str_len )
|
||||
{
|
||||
size_t suffix_len = strlen( suffix );
|
||||
if ( str_len >= suffix_len )
|
||||
{
|
||||
str += str_len - suffix_len;
|
||||
while ( *str && tolower( (unsigned char) *str ) == *suffix )
|
||||
{
|
||||
str++;
|
||||
suffix++;
|
||||
}
|
||||
}
|
||||
return *suffix == 0;
|
||||
}
|
||||
|
||||
BLARGG_EXPORT int fex_has_extension( const char str [], const char suffix [] )
|
||||
{
|
||||
return fex_has_extension_( str, suffix, strlen( str ) );
|
||||
}
|
||||
|
||||
static int is_archive_extension( const char str [] )
|
||||
{
|
||||
static const char exts [] [6] = {
|
||||
".7z",
|
||||
".arc",
|
||||
".arj",
|
||||
".bz2",
|
||||
".cab",
|
||||
".dmg",
|
||||
".gz",
|
||||
".lha",
|
||||
".lz",
|
||||
".lzh",
|
||||
".lzma",
|
||||
".lzo",
|
||||
".lzx",
|
||||
".pea",
|
||||
".rar",
|
||||
".sit",
|
||||
".sitx",
|
||||
".tgz",
|
||||
".tlz",
|
||||
".z",
|
||||
".zip",
|
||||
".zoo",
|
||||
""
|
||||
};
|
||||
|
||||
size_t str_len = strlen( str );
|
||||
const char (*ext) [6] = exts;
|
||||
for ( ; **ext; ext++ )
|
||||
{
|
||||
if ( fex_has_extension_( str, *ext, str_len ) )
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
BLARGG_EXPORT fex_type_t fex_identify_extension( const char str [] )
|
||||
{
|
||||
size_t str_len = strlen( str );
|
||||
for ( fex_type_t const* types = fex_type_list(); *types; types++ )
|
||||
{
|
||||
if ( fex_has_extension_( str, (*types)->extension, str_len ) )
|
||||
{
|
||||
// Avoid treating known archive type as binary
|
||||
if ( *(*types)->extension || !is_archive_extension( str ) )
|
||||
return *types;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BLARGG_EXPORT fex_err_t fex_identify_file( fex_type_t* type_out, const char path [] )
|
||||
{
|
||||
*type_out = NULL;
|
||||
|
||||
fex_type_t type = fex_identify_extension( path );
|
||||
|
||||
// Unsupported extension?
|
||||
if ( !type )
|
||||
return blargg_ok; // reject
|
||||
|
||||
// Unknown/no extension?
|
||||
if ( !*(type->extension) )
|
||||
{
|
||||
// Examine header
|
||||
FEX_FILE_READER in;
|
||||
RETURN_ERR( in.open( path ) );
|
||||
if ( in.remain() >= fex_identify_header_size )
|
||||
{
|
||||
char h [fex_identify_header_size];
|
||||
RETURN_ERR( in.read( h, sizeof h ) );
|
||||
|
||||
type = fex_identify_extension( fex_identify_header( h ) );
|
||||
}
|
||||
}
|
||||
|
||||
*type_out = type;
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
BLARGG_EXPORT fex_err_t fex_open_type( fex_t** fe_out, const char path [], fex_type_t type )
|
||||
{
|
||||
*fe_out = NULL;
|
||||
|
||||
if ( !type )
|
||||
return blargg_err_file_type;
|
||||
|
||||
fex_t* fe = type->new_fex();
|
||||
CHECK_ALLOC( fe );
|
||||
|
||||
fex_err_t err = fe->open( path );
|
||||
if ( err )
|
||||
{
|
||||
delete fe;
|
||||
return err;
|
||||
}
|
||||
|
||||
*fe_out = fe;
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
BLARGG_EXPORT fex_err_t fex_open( fex_t** fe_out, const char path [] )
|
||||
{
|
||||
*fe_out = NULL;
|
||||
|
||||
fex_type_t type;
|
||||
RETURN_ERR( fex_identify_file( &type, path ) );
|
||||
|
||||
return fex_open_type( fe_out, path, type );
|
||||
}
|
||||
|
||||
|
||||
//// Wide paths
|
||||
|
||||
char* fex_wide_to_path( const wchar_t* wide )
|
||||
{
|
||||
return blargg_to_utf8( wide );
|
||||
}
|
||||
|
||||
void fex_free_path( char* path )
|
||||
{
|
||||
free( path );
|
||||
}
|
||||
|
||||
|
||||
//// Errors
|
||||
|
||||
#define ENTRY( name ) { blargg_err_##name, fex_err_##name }
|
||||
static blargg_err_to_code_t const fex_codes [] =
|
||||
{
|
||||
ENTRY( generic ),
|
||||
ENTRY( memory ),
|
||||
ENTRY( caller ),
|
||||
ENTRY( internal ),
|
||||
ENTRY( limitation ),
|
||||
|
||||
ENTRY( file_missing ),
|
||||
ENTRY( file_read ),
|
||||
ENTRY( file_io ),
|
||||
ENTRY( file_eof ),
|
||||
|
||||
ENTRY( file_type ),
|
||||
ENTRY( file_feature ),
|
||||
ENTRY( file_corrupt ),
|
||||
|
||||
{ 0, -1 }
|
||||
};
|
||||
#undef ENTRY
|
||||
|
||||
static int err_code( fex_err_t err )
|
||||
{
|
||||
return blargg_err_to_code( err, fex_codes );
|
||||
}
|
||||
|
||||
BLARGG_EXPORT int fex_err_code( fex_err_t err )
|
||||
{
|
||||
int code = err_code( err );
|
||||
return (code >= 0 ? code : fex_err_generic);
|
||||
}
|
||||
|
||||
BLARGG_EXPORT fex_err_t fex_code_to_err( int code )
|
||||
{
|
||||
return blargg_code_to_err( code, fex_codes );
|
||||
}
|
||||
|
||||
BLARGG_EXPORT const char* fex_err_details( fex_err_t err )
|
||||
{
|
||||
// If we don't have error code assigned, return entire string
|
||||
return (err_code( err ) >= 0 ? blargg_err_details( err ) : blargg_err_str( err ));
|
||||
}
|
||||
|
||||
|
||||
//// Wrappers
|
||||
|
||||
BLARGG_EXPORT fex_err_t fex_read( fex_t* fe, void* out, int count )
|
||||
{
|
||||
RETURN_ERR( fe->stat() );
|
||||
return fe->reader().read( out, count );
|
||||
}
|
||||
|
||||
BLARGG_EXPORT void fex_close ( fex_t* fe ) { delete fe; }
|
||||
BLARGG_EXPORT fex_type_t fex_type ( const fex_t* fe ) { return fe->type(); }
|
||||
BLARGG_EXPORT int fex_done ( const fex_t* fe ) { return fe->done(); }
|
||||
BLARGG_EXPORT const char* fex_name ( const fex_t* fe ) { return fe->name(); }
|
||||
BLARGG_EXPORT const wchar_t* fex_wname ( const fex_t* fe ) { return fe->wname(); }
|
||||
BLARGG_EXPORT int fex_size ( const fex_t* fe ) { return fe->size(); }
|
||||
BLARGG_EXPORT unsigned fex_dos_date ( const fex_t* fe ) { return fe->dos_date(); }
|
||||
BLARGG_EXPORT unsigned fex_crc32 ( const fex_t* fe ) { return fe->crc32(); }
|
||||
BLARGG_EXPORT fex_err_t fex_stat ( fex_t* fe ) { return fe->stat(); }
|
||||
BLARGG_EXPORT fex_err_t fex_next ( fex_t* fe ) { return fe->next(); }
|
||||
BLARGG_EXPORT fex_err_t fex_rewind ( fex_t* fe ) { return fe->rewind(); }
|
||||
BLARGG_EXPORT int fex_tell ( const fex_t* fe ) { return fe->tell(); }
|
||||
BLARGG_EXPORT fex_pos_t fex_tell_arc ( const fex_t* fe ) { return fe->tell_arc(); }
|
||||
BLARGG_EXPORT fex_err_t fex_seek_arc ( fex_t* fe, fex_pos_t pos ) { return fe->seek_arc( pos ); }
|
||||
BLARGG_EXPORT const char* fex_type_extension ( fex_type_t t ) { return t->extension; }
|
||||
BLARGG_EXPORT const char* fex_type_name ( fex_type_t t ) { return t->name; }
|
||||
BLARGG_EXPORT fex_err_t fex_data ( fex_t* fe, const void** data_out ) { return fe->data( data_out ); }
|
||||
BLARGG_EXPORT const char* fex_err_str ( fex_err_t err ) { return blargg_err_str( err ); }
|
||||
|
|
408
fex/fex/fex.h
408
fex/fex/fex.h
|
@ -1,204 +1,204 @@
|
|||
/** Uniform access to zip, gzip, 7-zip, and RAR compressed archives \file */
|
||||
|
||||
/* File_Extractor 1.0.0 */
|
||||
#ifndef FEX_H
|
||||
#define FEX_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/** First parameter of most functions is fex_t*, or const fex_t* if nothing is
|
||||
changed. Once one of these functions returns an error, the archive should not
|
||||
be used any further, other than to close it. One exception is
|
||||
fex_error_file_eof; the archive may still be used after this. */
|
||||
typedef struct fex_t fex_t;
|
||||
|
||||
/** Pointer to error, or NULL if function was successful. See error functions
|
||||
below. */
|
||||
#ifndef fex_err_t /* (#ifndef allows better testing of library) */
|
||||
typedef const char* fex_err_t;
|
||||
#endif
|
||||
|
||||
|
||||
/**** File types ****/
|
||||
|
||||
/** Archive file type identifier. Can also hold NULL. */
|
||||
typedef const struct fex_type_t_* fex_type_t;
|
||||
|
||||
/** Array of supported types, with NULL at end */
|
||||
const fex_type_t* fex_type_list( void );
|
||||
|
||||
/** Name of this archive type, e.g. "ZIP archive", "file" */
|
||||
const char* fex_type_name( fex_type_t );
|
||||
|
||||
/** Usual file extension for type, e.g. ".zip", ".7z". For binary file type,
|
||||
returns "", since it can open any file. */
|
||||
const char* fex_type_extension( fex_type_t );
|
||||
|
||||
|
||||
/**** Wide-character file paths ****/
|
||||
|
||||
/** Converts wide-character path to form suitable for use with fex functions. */
|
||||
char* fex_wide_to_path( const wchar_t* wide );
|
||||
|
||||
/** Frees converted path. OK to pass NULL. */
|
||||
void fex_free_path( char* );
|
||||
|
||||
|
||||
/**** Identification ****/
|
||||
|
||||
/** True if str ends in extension. If extension is "", always returns true.
|
||||
Converts str to lowercase before comparison, so extension should ALREADY be
|
||||
lowercase (i.e. pass ".zip", NOT ".ZIP"). */
|
||||
int fex_has_extension( const char str [], const char extension [] );
|
||||
|
||||
/** Determines type based on first fex_identify_header_size bytes of file.
|
||||
Returns usual file extension this should have (e.g. ".zip", ".gz", etc.).
|
||||
Returns "" if file header is not recognized. */
|
||||
const char* fex_identify_header( const void* header );
|
||||
enum { fex_identify_header_size = 16 };
|
||||
|
||||
/** Determines type based on extension of a file path, or just a lone extension
|
||||
(must include '.', e.g. ".zip", NOT just "zip"). Returns NULL if extension is
|
||||
for an unsupported type (e.g. ".lzh"). */
|
||||
fex_type_t fex_identify_extension( const char path_or_extension [] );
|
||||
|
||||
/** Determines type based on filename extension and/or file header. Sets *out
|
||||
to determined type, or NULL if type is not supported. */
|
||||
fex_err_t fex_identify_file( fex_type_t* out, const char path [] );
|
||||
|
||||
/** Type of an already-opened archive */
|
||||
fex_type_t fex_type( const fex_t* );
|
||||
|
||||
|
||||
/**** Open/close ****/
|
||||
|
||||
/** Initializes static tables used by library. Automatically called by
|
||||
fex_open(). OK to call more than once. */
|
||||
fex_err_t fex_init( void );
|
||||
|
||||
/** Opens archive and points *out at it. If error, sets *out to NULL. */
|
||||
fex_err_t fex_open( fex_t** out, const char path [] );
|
||||
|
||||
/** Opens archive of specified type and sets *out. Returns error if file is not
|
||||
of that archive type. If error, sets *out to NULL. */
|
||||
fex_err_t fex_open_type( fex_t** out, const char path [], fex_type_t );
|
||||
|
||||
/** Closes archive and frees memory. OK to pass NULL. */
|
||||
void fex_close( fex_t* );
|
||||
|
||||
|
||||
/**** Scanning ****/
|
||||
|
||||
/** True if at end of archive. Must be called after fex_open() or fex_rewind(),
|
||||
as an archive might contain no files. */
|
||||
int fex_done( const fex_t* );
|
||||
|
||||
/** Goes to next file in archive. If there are no more files, fex_done() will
|
||||
now return true. */
|
||||
fex_err_t fex_next( fex_t* );
|
||||
|
||||
/** Goes back to first file in archive, as if it were just opened with
|
||||
fex_open() */
|
||||
fex_err_t fex_rewind( fex_t* );
|
||||
|
||||
/** Saved position in archive. Can also store zero. */
|
||||
typedef int fex_pos_t;
|
||||
|
||||
/** Position of current file in archive. Never returns zero. */
|
||||
fex_pos_t fex_tell_arc( const fex_t* );
|
||||
|
||||
/** Returns to file at previously-saved position */
|
||||
fex_err_t fex_seek_arc( fex_t*, fex_pos_t );
|
||||
|
||||
|
||||
/**** Info ****/
|
||||
|
||||
/** Name of current file */
|
||||
const char* fex_name( const fex_t* );
|
||||
|
||||
/** Wide-character name of current file, or NULL if unavailable */
|
||||
const wchar_t* fex_wname( const fex_t* );
|
||||
|
||||
/** Makes further information available for file */
|
||||
fex_err_t fex_stat( fex_t* );
|
||||
|
||||
/** Size of current file. fex_stat() or fex_data() must have been called. */
|
||||
int fex_size( const fex_t* );
|
||||
|
||||
/** Modification date of current file (MS-DOS format), or 0 if unavailable.
|
||||
fex_stat() must have been called. */
|
||||
unsigned int fex_dos_date( const fex_t* );
|
||||
|
||||
/** CRC-32 checksum of current file's contents, or 0 if unavailable. Doesn't
|
||||
require calculation; simply gets it from file's header. fex_stat() must have
|
||||
been called. */
|
||||
unsigned int fex_crc32( const fex_t* );
|
||||
|
||||
|
||||
/**** Extraction ****/
|
||||
|
||||
/** Reads n bytes from current file. Reading past end of file results in
|
||||
fex_err_file_eof. */
|
||||
fex_err_t fex_read( fex_t*, void* out, int n );
|
||||
|
||||
/** Number of bytes read from current file */
|
||||
int fex_tell( const fex_t* );
|
||||
|
||||
/** Points *out at current file's data in memory. Pointer is valid until
|
||||
fex_next(), fex_rewind(), fex_seek_arc(), or fex_close() is called. Pointer
|
||||
must NOT be freed(); library frees it automatically. If error, sets *out to
|
||||
NULL. */
|
||||
fex_err_t fex_data( fex_t*, const void** out );
|
||||
|
||||
|
||||
/**** Errors ****/
|
||||
|
||||
/** Error string associated with err. Returns "" if err is NULL. Returns err
|
||||
unchanged if it isn't a fex_err_t returned by library. */
|
||||
const char* fex_err_str( fex_err_t err );
|
||||
|
||||
/** Details of error beyond main cause, or "" if none or err is NULL. Returns
|
||||
err unchanged if it isn't a fex_err_t returned by library. */
|
||||
const char* fex_err_details( fex_err_t err );
|
||||
|
||||
/** Numeric code corresponding to err. Returns fex_ok if err is NULL. Returns
|
||||
fex_err_generic if err isn't a fex_err_t returned by library. */
|
||||
int fex_err_code( fex_err_t err );
|
||||
|
||||
enum {
|
||||
fex_ok = 0,/**< Successful call. Guaranteed to be zero. */
|
||||
fex_err_generic = 0x01,/**< Error of unspecified type */
|
||||
fex_err_memory = 0x02,/**< Out of memory */
|
||||
fex_err_caller = 0x03,/**< Caller called function with bad args */
|
||||
fex_err_internal = 0x04,/**< Internal problem, bug, etc. */
|
||||
fex_err_limitation = 0x05,/**< Exceeded program limit */
|
||||
|
||||
fex_err_file_missing = 0x20,/**< File not found at specified path */
|
||||
fex_err_file_read = 0x21,/**< Couldn't open file for reading */
|
||||
fex_err_file_io = 0x23,/**< Read/write error */
|
||||
fex_err_file_eof = 0x25,/**< Tried to read past end of file */
|
||||
|
||||
fex_err_file_type = 0x30,/**< File is of wrong type */
|
||||
fex_err_file_feature = 0x32,/**< File requires unsupported feature */
|
||||
fex_err_file_corrupt = 0x33 /**< File is corrupt */
|
||||
};
|
||||
|
||||
/** fex_err_t corresponding to numeric code. Note that this might not recover
|
||||
the original fex_err_t before it was converted to a numeric code; in
|
||||
particular, fex_err_details(fex_code_to_err(code)) will be "" in most cases. */
|
||||
fex_err_t fex_code_to_err( int code );
|
||||
|
||||
|
||||
/* Deprecated */
|
||||
typedef fex_t File_Extractor;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/** Uniform access to zip, gzip, 7-zip, and RAR compressed archives \file */
|
||||
|
||||
/* File_Extractor 1.0.0 */
|
||||
#ifndef FEX_H
|
||||
#define FEX_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/** First parameter of most functions is fex_t*, or const fex_t* if nothing is
|
||||
changed. Once one of these functions returns an error, the archive should not
|
||||
be used any further, other than to close it. One exception is
|
||||
fex_error_file_eof; the archive may still be used after this. */
|
||||
typedef struct fex_t fex_t;
|
||||
|
||||
/** Pointer to error, or NULL if function was successful. See error functions
|
||||
below. */
|
||||
#ifndef fex_err_t /* (#ifndef allows better testing of library) */
|
||||
typedef const char* fex_err_t;
|
||||
#endif
|
||||
|
||||
|
||||
/**** File types ****/
|
||||
|
||||
/** Archive file type identifier. Can also hold NULL. */
|
||||
typedef const struct fex_type_t_* fex_type_t;
|
||||
|
||||
/** Array of supported types, with NULL at end */
|
||||
const fex_type_t* fex_type_list( void );
|
||||
|
||||
/** Name of this archive type, e.g. "ZIP archive", "file" */
|
||||
const char* fex_type_name( fex_type_t );
|
||||
|
||||
/** Usual file extension for type, e.g. ".zip", ".7z". For binary file type,
|
||||
returns "", since it can open any file. */
|
||||
const char* fex_type_extension( fex_type_t );
|
||||
|
||||
|
||||
/**** Wide-character file paths ****/
|
||||
|
||||
/** Converts wide-character path to form suitable for use with fex functions. */
|
||||
char* fex_wide_to_path( const wchar_t* wide );
|
||||
|
||||
/** Frees converted path. OK to pass NULL. */
|
||||
void fex_free_path( char* );
|
||||
|
||||
|
||||
/**** Identification ****/
|
||||
|
||||
/** True if str ends in extension. If extension is "", always returns true.
|
||||
Converts str to lowercase before comparison, so extension should ALREADY be
|
||||
lowercase (i.e. pass ".zip", NOT ".ZIP"). */
|
||||
int fex_has_extension( const char str [], const char extension [] );
|
||||
|
||||
/** Determines type based on first fex_identify_header_size bytes of file.
|
||||
Returns usual file extension this should have (e.g. ".zip", ".gz", etc.).
|
||||
Returns "" if file header is not recognized. */
|
||||
const char* fex_identify_header( const void* header );
|
||||
enum { fex_identify_header_size = 16 };
|
||||
|
||||
/** Determines type based on extension of a file path, or just a lone extension
|
||||
(must include '.', e.g. ".zip", NOT just "zip"). Returns NULL if extension is
|
||||
for an unsupported type (e.g. ".lzh"). */
|
||||
fex_type_t fex_identify_extension( const char path_or_extension [] );
|
||||
|
||||
/** Determines type based on filename extension and/or file header. Sets *out
|
||||
to determined type, or NULL if type is not supported. */
|
||||
fex_err_t fex_identify_file( fex_type_t* out, const char path [] );
|
||||
|
||||
/** Type of an already-opened archive */
|
||||
fex_type_t fex_type( const fex_t* );
|
||||
|
||||
|
||||
/**** Open/close ****/
|
||||
|
||||
/** Initializes static tables used by library. Automatically called by
|
||||
fex_open(). OK to call more than once. */
|
||||
fex_err_t fex_init( void );
|
||||
|
||||
/** Opens archive and points *out at it. If error, sets *out to NULL. */
|
||||
fex_err_t fex_open( fex_t** out, const char path [] );
|
||||
|
||||
/** Opens archive of specified type and sets *out. Returns error if file is not
|
||||
of that archive type. If error, sets *out to NULL. */
|
||||
fex_err_t fex_open_type( fex_t** out, const char path [], fex_type_t );
|
||||
|
||||
/** Closes archive and frees memory. OK to pass NULL. */
|
||||
void fex_close( fex_t* );
|
||||
|
||||
|
||||
/**** Scanning ****/
|
||||
|
||||
/** True if at end of archive. Must be called after fex_open() or fex_rewind(),
|
||||
as an archive might contain no files. */
|
||||
int fex_done( const fex_t* );
|
||||
|
||||
/** Goes to next file in archive. If there are no more files, fex_done() will
|
||||
now return true. */
|
||||
fex_err_t fex_next( fex_t* );
|
||||
|
||||
/** Goes back to first file in archive, as if it were just opened with
|
||||
fex_open() */
|
||||
fex_err_t fex_rewind( fex_t* );
|
||||
|
||||
/** Saved position in archive. Can also store zero. */
|
||||
typedef int fex_pos_t;
|
||||
|
||||
/** Position of current file in archive. Never returns zero. */
|
||||
fex_pos_t fex_tell_arc( const fex_t* );
|
||||
|
||||
/** Returns to file at previously-saved position */
|
||||
fex_err_t fex_seek_arc( fex_t*, fex_pos_t );
|
||||
|
||||
|
||||
/**** Info ****/
|
||||
|
||||
/** Name of current file */
|
||||
const char* fex_name( const fex_t* );
|
||||
|
||||
/** Wide-character name of current file, or NULL if unavailable */
|
||||
const wchar_t* fex_wname( const fex_t* );
|
||||
|
||||
/** Makes further information available for file */
|
||||
fex_err_t fex_stat( fex_t* );
|
||||
|
||||
/** Size of current file. fex_stat() or fex_data() must have been called. */
|
||||
int fex_size( const fex_t* );
|
||||
|
||||
/** Modification date of current file (MS-DOS format), or 0 if unavailable.
|
||||
fex_stat() must have been called. */
|
||||
unsigned int fex_dos_date( const fex_t* );
|
||||
|
||||
/** CRC-32 checksum of current file's contents, or 0 if unavailable. Doesn't
|
||||
require calculation; simply gets it from file's header. fex_stat() must have
|
||||
been called. */
|
||||
unsigned int fex_crc32( const fex_t* );
|
||||
|
||||
|
||||
/**** Extraction ****/
|
||||
|
||||
/** Reads n bytes from current file. Reading past end of file results in
|
||||
fex_err_file_eof. */
|
||||
fex_err_t fex_read( fex_t*, void* out, int n );
|
||||
|
||||
/** Number of bytes read from current file */
|
||||
int fex_tell( const fex_t* );
|
||||
|
||||
/** Points *out at current file's data in memory. Pointer is valid until
|
||||
fex_next(), fex_rewind(), fex_seek_arc(), or fex_close() is called. Pointer
|
||||
must NOT be freed(); library frees it automatically. If error, sets *out to
|
||||
NULL. */
|
||||
fex_err_t fex_data( fex_t*, const void** out );
|
||||
|
||||
|
||||
/**** Errors ****/
|
||||
|
||||
/** Error string associated with err. Returns "" if err is NULL. Returns err
|
||||
unchanged if it isn't a fex_err_t returned by library. */
|
||||
const char* fex_err_str( fex_err_t err );
|
||||
|
||||
/** Details of error beyond main cause, or "" if none or err is NULL. Returns
|
||||
err unchanged if it isn't a fex_err_t returned by library. */
|
||||
const char* fex_err_details( fex_err_t err );
|
||||
|
||||
/** Numeric code corresponding to err. Returns fex_ok if err is NULL. Returns
|
||||
fex_err_generic if err isn't a fex_err_t returned by library. */
|
||||
int fex_err_code( fex_err_t err );
|
||||
|
||||
enum {
|
||||
fex_ok = 0,/**< Successful call. Guaranteed to be zero. */
|
||||
fex_err_generic = 0x01,/**< Error of unspecified type */
|
||||
fex_err_memory = 0x02,/**< Out of memory */
|
||||
fex_err_caller = 0x03,/**< Caller called function with bad args */
|
||||
fex_err_internal = 0x04,/**< Internal problem, bug, etc. */
|
||||
fex_err_limitation = 0x05,/**< Exceeded program limit */
|
||||
|
||||
fex_err_file_missing = 0x20,/**< File not found at specified path */
|
||||
fex_err_file_read = 0x21,/**< Couldn't open file for reading */
|
||||
fex_err_file_io = 0x23,/**< Read/write error */
|
||||
fex_err_file_eof = 0x25,/**< Tried to read past end of file */
|
||||
|
||||
fex_err_file_type = 0x30,/**< File is of wrong type */
|
||||
fex_err_file_feature = 0x32,/**< File requires unsupported feature */
|
||||
fex_err_file_corrupt = 0x33 /**< File is corrupt */
|
||||
};
|
||||
|
||||
/** fex_err_t corresponding to numeric code. Note that this might not recover
|
||||
the original fex_err_t before it was converted to a numeric code; in
|
||||
particular, fex_err_details(fex_code_to_err(code)) will be "" in most cases. */
|
||||
fex_err_t fex_code_to_err( int code );
|
||||
|
||||
|
||||
/* Deprecated */
|
||||
typedef fex_t File_Extractor;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,91 +1,91 @@
|
|||
File_Extractor library internals
|
||||
--------------------------------
|
||||
This describes the implementation and design.
|
||||
|
||||
Contents
|
||||
--------
|
||||
* Framework
|
||||
* Archive abstraction
|
||||
* 7-ZIP
|
||||
* ZIP
|
||||
* RAR
|
||||
* GZIP
|
||||
* Binary
|
||||
|
||||
|
||||
Framework
|
||||
---------
|
||||
This library is essentially:
|
||||
|
||||
* Several archive readers
|
||||
* Wrappers to provide common interface
|
||||
* File type detection
|
||||
|
||||
The File_Extractor base class implements the common aspects of the
|
||||
interface and filters out invalid calls. It also provides default
|
||||
implementations for some operations. Each derived *_Extractor class then
|
||||
wraps the particular library.
|
||||
|
||||
Then fex.h provides a stable, C-compatible wrapper over File_Extractor,
|
||||
and does file type identification.
|
||||
|
||||
|
||||
Archive abstraction
|
||||
-------------------
|
||||
An extractor is abstracted to these fundamental operations:
|
||||
|
||||
* Open (either from path or custom reader)
|
||||
* Iterate over each file
|
||||
* Extract file's data (either gradually, or all at once into memory)
|
||||
* Seek to particular file in archive
|
||||
* Close
|
||||
|
||||
The extractor can choose whether to open a file path immediately, or
|
||||
defer until the first stat() call. When extracting data, it can
|
||||
implement one or both of normal read and "give me a pointer to the data
|
||||
already in memory". If it only implements one, File_Extractor will
|
||||
implement the other in terms of it.
|
||||
|
||||
|
||||
7-ZIP
|
||||
-----
|
||||
A fairly simple wrapper over a slightly-modified LZMA library.
|
||||
Unfortunately you probably won't be able to drop a later version of the
|
||||
LZMA library sources in and recompile, as the interface and file
|
||||
arrangement tends to change with every release. The main change I've
|
||||
made is to declare functions extern "C" in headers, so C++ code can call
|
||||
them.
|
||||
|
||||
|
||||
ZIP
|
||||
---
|
||||
A complete implementation I wrote. Has nifty optimization that makes all
|
||||
disk reads begin and end on a multiple of 4K. Also minimizes number of
|
||||
accesses when initially reading catalog, and extracting file data.
|
||||
Correctly handles empty zip archives, unlike the popular unzip library
|
||||
which reports it as a bad archive.
|
||||
|
||||
|
||||
RAR
|
||||
---
|
||||
Wrapper over heavily-modified UnRAR extraction library based on the
|
||||
official UnRAR sources. The library is available separately with
|
||||
documentation and demos, in case you want to use it without the
|
||||
File_Extractor front-end (see unrar/changes.txt for more).
|
||||
|
||||
|
||||
GZIP
|
||||
----
|
||||
Uses zlib's built-in parsing. Also works with non-gzipped files, based
|
||||
on absence of two-byte Gzip header. Defers opening of file until
|
||||
fex_stat(), speeding mere scanning of filenames. Gzip_Reader and
|
||||
Zlib_Reader further divide the implementation into more manageable and
|
||||
reusable components.
|
||||
|
||||
|
||||
Binary
|
||||
------
|
||||
Just a minimal wrapper over C-style FILE.
|
||||
|
||||
--
|
||||
Shay Green <gblargg@gmail.com>
|
||||
File_Extractor library internals
|
||||
--------------------------------
|
||||
This describes the implementation and design.
|
||||
|
||||
Contents
|
||||
--------
|
||||
* Framework
|
||||
* Archive abstraction
|
||||
* 7-ZIP
|
||||
* ZIP
|
||||
* RAR
|
||||
* GZIP
|
||||
* Binary
|
||||
|
||||
|
||||
Framework
|
||||
---------
|
||||
This library is essentially:
|
||||
|
||||
* Several archive readers
|
||||
* Wrappers to provide common interface
|
||||
* File type detection
|
||||
|
||||
The File_Extractor base class implements the common aspects of the
|
||||
interface and filters out invalid calls. It also provides default
|
||||
implementations for some operations. Each derived *_Extractor class then
|
||||
wraps the particular library.
|
||||
|
||||
Then fex.h provides a stable, C-compatible wrapper over File_Extractor,
|
||||
and does file type identification.
|
||||
|
||||
|
||||
Archive abstraction
|
||||
-------------------
|
||||
An extractor is abstracted to these fundamental operations:
|
||||
|
||||
* Open (either from path or custom reader)
|
||||
* Iterate over each file
|
||||
* Extract file's data (either gradually, or all at once into memory)
|
||||
* Seek to particular file in archive
|
||||
* Close
|
||||
|
||||
The extractor can choose whether to open a file path immediately, or
|
||||
defer until the first stat() call. When extracting data, it can
|
||||
implement one or both of normal read and "give me a pointer to the data
|
||||
already in memory". If it only implements one, File_Extractor will
|
||||
implement the other in terms of it.
|
||||
|
||||
|
||||
7-ZIP
|
||||
-----
|
||||
A fairly simple wrapper over a slightly-modified LZMA library.
|
||||
Unfortunately you probably won't be able to drop a later version of the
|
||||
LZMA library sources in and recompile, as the interface and file
|
||||
arrangement tends to change with every release. The main change I've
|
||||
made is to declare functions extern "C" in headers, so C++ code can call
|
||||
them.
|
||||
|
||||
|
||||
ZIP
|
||||
---
|
||||
A complete implementation I wrote. Has nifty optimization that makes all
|
||||
disk reads begin and end on a multiple of 4K. Also minimizes number of
|
||||
accesses when initially reading catalog, and extracting file data.
|
||||
Correctly handles empty zip archives, unlike the popular unzip library
|
||||
which reports it as a bad archive.
|
||||
|
||||
|
||||
RAR
|
||||
---
|
||||
Wrapper over heavily-modified UnRAR extraction library based on the
|
||||
official UnRAR sources. The library is available separately with
|
||||
documentation and demos, in case you want to use it without the
|
||||
File_Extractor front-end (see unrar/changes.txt for more).
|
||||
|
||||
|
||||
GZIP
|
||||
----
|
||||
Uses zlib's built-in parsing. Also works with non-gzipped files, based
|
||||
on absence of two-byte Gzip header. Defers opening of file until
|
||||
fex_stat(), speeding mere scanning of filenames. Gzip_Reader and
|
||||
Zlib_Reader further divide the implementation into more manageable and
|
||||
reusable components.
|
||||
|
||||
|
||||
Binary
|
||||
------
|
||||
Just a minimal wrapper over C-style FILE.
|
||||
|
||||
--
|
||||
Shay Green <gblargg@gmail.com>
|
||||
|
|
1008
fex/license.txt
1008
fex/license.txt
File diff suppressed because it is too large
Load Diff
118
fex/readme.txt
118
fex/readme.txt
|
@ -1,59 +1,59 @@
|
|||
File_Extractor 1.0.0
|
||||
--------------------
|
||||
File_Extractor is a modular archive scanning and extraction library that
|
||||
supports several popular compressed file formats. It gives a common
|
||||
interface to the supported formats, allowing one version of user code.
|
||||
|
||||
Features:
|
||||
* Simple C interface.
|
||||
* Supports ZIP, GZIP, 7-Zip (7Z), and RAR[1] archive formats.
|
||||
* Non-archive files act like archive of that one file, simplifying code.
|
||||
* Modular design allows removal of support for unneeded archive formats.
|
||||
* Optionally supports wide-character paths on Windows.
|
||||
* Archive file type identification can be customized
|
||||
|
||||
[1] RAR support must be enabled before use, due to its special
|
||||
licensing.
|
||||
|
||||
Author : Shay Green <gblargg@gmail.com>
|
||||
Website : http://code.google.com/p/file-extractor/
|
||||
License : GNU LGPL 2.1 or later for all except unrar
|
||||
Language: C interface, C++ implementation
|
||||
|
||||
|
||||
Getting Started
|
||||
---------------
|
||||
Build the demo by typing "make" at the command-line. If that doesn't
|
||||
work, manually build a program from demo.c and all *.c and *.cpp files
|
||||
in fex/, 7z_C/, and zlib/. Run demo with test.zip in the same directory.
|
||||
|
||||
To enable RAR archive support, edit fex/blargg_config.h.
|
||||
|
||||
See fex.h for reference and fex.txt for documentation.
|
||||
|
||||
|
||||
Files
|
||||
-----
|
||||
fex.txt Manual
|
||||
license.txt GNU LGPL 2.1 license
|
||||
|
||||
makefile Builds libfex.a and demo
|
||||
|
||||
demo.c Basic usage
|
||||
demo_read.c Uses fex_read() to extract data
|
||||
demo_rewind.c Uses fex_rewind() to re-scan archive
|
||||
demo_seek.c Uses fex_seek_arc() to go back to files
|
||||
demo_directory.c Recursively scans directory for archives
|
||||
demo.zip Test archive used by demos
|
||||
|
||||
fex/
|
||||
blargg_config.h Configuration (modify as needed)
|
||||
fex.h C interface (also usable from C++)
|
||||
(all other files) Library sources
|
||||
|
||||
zlib/ Zip/Gzip (can use your system's instead)
|
||||
7z_C/ 7-Zip
|
||||
unrar/ RAR
|
||||
|
||||
--
|
||||
Shay Green <gblargg@gmail.com>
|
||||
File_Extractor 1.0.0
|
||||
--------------------
|
||||
File_Extractor is a modular archive scanning and extraction library that
|
||||
supports several popular compressed file formats. It gives a common
|
||||
interface to the supported formats, allowing one version of user code.
|
||||
|
||||
Features:
|
||||
* Simple C interface.
|
||||
* Supports ZIP, GZIP, 7-Zip (7Z), and RAR[1] archive formats.
|
||||
* Non-archive files act like archive of that one file, simplifying code.
|
||||
* Modular design allows removal of support for unneeded archive formats.
|
||||
* Optionally supports wide-character paths on Windows.
|
||||
* Archive file type identification can be customized
|
||||
|
||||
[1] RAR support must be enabled before use, due to its special
|
||||
licensing.
|
||||
|
||||
Author : Shay Green <gblargg@gmail.com>
|
||||
Website : http://code.google.com/p/file-extractor/
|
||||
License : GNU LGPL 2.1 or later for all except unrar
|
||||
Language: C interface, C++ implementation
|
||||
|
||||
|
||||
Getting Started
|
||||
---------------
|
||||
Build the demo by typing "make" at the command-line. If that doesn't
|
||||
work, manually build a program from demo.c and all *.c and *.cpp files
|
||||
in fex/, 7z_C/, and zlib/. Run demo with test.zip in the same directory.
|
||||
|
||||
To enable RAR archive support, edit fex/blargg_config.h.
|
||||
|
||||
See fex.h for reference and fex.txt for documentation.
|
||||
|
||||
|
||||
Files
|
||||
-----
|
||||
fex.txt Manual
|
||||
license.txt GNU LGPL 2.1 license
|
||||
|
||||
makefile Builds libfex.a and demo
|
||||
|
||||
demo.c Basic usage
|
||||
demo_read.c Uses fex_read() to extract data
|
||||
demo_rewind.c Uses fex_rewind() to re-scan archive
|
||||
demo_seek.c Uses fex_seek_arc() to go back to files
|
||||
demo_directory.c Recursively scans directory for archives
|
||||
demo.zip Test archive used by demos
|
||||
|
||||
fex/
|
||||
blargg_config.h Configuration (modify as needed)
|
||||
fex.h C interface (also usable from C++)
|
||||
(all other files) Library sources
|
||||
|
||||
zlib/ Zip/Gzip (can use your system's instead)
|
||||
7z_C/ 7-Zip
|
||||
unrar/ RAR
|
||||
|
||||
--
|
||||
Shay Green <gblargg@gmail.com>
|
||||
|
|
Loading…
Reference in New Issue