mirror of
https://github.com/joel16/VitaShell.git
synced 2024-11-26 21:30:45 +00:00
Dropped fex and now using minizip. Updated to latest vitasdk.
This commit is contained in:
parent
163f34db05
commit
451ee91c1e
10
Makefile
10
Makefile
@ -2,12 +2,7 @@ TITLE_ID = VITASHELL
|
||||
TARGET = VitaShell
|
||||
OBJS = main.o init.o io_process.o package_installer.o archive.o photo.o file.o text.o hex.o \
|
||||
uncommon_dialog.o message_dialog.o ime_dialog.o language.o utils.o sha1.o \
|
||||
audioplayer.o
|
||||
|
||||
FEXDIRS = fex fex/7z_C fex/fex fex/unrar
|
||||
FEXCSRCS = $(foreach dir, $(FEXDIRS), $(wildcard $(dir)/*.c))
|
||||
FEXCPPSRCS = $(foreach dir, $(FEXDIRS), $(wildcard $(dir)/*.cpp))
|
||||
OBJS += $(FEXCSRCS:.c=.o) $(FEXCPPSRCS:.cpp=.o)
|
||||
audioplayer.o minizip/unzip.o minizip/ioapi.o
|
||||
|
||||
RESOURCES_PNG = resources/ftp.png resources/battery.png resources/battery_bar_green.png resources/battery_bar_red.png \
|
||||
resources/headphone.png resources/audio_previous.png resources/audio_pause.png resources/audio_play.png \
|
||||
@ -34,8 +29,7 @@ endif
|
||||
PREFIX = arm-vita-eabi
|
||||
CC = $(PREFIX)-gcc
|
||||
CXX = $(PREFIX)-g++
|
||||
CFLAGS += -Wl,-q -Wall -O3 -Wno-unused-variable -Wno-unused-but-set-variable \
|
||||
$(foreach dir, $(FEXDIRS), -I$(dir))
|
||||
CFLAGS = -Wl,-q -Wall -O3 -Wno-unused-variable -Wno-unused-but-set-variable
|
||||
CXXFLAGS = $(CFLAGS) -std=c++11 -fno-rtti -fno-exceptions
|
||||
ASFLAGS = $(CFLAGS)
|
||||
|
||||
|
@ -14,6 +14,11 @@ This homebrew was an entry of the Revitalize PS Vita homebrew competition and wo
|
||||
* wololo for the Revitalize contest
|
||||
* Everybody who contributed on vitasdk
|
||||
|
||||
### Changelog 0.X ###
|
||||
- Added support for >2GB zip archives (dropped support for 7zip and rar though).
|
||||
- Added cache system for zipfs (faster file reading browsing in zip archives).
|
||||
- Fixed 12h time conversion.
|
||||
|
||||
### Changelog 0.7 ###
|
||||
- Ported to HENkaku (support for renaming/creating folders and for analog stick for fast movement).
|
||||
- Added custom dialogs.
|
||||
|
304
archive.c
304
archive.c
@ -21,84 +21,90 @@
|
||||
#include "file.h"
|
||||
#include "utils.h"
|
||||
|
||||
static int path_length = 0;
|
||||
#include "minizip/unzip.h"
|
||||
|
||||
static fex_t *fex = NULL;
|
||||
static fex_pos_t archive_file_pos = 0;
|
||||
static int archive_file_size = 0;
|
||||
static int archive_path_start = 0;
|
||||
static unzFile uf = NULL;
|
||||
static FileList archive_list;
|
||||
|
||||
int fileListGetArchiveEntries(FileList *list, char *path) {
|
||||
if (!fex)
|
||||
int res;
|
||||
|
||||
if (!uf)
|
||||
return -1;
|
||||
|
||||
FileListEntry *entry = malloc(sizeof(FileListEntry));
|
||||
strcpy(entry->name, DIR_UP);
|
||||
entry->name_length = strlen(entry->name);
|
||||
entry->is_folder = 1;
|
||||
entry->type = FILE_TYPE_UNKNOWN;
|
||||
fileListAddEntry(list, entry, SORT_BY_NAME_AND_FOLDER);
|
||||
|
||||
char *archive_path = path + path_length;
|
||||
int archive_path_length = strlen(archive_path);
|
||||
char *archive_path = path + archive_path_start;
|
||||
int name_length = strlen(archive_path);
|
||||
|
||||
fex_rewind(fex);
|
||||
FileListEntry *archive_entry = archive_list.head;
|
||||
|
||||
int count = 0;
|
||||
|
||||
while (!fex_done(fex)) {
|
||||
fex_stat(fex);
|
||||
|
||||
const char *name = fex_name(fex);
|
||||
int size = fex_size(fex);
|
||||
|
||||
if (strncmp(name, archive_path, archive_path_length) == 0) { // Needs a / at end
|
||||
char *p = strchr(name + archive_path_length, '/');
|
||||
int i;
|
||||
for (i = 0; i < archive_list.length; i++) {
|
||||
if (archive_entry->name_length >= name_length && strncmp(archive_entry->name, archive_path, name_length) == 0) { // Needs a / at end
|
||||
char *p = strchr(archive_entry->name + name_length, '/'); // it's a sub-directory if it has got a slash
|
||||
|
||||
if (p)
|
||||
*p = '\0';
|
||||
|
||||
FileListEntry *entry = malloc(sizeof(FileListEntry));
|
||||
|
||||
strcpy(entry->name, name + archive_path_length);
|
||||
|
||||
char name[MAX_PATH_LENGTH];
|
||||
strcpy(name, archive_entry->name + name_length);
|
||||
if (p) {
|
||||
addEndSlash(entry->name);
|
||||
entry->is_folder = 1;
|
||||
entry->type = FILE_TYPE_UNKNOWN;
|
||||
list->folders++;
|
||||
} else {
|
||||
entry->is_folder = 0;
|
||||
entry->type = getFileType(entry->name);
|
||||
list->files++;
|
||||
addEndSlash(name);
|
||||
}
|
||||
|
||||
entry->size = size;
|
||||
if (strlen(name) > 0 && !fileListFindEntry(list, name)) {
|
||||
FileListEntry *entry = malloc(sizeof(FileListEntry));
|
||||
|
||||
sceRtcSetDosTime(&entry->time, fex_dos_date(fex));
|
||||
strcpy(entry->name, archive_entry->name + name_length);
|
||||
|
||||
if (p) {
|
||||
addEndSlash(entry->name);
|
||||
entry->is_folder = 1;
|
||||
entry->type = FILE_TYPE_UNKNOWN;
|
||||
list->folders++;
|
||||
} else {
|
||||
entry->is_folder = 0;
|
||||
entry->type = getFileType(entry->name);
|
||||
list->files++;
|
||||
}
|
||||
|
||||
entry->name_length = strlen(entry->name);
|
||||
entry->size = archive_entry->size;
|
||||
|
||||
memcpy(&entry->time, &archive_entry->time, sizeof(SceDateTime));
|
||||
|
||||
if (!fileListFindEntry(list, entry->name)) {
|
||||
fileListAddEntry(list, entry, SORT_BY_NAME_AND_FOLDER);
|
||||
count++;
|
||||
}
|
||||
|
||||
if (p)
|
||||
*p = '/';
|
||||
}
|
||||
|
||||
fex_next(fex);
|
||||
// Next
|
||||
archive_entry = archive_entry->next;
|
||||
}
|
||||
|
||||
return count;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getArchivePathInfo(char *path, uint32_t *size, uint32_t *folders, uint32_t *files) {
|
||||
if (!fex)
|
||||
if (!uf)
|
||||
return -1;
|
||||
|
||||
FileList list;
|
||||
memset(&list, 0, sizeof(FileList));
|
||||
int count = fileListGetArchiveEntries(&list, path);
|
||||
SceIoStat stat;
|
||||
memset(&stat, 0, sizeof(SceIoStat));
|
||||
if (archiveFileGetstat(path, &stat) < 0) {
|
||||
FileList list;
|
||||
memset(&list, 0, sizeof(FileList));
|
||||
fileListGetArchiveEntries(&list, path);
|
||||
|
||||
if (count > 0) {
|
||||
FileListEntry *entry = list.head->next; // Ignore ..
|
||||
|
||||
int i;
|
||||
@ -106,8 +112,6 @@ int getArchivePathInfo(char *path, uint32_t *size, uint32_t *folders, uint32_t *
|
||||
char *new_path = malloc(strlen(path) + strlen(entry->name) + 2);
|
||||
snprintf(new_path, MAX_PATH_LENGTH, "%s%s", path, entry->name);
|
||||
|
||||
addEndSlash(new_path);
|
||||
|
||||
getArchivePathInfo(new_path, size, folders, files);
|
||||
|
||||
free(new_path);
|
||||
@ -117,36 +121,30 @@ int getArchivePathInfo(char *path, uint32_t *size, uint32_t *folders, uint32_t *
|
||||
|
||||
if (folders)
|
||||
(*folders)++;
|
||||
|
||||
fileListEmpty(&list);
|
||||
} else {
|
||||
removeEndSlash(path);
|
||||
|
||||
SceUID fd = archiveFileOpen(path);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
if (size)
|
||||
(*size) += archiveFileGetSize(fd);
|
||||
(*size) += stat.st_size;
|
||||
|
||||
if (files)
|
||||
(*files)++;
|
||||
|
||||
archiveFileClose(fd);
|
||||
}
|
||||
|
||||
fileListEmpty(&list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int extractArchivePath(char *src, char *dst, uint32_t *value, uint32_t max, void (* SetProgress)(uint32_t value, uint32_t max), int (* cancelHandler)()) {
|
||||
if (!fex)
|
||||
if (!uf)
|
||||
return -1;
|
||||
|
||||
FileList list;
|
||||
memset(&list, 0, sizeof(FileList));
|
||||
int count = fileListGetArchiveEntries(&list, src);
|
||||
SceIoStat stat;
|
||||
memset(&stat, 0, sizeof(SceIoStat));
|
||||
if (archiveFileGetstat(src, &stat) < 0) {
|
||||
FileList list;
|
||||
memset(&list, 0, sizeof(FileList));
|
||||
fileListGetArchiveEntries(&list, src);
|
||||
|
||||
if (count > 0) {
|
||||
int ret = sceIoMkdir(dst, 0777);
|
||||
if (ret < 0 && ret != SCE_ERROR_ERRNO_EEXIST) {
|
||||
fileListEmpty(&list);
|
||||
@ -174,14 +172,11 @@ int extractArchivePath(char *src, char *dst, uint32_t *value, uint32_t max, void
|
||||
char *dst_path = malloc(strlen(dst) + strlen(entry->name) + 2);
|
||||
snprintf(dst_path, MAX_PATH_LENGTH, "%s%s", dst, entry->name);
|
||||
|
||||
addEndSlash(src_path);
|
||||
addEndSlash(dst_path);
|
||||
|
||||
int ret = extractArchivePath(src_path, dst_path, value, max, SetProgress, cancelHandler);
|
||||
|
||||
free(dst_path);
|
||||
free(src_path);
|
||||
|
||||
|
||||
if (ret <= 0) {
|
||||
fileListEmpty(&list);
|
||||
return ret;
|
||||
@ -189,20 +184,16 @@ int extractArchivePath(char *src, char *dst, uint32_t *value, uint32_t max, void
|
||||
|
||||
entry = entry->next;
|
||||
}
|
||||
|
||||
fileListEmpty(&list);
|
||||
} else {
|
||||
removeEndSlash(src);
|
||||
removeEndSlash(dst);
|
||||
|
||||
SceUID fdsrc = archiveFileOpen(src);
|
||||
if (fdsrc < 0) {
|
||||
fileListEmpty(&list);
|
||||
SceUID fdsrc = archiveFileOpen(src, SCE_O_RDONLY, 0);
|
||||
if (fdsrc < 0)
|
||||
return fdsrc;
|
||||
}
|
||||
|
||||
SceUID fddst = sceIoOpen(dst, SCE_O_WRONLY | SCE_O_CREAT | SCE_O_TRUNC, 0777);
|
||||
if (fddst < 0) {
|
||||
archiveFileClose(fdsrc);
|
||||
fileListEmpty(&list);
|
||||
return fddst;
|
||||
}
|
||||
|
||||
@ -217,8 +208,6 @@ int extractArchivePath(char *src, char *dst, uint32_t *value, uint32_t max, void
|
||||
sceIoClose(fddst);
|
||||
archiveFileClose(fdsrc);
|
||||
|
||||
fileListEmpty(&list);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -227,15 +216,13 @@ int extractArchivePath(char *src, char *dst, uint32_t *value, uint32_t max, void
|
||||
|
||||
if (SetProgress)
|
||||
SetProgress(value ? *value : 0, max);
|
||||
|
||||
|
||||
if (cancelHandler && cancelHandler()) {
|
||||
free(buf);
|
||||
|
||||
sceIoClose(fddst);
|
||||
archiveFileClose(fdsrc);
|
||||
|
||||
fileListEmpty(&list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -246,99 +233,88 @@ int extractArchivePath(char *src, char *dst, uint32_t *value, uint32_t max, void
|
||||
archiveFileClose(fdsrc);
|
||||
}
|
||||
|
||||
fileListEmpty(&list);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int archiveFileOpen(char *path) {
|
||||
if (!fex)
|
||||
int archiveFileGetstat(const char *file, SceIoStat *stat) {
|
||||
if (!uf)
|
||||
return -1;
|
||||
|
||||
char *archive_path = path + path_length;
|
||||
const char *archive_path = file + archive_path_start;
|
||||
int name_length = strlen(archive_path);
|
||||
|
||||
if (!fex_done(fex)) {
|
||||
if (strcmp(fex_name(fex), archive_path) == 0) {
|
||||
archive_file_pos = fex_tell_arc(fex);
|
||||
archive_file_size = archiveFileGetSize(ARCHIVE_FD);
|
||||
return ARCHIVE_FD;
|
||||
}
|
||||
}
|
||||
FileListEntry *archive_entry = archive_list.head;
|
||||
|
||||
fex_rewind(fex);
|
||||
int i;
|
||||
for (i = 0; i < archive_list.length; i++) {
|
||||
if (archive_entry->name_length == name_length && strcmp(archive_entry->name, archive_path) == 0) {
|
||||
if (stat) {
|
||||
// TODO: more stat
|
||||
stat->st_size = archive_entry->size;
|
||||
}
|
||||
|
||||
while (!fex_done(fex)) {
|
||||
if (strcmp(fex_name(fex), archive_path) == 0) {
|
||||
archive_file_pos = fex_tell_arc(fex);
|
||||
archive_file_size = archiveFileGetSize(ARCHIVE_FD);
|
||||
return ARCHIVE_FD;
|
||||
return 0;
|
||||
}
|
||||
|
||||
fex_next(fex);
|
||||
// Next
|
||||
archive_entry = archive_entry->next;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int archiveFileGetSize(SceUID fd) {
|
||||
if (!fex || fd != ARCHIVE_FD)
|
||||
int archiveFileOpen(const char *file, int flags, SceMode mode) {
|
||||
int res;
|
||||
|
||||
if (!uf)
|
||||
return -1;
|
||||
|
||||
fex_stat(fex);
|
||||
return fex_size(fex);
|
||||
}
|
||||
const char *archive_path = file + archive_path_start;
|
||||
int name_length = strlen(archive_path);
|
||||
|
||||
int archiveFileSeek(SceUID fd, int n) {
|
||||
if (!fex || fd != ARCHIVE_FD)
|
||||
return -1;
|
||||
FileListEntry *archive_entry = archive_list.head;
|
||||
|
||||
archiveFileClose(fd);
|
||||
int i;
|
||||
for (i = 0; i < archive_list.length; i++) {
|
||||
if (archive_entry->name_length == name_length && strcmp(archive_entry->name, archive_path) == 0) {
|
||||
// Set pos
|
||||
unzGoToFilePos64(uf, (unz64_file_pos *)&archive_entry->reserved);
|
||||
|
||||
void *buf = malloc(TRANSFER_SIZE);
|
||||
// File info
|
||||
char name[MAX_PATH_LENGTH];
|
||||
unz_file_info64 file_info;
|
||||
unzGetCurrentFileInfo64(uf, &file_info, name, MAX_PATH_LENGTH, NULL, 0, NULL, 0);
|
||||
|
||||
res = unzOpenCurrentFile(uf);
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
int remain = 0, seek = 0;
|
||||
while ((remain = n - seek) > 0) {
|
||||
remain = MIN(remain, TRANSFER_SIZE);
|
||||
|
||||
fex_err_t res = fex_read(fex, buf, remain);
|
||||
if (res != 0) {
|
||||
free(buf);
|
||||
return -fex_err_code(res);
|
||||
return ARCHIVE_FD;
|
||||
}
|
||||
|
||||
seek += remain;
|
||||
// Next
|
||||
archive_entry = archive_entry->next;
|
||||
}
|
||||
|
||||
free(buf);
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int archiveFileRead(SceUID fd, void *data, int n) {
|
||||
if (!fex || fd != ARCHIVE_FD)
|
||||
int archiveFileRead(SceUID fd, void *data, SceSize size) {
|
||||
if (!uf || fd != ARCHIVE_FD)
|
||||
return -1;
|
||||
|
||||
int previous_pos = fex_tell(fex);
|
||||
|
||||
int remain = MIN(archive_file_size - previous_pos, n);
|
||||
|
||||
fex_err_t res = fex_read(fex, data, remain);
|
||||
if (res != NULL)
|
||||
return -fex_err_code(res);
|
||||
|
||||
return remain;
|
||||
return unzReadCurrentFile(uf, data, size);
|
||||
}
|
||||
|
||||
int archiveFileClose(SceUID fd) {
|
||||
if (!fex || fd != ARCHIVE_FD)
|
||||
if (!uf || fd != ARCHIVE_FD)
|
||||
return -1;
|
||||
|
||||
fex_seek_arc(fex, archive_file_pos);
|
||||
|
||||
return 0;
|
||||
return unzCloseCurrentFile(uf);
|
||||
}
|
||||
|
||||
int ReadArchiveFile(char *file, void *buf, int size) {
|
||||
SceUID fd = archiveFileOpen(file);
|
||||
SceUID fd = archiveFileOpen(file, SCE_O_RDONLY, 0);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
@ -347,22 +323,64 @@ int ReadArchiveFile(char *file, void *buf, int size) {
|
||||
return read;
|
||||
}
|
||||
|
||||
void archiveClose() {
|
||||
if (fex) {
|
||||
fex_close(fex);
|
||||
fex = NULL;
|
||||
}
|
||||
int archiveClose() {
|
||||
if (!uf)
|
||||
return -1;
|
||||
|
||||
fileListEmpty(&archive_list);
|
||||
|
||||
unzClose(uf);
|
||||
uf = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO: improve this, it's slow...
|
||||
int archiveOpen(char *file) {
|
||||
path_length = strlen(file) + 1;
|
||||
int res;
|
||||
|
||||
if (fex)
|
||||
archiveClose();
|
||||
// Start position of the archive path
|
||||
archive_path_start = strlen(file) + 1;
|
||||
|
||||
fex_err_t res = fex_open(&fex, file);
|
||||
if (res != NULL)
|
||||
return -fex_err_code(res);
|
||||
// Close previous zip file first
|
||||
if (uf)
|
||||
unzClose(uf);
|
||||
|
||||
// Open zip file
|
||||
uf = unzOpen64(file);
|
||||
if (!uf)
|
||||
return -1;
|
||||
|
||||
// Go to first entry
|
||||
res = unzGoToFirstFile(uf);
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
// Clear archive list
|
||||
memset(&archive_list, 0, sizeof(FileList));
|
||||
|
||||
// Go through all files
|
||||
do {
|
||||
FileListEntry *entry = malloc(sizeof(FileListEntry));
|
||||
|
||||
// File info
|
||||
unz_file_info64 file_info;
|
||||
unzGetCurrentFileInfo64(uf, &file_info, entry->name, MAX_PATH_LENGTH, NULL, 0, NULL, 0);
|
||||
|
||||
entry->is_folder = 0;
|
||||
entry->name_length = file_info.size_filename;
|
||||
entry->size = file_info.uncompressed_size;
|
||||
sceRtcSetDosTime(&entry->time, file_info.dosDate);
|
||||
|
||||
// Get pos
|
||||
unzGetFilePos64(uf, (unz64_file_pos *)&entry->reserved);
|
||||
|
||||
// Add entry
|
||||
fileListAddEntry(&archive_list, entry, SORT_BY_NAME_AND_FOLDER);
|
||||
|
||||
// Next
|
||||
res = unzGoToNextFile(uf);
|
||||
} while (res >= 0);
|
||||
|
||||
return 0;
|
||||
}
|
@ -28,15 +28,14 @@ int fileListGetArchiveEntries(FileList *list, char *path);
|
||||
int getArchivePathInfo(char *path, uint32_t *size, uint32_t *folders, uint32_t *files);
|
||||
int extractArchivePath(char *src, char *dst, uint32_t *value, uint32_t max, void (* SetProgress)(uint32_t value, uint32_t max), int (* cancelHandler)());
|
||||
|
||||
int archiveFileOpen(char *path);
|
||||
int archiveFileGetSize(SceUID fd);
|
||||
int archiveFileSeek(SceUID fd, int n);
|
||||
int archiveFileRead(SceUID fd, void *data, int n);
|
||||
int archiveFileGetstat(const char *file, SceIoStat *stat);
|
||||
int archiveFileOpen(const char *file, int flags, SceMode mode);
|
||||
int archiveFileRead(SceUID fd, void *data, SceSize size);
|
||||
int archiveFileClose(SceUID fd);
|
||||
|
||||
int ReadArchiveFile(char *file, void *buf, int size);
|
||||
|
||||
void archiveClose();
|
||||
int archiveClose();
|
||||
int archiveOpen(char *file);
|
||||
|
||||
#endif
|
@ -1,77 +0,0 @@
|
||||
/* 7zAlloc.c -- Allocation functions
|
||||
2008-10-04 : Igor Pavlov : Public domain */
|
||||
|
||||
#include <stdlib.h>
|
||||
#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,23 +0,0 @@
|
||||
/* 7zAlloc.h -- Allocation functions
|
||||
2008-10-04 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __7Z_ALLOC_H
|
||||
#define __7Z_ALLOC_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,36 +0,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,31 +0,0 @@
|
||||
/* 7zBuf.h -- Byte Buffer
|
||||
2008-10-04 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __7Z_BUF_H
|
||||
#define __7Z_BUF_H
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Byte *data;
|
||||
size_t size;
|
||||
} CBuf;
|
||||
|
||||
void Buf_Init(CBuf *p);
|
||||
int Buf_Create(CBuf *p, size_t size, ISzAlloc *alloc);
|
||||
void Buf_Free(CBuf *p, ISzAlloc *alloc);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Byte *data;
|
||||
size_t size;
|
||||
size_t pos;
|
||||
} CDynBuf;
|
||||
|
||||
void DynBuf_Construct(CDynBuf *p);
|
||||
void DynBuf_SeekToBeg(CDynBuf *p);
|
||||
int DynBuf_Write(CDynBuf *p, const Byte *buf, size_t size, ISzAlloc *alloc);
|
||||
void DynBuf_Free(CDynBuf *p, ISzAlloc *alloc);
|
||||
|
||||
#endif
|
194
fex/7z_C/7zC.txt
194
fex/7z_C/7zC.txt
@ -1,194 +0,0 @@
|
||||
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
|
@ -1,35 +0,0 @@
|
||||
/* 7zCrc.c -- CRC32 calculation
|
||||
2008-08-05
|
||||
Igor Pavlov
|
||||
Public domain */
|
||||
|
||||
#include "7zCrc.h"
|
||||
|
||||
#define kCrcPoly 0xEDB88320
|
||||
UInt32 g_CrcTable[256];
|
||||
|
||||
void MY_FAST_CALL CrcGenerateTable(void)
|
||||
{
|
||||
UInt32 i;
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
UInt32 r = i;
|
||||
int j;
|
||||
for (j = 0; j < 8; j++)
|
||||
r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1));
|
||||
g_CrcTable[i] = r;
|
||||
}
|
||||
}
|
||||
|
||||
UInt32 MY_FAST_CALL CrcUpdate(UInt32 v, const void *data, size_t size)
|
||||
{
|
||||
const Byte *p = (const Byte *)data;
|
||||
for (; size > 0 ; size--, p++)
|
||||
v = CRC_UPDATE_BYTE(v, *p);
|
||||
return v;
|
||||
}
|
||||
|
||||
UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size)
|
||||
{
|
||||
return CrcUpdate(CRC_INIT_VAL, data, size) ^ 0xFFFFFFFF;
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
/* 7zCrc.h -- CRC32 calculation
|
||||
2008-03-13
|
||||
Igor Pavlov
|
||||
Public domain */
|
||||
|
||||
#ifndef __7Z_CRC_H
|
||||
#define __7Z_CRC_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern UInt32 g_CrcTable[];
|
||||
|
||||
void MY_FAST_CALL CrcGenerateTable(void);
|
||||
|
||||
#define CRC_INIT_VAL 0xFFFFFFFF
|
||||
#define CRC_GET_DIGEST(crc) ((crc) ^ 0xFFFFFFFF)
|
||||
#define CRC_UPDATE_BYTE(crc, b) (g_CrcTable[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
|
||||
|
||||
UInt32 MY_FAST_CALL CrcUpdate(UInt32 crc, const void *data, size_t size);
|
||||
UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,257 +0,0 @@
|
||||
/* 7zDecode.c -- Decoding from 7z folder
|
||||
2008-11-23 : Igor Pavlov : Public domain */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "Bcj2.h"
|
||||
#include "Bra.h"
|
||||
#include "LzmaDec.h"
|
||||
#include "7zDecode.h"
|
||||
|
||||
#define k_Copy 0
|
||||
#define k_LZMA 0x30101
|
||||
#define k_BCJ 0x03030103
|
||||
#define k_BCJ2 0x0303011B
|
||||
|
||||
static SRes SzDecodeLzma(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inStream,
|
||||
Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain)
|
||||
{
|
||||
CLzmaDec state;
|
||||
SRes res = SZ_OK;
|
||||
|
||||
LzmaDec_Construct(&state);
|
||||
RINOK(LzmaDec_AllocateProbs(&state, coder->Props.data, (unsigned)coder->Props.size, allocMain));
|
||||
state.dic = outBuffer;
|
||||
state.dicBufSize = outSize;
|
||||
LzmaDec_Init(&state);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
Byte *inBuf = NULL;
|
||||
size_t lookahead = (1 << 18);
|
||||
if (lookahead > inSize)
|
||||
lookahead = (size_t)inSize;
|
||||
res = inStream->Look((void *)inStream, (void **)&inBuf, &lookahead);
|
||||
if (res != SZ_OK)
|
||||
break;
|
||||
|
||||
{
|
||||
SizeT inProcessed = (SizeT)lookahead, dicPos = state.dicPos;
|
||||
ELzmaStatus status;
|
||||
res = LzmaDec_DecodeToDic(&state, outSize, inBuf, &inProcessed, LZMA_FINISH_END, &status);
|
||||
lookahead -= inProcessed;
|
||||
inSize -= inProcessed;
|
||||
if (res != SZ_OK)
|
||||
break;
|
||||
if (state.dicPos == state.dicBufSize || (inProcessed == 0 && dicPos == state.dicPos))
|
||||
{
|
||||
if (state.dicBufSize != outSize || lookahead != 0 ||
|
||||
(status != LZMA_STATUS_FINISHED_WITH_MARK &&
|
||||
status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK))
|
||||
res = SZ_ERROR_DATA;
|
||||
break;
|
||||
}
|
||||
res = inStream->Skip((void *)inStream, inProcessed);
|
||||
if (res != SZ_OK)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LzmaDec_FreeProbs(&state, allocMain);
|
||||
return res;
|
||||
}
|
||||
|
||||
static SRes SzDecodeCopy(UInt64 inSize, ILookInStream *inStream, Byte *outBuffer)
|
||||
{
|
||||
while (inSize > 0)
|
||||
{
|
||||
void *inBuf;
|
||||
size_t curSize = (1 << 18);
|
||||
if (curSize > inSize)
|
||||
curSize = (size_t)inSize;
|
||||
RINOK(inStream->Look((void *)inStream, (void **)&inBuf, &curSize));
|
||||
if (curSize == 0)
|
||||
return SZ_ERROR_INPUT_EOF;
|
||||
memcpy(outBuffer, inBuf, curSize);
|
||||
outBuffer += curSize;
|
||||
inSize -= curSize;
|
||||
RINOK(inStream->Skip((void *)inStream, curSize));
|
||||
}
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
#define IS_UNSUPPORTED_METHOD(m) ((m) != k_Copy && (m) != k_LZMA)
|
||||
#define IS_UNSUPPORTED_CODER(c) (IS_UNSUPPORTED_METHOD(c.MethodID) || c.NumInStreams != 1 || c.NumOutStreams != 1)
|
||||
#define IS_NO_BCJ(c) (c.MethodID != k_BCJ || c.NumInStreams != 1 || c.NumOutStreams != 1)
|
||||
#define IS_NO_BCJ2(c) (c.MethodID != k_BCJ2 || c.NumInStreams != 4 || c.NumOutStreams != 1)
|
||||
|
||||
static
|
||||
SRes CheckSupportedFolder(const CSzFolder *f)
|
||||
{
|
||||
if (f->NumCoders < 1 || f->NumCoders > 4)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
if (IS_UNSUPPORTED_CODER(f->Coders[0]))
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
if (f->NumCoders == 1)
|
||||
{
|
||||
if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBindPairs != 0)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
return SZ_OK;
|
||||
}
|
||||
if (f->NumCoders == 2)
|
||||
{
|
||||
if (IS_NO_BCJ(f->Coders[1]) ||
|
||||
f->NumPackStreams != 1 || f->PackStreams[0] != 0 ||
|
||||
f->NumBindPairs != 1 ||
|
||||
f->BindPairs[0].InIndex != 1 || f->BindPairs[0].OutIndex != 0)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
return SZ_OK;
|
||||
}
|
||||
if (f->NumCoders == 4)
|
||||
{
|
||||
if (IS_UNSUPPORTED_CODER(f->Coders[1]) ||
|
||||
IS_UNSUPPORTED_CODER(f->Coders[2]) ||
|
||||
IS_NO_BCJ2(f->Coders[3]))
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
if (f->NumPackStreams != 4 ||
|
||||
f->PackStreams[0] != 2 ||
|
||||
f->PackStreams[1] != 6 ||
|
||||
f->PackStreams[2] != 1 ||
|
||||
f->PackStreams[3] != 0 ||
|
||||
f->NumBindPairs != 3 ||
|
||||
f->BindPairs[0].InIndex != 5 || f->BindPairs[0].OutIndex != 0 ||
|
||||
f->BindPairs[1].InIndex != 4 || f->BindPairs[1].OutIndex != 1 ||
|
||||
f->BindPairs[2].InIndex != 3 || f->BindPairs[2].OutIndex != 2)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
return SZ_OK;
|
||||
}
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
static
|
||||
UInt64 GetSum(const UInt64 *values, UInt32 index)
|
||||
{
|
||||
UInt64 sum = 0;
|
||||
UInt32 i;
|
||||
for (i = 0; i < index; i++)
|
||||
sum += values[i];
|
||||
return sum;
|
||||
}
|
||||
|
||||
static
|
||||
SRes SzDecode2(const UInt64 *packSizes, const CSzFolder *folder,
|
||||
ILookInStream *inStream, UInt64 startPos,
|
||||
Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain,
|
||||
Byte *tempBuf[])
|
||||
{
|
||||
UInt32 ci;
|
||||
SizeT tempSizes[3] = { 0, 0, 0};
|
||||
SizeT tempSize3 = 0;
|
||||
Byte *tempBuf3 = 0;
|
||||
|
||||
RINOK(CheckSupportedFolder(folder));
|
||||
|
||||
for (ci = 0; ci < folder->NumCoders; ci++)
|
||||
{
|
||||
CSzCoderInfo *coder = &folder->Coders[ci];
|
||||
|
||||
if (coder->MethodID == k_Copy || coder->MethodID == k_LZMA)
|
||||
{
|
||||
UInt32 si = 0;
|
||||
UInt64 offset;
|
||||
UInt64 inSize;
|
||||
Byte *outBufCur = outBuffer;
|
||||
SizeT outSizeCur = outSize;
|
||||
if (folder->NumCoders == 4)
|
||||
{
|
||||
UInt32 indices[] = { 3, 2, 0 };
|
||||
UInt64 unpackSize = folder->UnpackSizes[ci];
|
||||
si = indices[ci];
|
||||
if (ci < 2)
|
||||
{
|
||||
Byte *temp;
|
||||
outSizeCur = (SizeT)unpackSize;
|
||||
if (outSizeCur != unpackSize)
|
||||
return SZ_ERROR_MEM;
|
||||
temp = (Byte *)IAlloc_Alloc(allocMain, outSizeCur);
|
||||
if (temp == 0 && outSizeCur != 0)
|
||||
return SZ_ERROR_MEM;
|
||||
outBufCur = tempBuf[1 - ci] = temp;
|
||||
tempSizes[1 - ci] = outSizeCur;
|
||||
}
|
||||
else if (ci == 2)
|
||||
{
|
||||
if (unpackSize > outSize) /* check it */
|
||||
return SZ_ERROR_PARAM;
|
||||
tempBuf3 = outBufCur = outBuffer + (outSize - (size_t)unpackSize);
|
||||
tempSize3 = outSizeCur = (SizeT)unpackSize;
|
||||
}
|
||||
else
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
}
|
||||
offset = GetSum(packSizes, si);
|
||||
inSize = packSizes[si];
|
||||
RINOK(LookInStream_SeekTo(inStream, startPos + offset));
|
||||
|
||||
if (coder->MethodID == k_Copy)
|
||||
{
|
||||
if (inSize != outSizeCur) /* check it */
|
||||
return SZ_ERROR_DATA;
|
||||
RINOK(SzDecodeCopy(inSize, inStream, outBufCur));
|
||||
}
|
||||
else
|
||||
{
|
||||
RINOK(SzDecodeLzma(coder, inSize, inStream, outBufCur, outSizeCur, allocMain));
|
||||
}
|
||||
}
|
||||
else if (coder->MethodID == k_BCJ)
|
||||
{
|
||||
UInt32 state;
|
||||
if (ci != 1)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
x86_Convert_Init(state);
|
||||
x86_Convert(outBuffer, outSize, 0, &state, 0);
|
||||
}
|
||||
else if (coder->MethodID == k_BCJ2)
|
||||
{
|
||||
UInt64 offset = GetSum(packSizes, 1);
|
||||
UInt64 s3Size = packSizes[1];
|
||||
SRes res;
|
||||
if (ci != 3)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
RINOK(LookInStream_SeekTo(inStream, startPos + offset));
|
||||
tempSizes[2] = (SizeT)s3Size;
|
||||
if (tempSizes[2] != s3Size)
|
||||
return SZ_ERROR_MEM;
|
||||
tempBuf[2] = (Byte *)IAlloc_Alloc(allocMain, tempSizes[2]);
|
||||
if (tempBuf[2] == 0 && tempSizes[2] != 0)
|
||||
return SZ_ERROR_MEM;
|
||||
res = SzDecodeCopy(s3Size, inStream, tempBuf[2]);
|
||||
RINOK(res)
|
||||
|
||||
res = Bcj2_Decode(
|
||||
tempBuf3, tempSize3,
|
||||
tempBuf[0], tempSizes[0],
|
||||
tempBuf[1], tempSizes[1],
|
||||
tempBuf[2], tempSizes[2],
|
||||
outBuffer, outSize);
|
||||
RINOK(res)
|
||||
}
|
||||
else
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
}
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
SRes SzDecode(const UInt64 *packSizes, const CSzFolder *folder,
|
||||
ILookInStream *inStream, UInt64 startPos,
|
||||
Byte *outBuffer, size_t outSize, ISzAlloc *allocMain)
|
||||
{
|
||||
Byte *tempBuf[3] = { 0, 0, 0};
|
||||
int i;
|
||||
SRes res = SzDecode2(packSizes, folder, inStream, startPos,
|
||||
outBuffer, (SizeT)outSize, allocMain, tempBuf);
|
||||
for (i = 0; i < 3; i++)
|
||||
IAlloc_Free(allocMain, tempBuf[i]);
|
||||
return res;
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
/* 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 +0,0 @@
|
||||
/* 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 +0,0 @@
|
||||
/* 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 +0,0 @@
|
||||
/* 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 +0,0 @@
|
||||
/* 7zHeader.h -- 7z Headers
|
||||
2008-10-04 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __7Z_HEADER_H
|
||||
#define __7Z_HEADER_H
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
#define k7zSignatureSize 6
|
||||
extern Byte k7zSignature[k7zSignatureSize];
|
||||
|
||||
#define k7zMajorVersion 0
|
||||
|
||||
#define k7zStartHeaderSize 0x20
|
||||
|
||||
enum EIdEnum
|
||||
{
|
||||
k7zIdEnd,
|
||||
|
||||
k7zIdHeader,
|
||||
|
||||
k7zIdArchiveProperties,
|
||||
|
||||
k7zIdAdditionalStreamsInfo,
|
||||
k7zIdMainStreamsInfo,
|
||||
k7zIdFilesInfo,
|
||||
|
||||
k7zIdPackInfo,
|
||||
k7zIdUnpackInfo,
|
||||
k7zIdSubStreamsInfo,
|
||||
|
||||
k7zIdSize,
|
||||
k7zIdCRC,
|
||||
|
||||
k7zIdFolder,
|
||||
|
||||
k7zIdCodersUnpackSize,
|
||||
k7zIdNumUnpackStream,
|
||||
|
||||
k7zIdEmptyStream,
|
||||
k7zIdEmptyFile,
|
||||
k7zIdAnti,
|
||||
|
||||
k7zIdName,
|
||||
k7zIdCTime,
|
||||
k7zIdATime,
|
||||
k7zIdMTime,
|
||||
k7zIdWinAttributes,
|
||||
k7zIdComment,
|
||||
|
||||
k7zIdEncodedHeader,
|
||||
|
||||
k7zIdStartPos,
|
||||
k7zIdDummy
|
||||
};
|
||||
|
||||
#endif
|
1204
fex/7z_C/7zIn.c
1204
fex/7z_C/7zIn.c
File diff suppressed because it is too large
Load Diff
@ -1,49 +0,0 @@
|
||||
/* 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 +0,0 @@
|
||||
/* 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 +0,0 @@
|
||||
/* 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,184 +0,0 @@
|
||||
/* 7zStream.c -- 7z Stream functions
|
||||
2008-11-23 : Igor Pavlov : Public domain */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
#if NEVER_CALLED
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
|
||||
SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset)
|
||||
{
|
||||
Int64 t = offset;
|
||||
return stream->Seek(stream, &t, SZ_SEEK_SET);
|
||||
}
|
||||
|
||||
#if NEVER_CALLED
|
||||
SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size)
|
||||
{
|
||||
void *lookBuf;
|
||||
if (*size == 0)
|
||||
return SZ_OK;
|
||||
RINOK(stream->Look(stream, &lookBuf, size));
|
||||
memcpy(buf, lookBuf, *size);
|
||||
return stream->Skip(stream, *size);
|
||||
}
|
||||
#endif
|
||||
|
||||
SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType)
|
||||
{
|
||||
while (size != 0)
|
||||
{
|
||||
size_t processed = size;
|
||||
RINOK(stream->Read(stream, buf, &processed));
|
||||
if (processed == 0)
|
||||
return errorType;
|
||||
buf = (void *)((Byte *)buf + processed);
|
||||
size -= processed;
|
||||
}
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size)
|
||||
{
|
||||
return LookInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF);
|
||||
}
|
||||
|
||||
static SRes LookToRead_Look_Lookahead(void *pp, void **buf, size_t *size)
|
||||
{
|
||||
SRes res = SZ_OK;
|
||||
#if !NEVER_CALLED
|
||||
(void)pp;
|
||||
(void)buf;
|
||||
(void)size;
|
||||
#else
|
||||
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;
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
static SRes LookToRead_Look_Exact(void *pp, void **buf, size_t *size)
|
||||
{
|
||||
SRes res = SZ_OK;
|
||||
CLookToRead *p = (CLookToRead *)pp;
|
||||
size_t size2 = p->size - p->pos;
|
||||
if (size2 == 0 && *size > 0)
|
||||
{
|
||||
p->pos = 0;
|
||||
if (*size > LookToRead_BUF_SIZE)
|
||||
*size = LookToRead_BUF_SIZE;
|
||||
res = p->realStream->Read(p->realStream, p->buf, size);
|
||||
size2 = p->size = *size;
|
||||
}
|
||||
if (size2 < *size)
|
||||
*size = size2;
|
||||
*buf = p->buf + p->pos;
|
||||
return res;
|
||||
}
|
||||
|
||||
static SRes LookToRead_Skip(void *pp, size_t offset)
|
||||
{
|
||||
CLookToRead *p = (CLookToRead *)pp;
|
||||
p->pos += offset;
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
static SRes LookToRead_Read(void *pp, void *buf, size_t *size)
|
||||
{
|
||||
CLookToRead *p = (CLookToRead *)pp;
|
||||
size_t rem = p->size - p->pos;
|
||||
if (rem == 0)
|
||||
return p->realStream->Read(p->realStream, buf, size);
|
||||
if (rem > *size)
|
||||
rem = *size;
|
||||
memcpy(buf, p->buf + p->pos, rem);
|
||||
p->pos += rem;
|
||||
*size = rem;
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
static SRes LookToRead_Seek(void *pp, Int64 *pos, ESzSeek origin)
|
||||
{
|
||||
CLookToRead *p = (CLookToRead *)pp;
|
||||
p->pos = p->size = 0;
|
||||
return p->realStream->Seek(p->realStream, pos, origin);
|
||||
}
|
||||
|
||||
void LookToRead_CreateVTable(CLookToRead *p, int lookahead)
|
||||
{
|
||||
#if !NEVER_CALLED
|
||||
lookahead = 0;
|
||||
#endif
|
||||
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;
|
||||
}
|
||||
|
||||
#if NEVER_CALLED
|
||||
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;
|
||||
}
|
||||
#endif
|
132
fex/7z_C/Bcj2.c
132
fex/7z_C/Bcj2.c
@ -1,132 +0,0 @@
|
||||
/* 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 bb = buf0[inPos];
|
||||
outBuf[outPos++] = bb;
|
||||
if (IsJ(prevByte, bb))
|
||||
break;
|
||||
inPos++;
|
||||
prevByte = bb;
|
||||
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,30 +0,0 @@
|
||||
/* Bcj2.h -- Converter for x86 code (BCJ2)
|
||||
2008-10-04 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __BCJ2_H
|
||||
#define __BCJ2_H
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
/*
|
||||
Conditions:
|
||||
outSize <= FullOutputSize,
|
||||
where FullOutputSize is full size of output stream of x86_2 filter.
|
||||
|
||||
If buf0 overlaps outBuf, there are two required conditions:
|
||||
1) (buf0 >= outBuf)
|
||||
2) (buf0 + size0 >= outBuf + FullOutputSize).
|
||||
|
||||
Returns:
|
||||
SZ_OK
|
||||
SZ_ERROR_DATA - Data error
|
||||
*/
|
||||
|
||||
int Bcj2_Decode(
|
||||
const Byte *buf0, SizeT size0,
|
||||
const Byte *buf1, SizeT size1,
|
||||
const Byte *buf2, SizeT size2,
|
||||
const Byte *buf3, SizeT size3,
|
||||
Byte *outBuf, SizeT outSize);
|
||||
|
||||
#endif
|
@ -1,60 +0,0 @@
|
||||
/* Bra.h -- Branch converters for executables
|
||||
2008-10-04 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __BRA_H
|
||||
#define __BRA_H
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
/*
|
||||
These functions convert relative addresses to absolute addresses
|
||||
in CALL instructions to increase the compression ratio.
|
||||
|
||||
In:
|
||||
data - data buffer
|
||||
size - size of data
|
||||
ip - current virtual Instruction Pinter (IP) value
|
||||
state - state variable for x86 converter
|
||||
encoding - 0 (for decoding), 1 (for encoding)
|
||||
|
||||
Out:
|
||||
state - state variable for x86 converter
|
||||
|
||||
Returns:
|
||||
The number of processed bytes. If you call these functions with multiple calls,
|
||||
you must start next call with first byte after block of processed bytes.
|
||||
|
||||
Type Endian Alignment LookAhead
|
||||
|
||||
x86 little 1 4
|
||||
ARMT little 2 2
|
||||
ARM little 4 0
|
||||
PPC big 4 0
|
||||
SPARC big 4 0
|
||||
IA64 little 16 0
|
||||
|
||||
size must be >= Alignment + LookAhead, if it's not last block.
|
||||
If (size < Alignment + LookAhead), converter returns 0.
|
||||
|
||||
Example:
|
||||
|
||||
UInt32 ip = 0;
|
||||
for ()
|
||||
{
|
||||
; size must be >= Alignment + LookAhead, if it's not last block
|
||||
SizeT processed = Convert(data, size, ip, 1);
|
||||
data += processed;
|
||||
size -= processed;
|
||||
ip += processed;
|
||||
}
|
||||
*/
|
||||
|
||||
#define x86_Convert_Init(state) { state = 0; }
|
||||
SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding);
|
||||
SizeT ARM_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
|
||||
SizeT ARMT_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
|
||||
SizeT PPC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
|
||||
SizeT SPARC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
|
||||
SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
|
||||
|
||||
#endif
|
@ -1,85 +0,0 @@
|
||||
/* 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,69 +0,0 @@
|
||||
/* CpuArch.h
|
||||
2008-08-05
|
||||
Igor Pavlov
|
||||
Public domain */
|
||||
|
||||
#ifndef __CPUARCH_H
|
||||
#define __CPUARCH_H
|
||||
|
||||
/*
|
||||
LITTLE_ENDIAN_UNALIGN means:
|
||||
1) CPU is LITTLE_ENDIAN
|
||||
2) it's allowed to make unaligned memory accesses
|
||||
if LITTLE_ENDIAN_UNALIGN is not defined, it means that we don't know
|
||||
about these properties of platform.
|
||||
*/
|
||||
|
||||
#if defined(_M_IX86) || defined(_M_X64) || defined(_M_AMD64) || defined(__i386__) || defined(__x86_64__)
|
||||
#define LITTLE_ENDIAN_UNALIGN
|
||||
#endif
|
||||
|
||||
#ifdef LITTLE_ENDIAN_UNALIGN
|
||||
|
||||
#define GetUi16(p) (*(const UInt16 *)(p))
|
||||
#define GetUi32(p) (*(const UInt32 *)(p))
|
||||
#define GetUi64(p) (*(const UInt64 *)(p))
|
||||
#define SetUi32(p, d) *(UInt32 *)(p) = (d);
|
||||
|
||||
#else
|
||||
|
||||
#define GetUi16(p) (((const Byte *)(p))[0] | ((UInt16)((const Byte *)(p))[1] << 8))
|
||||
|
||||
#define GetUi32(p) ( \
|
||||
((const Byte *)(p))[0] | \
|
||||
((UInt32)((const Byte *)(p))[1] << 8) | \
|
||||
((UInt32)((const Byte *)(p))[2] << 16) | \
|
||||
((UInt32)((const Byte *)(p))[3] << 24))
|
||||
|
||||
#define GetUi64(p) (GetUi32(p) | ((UInt64)GetUi32(((const Byte *)(p)) + 4) << 32))
|
||||
|
||||
#define SetUi32(p, d) { UInt32 _x_ = (d); \
|
||||
((Byte *)(p))[0] = (Byte)_x_; \
|
||||
((Byte *)(p))[1] = (Byte)(_x_ >> 8); \
|
||||
((Byte *)(p))[2] = (Byte)(_x_ >> 16); \
|
||||
((Byte *)(p))[3] = (Byte)(_x_ >> 24); }
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(LITTLE_ENDIAN_UNALIGN) && defined(_WIN64) && (_MSC_VER >= 1300)
|
||||
|
||||
#pragma intrinsic(_byteswap_ulong)
|
||||
#pragma intrinsic(_byteswap_uint64)
|
||||
#define GetBe32(p) _byteswap_ulong(*(const UInt32 *)(const Byte *)(p))
|
||||
#define GetBe64(p) _byteswap_uint64(*(const UInt64 *)(const Byte *)(p))
|
||||
|
||||
#else
|
||||
|
||||
#define GetBe32(p) ( \
|
||||
((UInt32)((const Byte *)(p))[0] << 24) | \
|
||||
((UInt32)((const Byte *)(p))[1] << 16) | \
|
||||
((UInt32)((const Byte *)(p))[2] << 8) | \
|
||||
((const Byte *)(p))[3] )
|
||||
|
||||
#define GetBe64(p) (((UInt64)GetBe32(p) << 32) | GetBe32(((const Byte *)(p)) + 4))
|
||||
|
||||
#endif
|
||||
|
||||
#define GetBe16(p) (((UInt16)((const Byte *)(p))[0] << 8) | ((const Byte *)(p))[1])
|
||||
|
||||
#endif
|
1010
fex/7z_C/LzmaDec.c
1010
fex/7z_C/LzmaDec.c
File diff suppressed because it is too large
Load Diff
@ -1,223 +0,0 @@
|
||||
/* LzmaDec.h -- LZMA Decoder
|
||||
2008-10-04 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __LZMADEC_H
|
||||
#define __LZMADEC_H
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
/* #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);
|
||||
|
||||
#endif
|
206
fex/7z_C/Types.h
206
fex/7z_C/Types.h
@ -1,206 +0,0 @@
|
||||
/* Types.h -- Basic types
|
||||
2008-11-23 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __7Z_TYPES_H
|
||||
#define __7Z_TYPES_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#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;
|
||||
|
||||
#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;
|
||||
#else
|
||||
typedef long long int Int64;
|
||||
typedef unsigned long long int UInt64;
|
||||
#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 _MSC_VER
|
||||
|
||||
#if _MSC_VER >= 1300
|
||||
#define MY_NO_INLINE __declspec(noinline)
|
||||
#else
|
||||
#define MY_NO_INLINE
|
||||
#endif
|
||||
|
||||
#define MY_CDECL __cdecl
|
||||
#define MY_STD_CALL __stdcall
|
||||
#define MY_FAST_CALL MY_NO_INLINE __fastcall
|
||||
|
||||
#else
|
||||
|
||||
#define MY_CDECL
|
||||
#define MY_STD_CALL
|
||||
#define MY_FAST_CALL
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* The following interfaces use first parameter as pointer to structure */
|
||||
|
||||
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, 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 __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,594 +0,0 @@
|
||||
LZMA SDK 4.65
|
||||
-------------
|
||||
|
||||
LZMA SDK provides the documentation, samples, header files, libraries,
|
||||
and tools you need to develop applications that use LZMA compression.
|
||||
|
||||
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.
|
||||
|
||||
LZMA is an improved version of famous LZ77 compression algorithm.
|
||||
It was improved in way of maximum increasing of compression ratio,
|
||||
keeping high decompression speed and low memory requirements for
|
||||
decompressing.
|
||||
|
||||
|
||||
|
||||
LICENSE
|
||||
-------
|
||||
|
||||
LZMA SDK is written and placed in the public domain by Igor Pavlov.
|
||||
|
||||
|
||||
LZMA SDK Contents
|
||||
-----------------
|
||||
|
||||
LZMA SDK includes:
|
||||
|
||||
- ANSI-C/C++/C#/Java source code for LZMA compressing and decompressing
|
||||
- Compiled file->file LZMA compressing/decompressing program for Windows system
|
||||
|
||||
|
||||
UNIX/Linux version
|
||||
------------------
|
||||
To compile C++ version of file->file LZMA encoding, go to directory
|
||||
C++/7zip/Compress/LZMA_Alone
|
||||
and call make to recompile it:
|
||||
make -f makefile.gcc clean all
|
||||
|
||||
In some UNIX/Linux versions you must compile LZMA with static libraries.
|
||||
To compile with static libraries, you can use
|
||||
LIB = -lm -static
|
||||
|
||||
|
||||
Files
|
||||
---------------------
|
||||
lzma.txt - LZMA SDK description (this file)
|
||||
7zFormat.txt - 7z Format description
|
||||
7zC.txt - 7z ANSI-C Decoder description
|
||||
methods.txt - Compression method IDs for .7z
|
||||
lzma.exe - Compiled file->file LZMA encoder/decoder for Windows
|
||||
history.txt - history of the LZMA SDK
|
||||
|
||||
|
||||
Source code structure
|
||||
---------------------
|
||||
|
||||
C/ - C files
|
||||
7zCrc*.* - CRC code
|
||||
Alloc.* - Memory allocation functions
|
||||
Bra*.* - Filters for x86, IA-64, ARM, ARM-Thumb, PowerPC and SPARC code
|
||||
LzFind.* - Match finder for LZ (LZMA) encoders
|
||||
LzFindMt.* - Match finder for LZ (LZMA) encoders for multithreading encoding
|
||||
LzHash.h - Additional file for LZ match finder
|
||||
LzmaDec.* - LZMA decoding
|
||||
LzmaEnc.* - LZMA encoding
|
||||
LzmaLib.* - LZMA Library for DLL calling
|
||||
Types.h - Basic types for another .c files
|
||||
Threads.* - The code for multithreading.
|
||||
|
||||
LzmaLib - LZMA Library (.DLL for Windows)
|
||||
|
||||
LzmaUtil - LZMA Utility (file->file LZMA encoder/decoder).
|
||||
|
||||
Archive - files related to archiving
|
||||
7z - 7z ANSI-C Decoder
|
||||
|
||||
CPP/ -- CPP files
|
||||
|
||||
Common - common files for C++ projects
|
||||
Windows - common files for Windows related code
|
||||
|
||||
7zip - files related to 7-Zip Project
|
||||
|
||||
Common - common files for 7-Zip
|
||||
|
||||
Compress - files related to compression/decompression
|
||||
|
||||
Copy - Copy coder
|
||||
RangeCoder - Range Coder (special code of compression/decompression)
|
||||
LZMA - LZMA compression/decompression on C++
|
||||
LZMA_Alone - file->file LZMA compression/decompression
|
||||
Branch - Filters for x86, IA-64, ARM, ARM-Thumb, PowerPC and SPARC code
|
||||
|
||||
Archive - files related to archiving
|
||||
|
||||
Common - common files for archive handling
|
||||
7z - 7z C++ Encoder/Decoder
|
||||
|
||||
Bundles - Modules that are bundles of other modules
|
||||
|
||||
Alone7z - 7zr.exe: Standalone version of 7z.exe that supports only 7z/LZMA/BCJ/BCJ2
|
||||
Format7zR - 7zr.dll: Reduced version of 7za.dll: extracting/compressing to 7z/LZMA/BCJ/BCJ2
|
||||
Format7zExtractR - 7zxr.dll: Reduced version of 7zxa.dll: extracting from 7z/LZMA/BCJ/BCJ2.
|
||||
|
||||
UI - User Interface files
|
||||
|
||||
Client7z - Test application for 7za.dll, 7zr.dll, 7zxr.dll
|
||||
Common - Common UI files
|
||||
Console - Code for console archiver
|
||||
|
||||
|
||||
|
||||
CS/ - C# files
|
||||
7zip
|
||||
Common - some common files for 7-Zip
|
||||
Compress - files related to compression/decompression
|
||||
LZ - files related to LZ (Lempel-Ziv) compression algorithm
|
||||
LZMA - LZMA compression/decompression
|
||||
LzmaAlone - file->file LZMA compression/decompression
|
||||
RangeCoder - Range Coder (special code of compression/decompression)
|
||||
|
||||
Java/ - Java files
|
||||
SevenZip
|
||||
Compression - files related to compression/decompression
|
||||
LZ - files related to LZ (Lempel-Ziv) compression algorithm
|
||||
LZMA - LZMA compression/decompression
|
||||
RangeCoder - Range Coder (special code of compression/decompression)
|
||||
|
||||
|
||||
C/C++ source code of LZMA SDK is part of 7-Zip project.
|
||||
7-Zip source code can be downloaded from 7-Zip's SourceForge page:
|
||||
|
||||
http://sourceforge.net/projects/sevenzip/
|
||||
|
||||
|
||||
|
||||
LZMA features
|
||||
-------------
|
||||
- Variable dictionary size (up to 1 GB)
|
||||
- Estimated compressing speed: about 2 MB/s on 2 GHz CPU
|
||||
- Estimated decompressing speed:
|
||||
- 20-30 MB/s on 2 GHz Core 2 or AMD Athlon 64
|
||||
- 1-2 MB/s on 200 MHz ARM, MIPS, PowerPC or other simple RISC
|
||||
- Small memory requirements for decompressing (16 KB + DictionarySize)
|
||||
- Small code size for decompressing: 5-8 KB
|
||||
|
||||
LZMA decoder uses only integer operations and can be
|
||||
implemented in any modern 32-bit CPU (or on 16-bit CPU with some conditions).
|
||||
|
||||
Some critical operations that affect the speed of LZMA decompression:
|
||||
1) 32*16 bit integer multiply
|
||||
2) Misspredicted branches (penalty mostly depends from pipeline length)
|
||||
3) 32-bit shift and arithmetic operations
|
||||
|
||||
The speed of LZMA decompressing mostly depends from CPU speed.
|
||||
Memory speed has no big meaning. But if your CPU has small data cache,
|
||||
overall weight of memory speed will slightly increase.
|
||||
|
||||
|
||||
How To Use
|
||||
----------
|
||||
|
||||
Using LZMA encoder/decoder executable
|
||||
--------------------------------------
|
||||
|
||||
Usage: LZMA <e|d> inputFile outputFile [<switches>...]
|
||||
|
||||
e: encode file
|
||||
|
||||
d: decode file
|
||||
|
||||
b: Benchmark. There are two tests: compressing and decompressing
|
||||
with LZMA method. Benchmark shows rating in MIPS (million
|
||||
instructions per second). Rating value is calculated from
|
||||
measured speed and it is normalized with Intel's Core 2 results.
|
||||
Also Benchmark checks possible hardware errors (RAM
|
||||
errors in most cases). Benchmark uses these settings:
|
||||
(-a1, -d21, -fb32, -mfbt4). You can change only -d parameter.
|
||||
Also you can change the number of iterations. Example for 30 iterations:
|
||||
LZMA b 30
|
||||
Default number of iterations is 10.
|
||||
|
||||
<Switches>
|
||||
|
||||
|
||||
-a{N}: set compression mode 0 = fast, 1 = normal
|
||||
default: 1 (normal)
|
||||
|
||||
d{N}: Sets Dictionary size - [0, 30], default: 23 (8MB)
|
||||
The maximum value for dictionary size is 1 GB = 2^30 bytes.
|
||||
Dictionary size is calculated as DictionarySize = 2^N bytes.
|
||||
For decompressing file compressed by LZMA method with dictionary
|
||||
size D = 2^N you need about D bytes of memory (RAM).
|
||||
|
||||
-fb{N}: set number of fast bytes - [5, 273], default: 128
|
||||
Usually big number gives a little bit better compression ratio
|
||||
and slower compression process.
|
||||
|
||||
-lc{N}: set number of literal context bits - [0, 8], default: 3
|
||||
Sometimes lc=4 gives gain for big files.
|
||||
|
||||
-lp{N}: set number of literal pos bits - [0, 4], default: 0
|
||||
lp switch is intended for periodical data when period is
|
||||
equal 2^N. For example, for 32-bit (4 bytes)
|
||||
periodical data you can use lp=2. Often it's better to set lc0,
|
||||
if you change lp switch.
|
||||
|
||||
-pb{N}: set number of pos bits - [0, 4], default: 2
|
||||
pb switch is intended for periodical data
|
||||
when period is equal 2^N.
|
||||
|
||||
-mf{MF_ID}: set Match Finder. Default: bt4.
|
||||
Algorithms from hc* group doesn't provide good compression
|
||||
ratio, but they often works pretty fast in combination with
|
||||
fast mode (-a0).
|
||||
|
||||
Memory requirements depend from dictionary size
|
||||
(parameter "d" in table below).
|
||||
|
||||
MF_ID Memory Description
|
||||
|
||||
bt2 d * 9.5 + 4MB Binary Tree with 2 bytes hashing.
|
||||
bt3 d * 11.5 + 4MB Binary Tree with 3 bytes hashing.
|
||||
bt4 d * 11.5 + 4MB Binary Tree with 4 bytes hashing.
|
||||
hc4 d * 7.5 + 4MB Hash Chain with 4 bytes hashing.
|
||||
|
||||
-eos: write End Of Stream marker. By default LZMA doesn't write
|
||||
eos marker, since LZMA decoder knows uncompressed size
|
||||
stored in .lzma file header.
|
||||
|
||||
-si: Read data from stdin (it will write End Of Stream marker).
|
||||
-so: Write data to stdout
|
||||
|
||||
|
||||
Examples:
|
||||
|
||||
1) LZMA e file.bin file.lzma -d16 -lc0
|
||||
|
||||
compresses file.bin to file.lzma with 64 KB dictionary (2^16=64K)
|
||||
and 0 literal context bits. -lc0 allows to reduce memory requirements
|
||||
for decompression.
|
||||
|
||||
|
||||
2) LZMA e file.bin file.lzma -lc0 -lp2
|
||||
|
||||
compresses file.bin to file.lzma with settings suitable
|
||||
for 32-bit periodical data (for example, ARM or MIPS code).
|
||||
|
||||
3) LZMA d file.lzma file.bin
|
||||
|
||||
decompresses file.lzma to file.bin.
|
||||
|
||||
|
||||
Compression ratio hints
|
||||
-----------------------
|
||||
|
||||
Recommendations
|
||||
---------------
|
||||
|
||||
To increase the compression ratio for LZMA compressing it's desirable
|
||||
to have aligned data (if it's possible) and also it's desirable to locate
|
||||
data in such order, where code is grouped in one place and data is
|
||||
grouped in other place (it's better than such mixing: code, data, code,
|
||||
data, ...).
|
||||
|
||||
|
||||
Filters
|
||||
-------
|
||||
You can increase the compression ratio for some data types, using
|
||||
special filters before compressing. For example, it's possible to
|
||||
increase the compression ratio on 5-10% for code for those CPU ISAs:
|
||||
x86, IA-64, ARM, ARM-Thumb, PowerPC, SPARC.
|
||||
|
||||
You can find C source code of such filters in C/Bra*.* files
|
||||
|
||||
You can check the compression ratio gain of these filters with such
|
||||
7-Zip commands (example for ARM code):
|
||||
No filter:
|
||||
7z a a1.7z a.bin -m0=lzma
|
||||
|
||||
With filter for little-endian ARM code:
|
||||
7z a a2.7z a.bin -m0=arm -m1=lzma
|
||||
|
||||
It works in such manner:
|
||||
Compressing = Filter_encoding + LZMA_encoding
|
||||
Decompressing = LZMA_decoding + Filter_decoding
|
||||
|
||||
Compressing and decompressing speed of such filters is very high,
|
||||
so it will not increase decompressing time too much.
|
||||
Moreover, it reduces decompression time for LZMA_decoding,
|
||||
since compression ratio with filtering is higher.
|
||||
|
||||
These filters convert CALL (calling procedure) instructions
|
||||
from relative offsets to absolute addresses, so such data becomes more
|
||||
compressible.
|
||||
|
||||
For some ISAs (for example, for MIPS) it's impossible to get gain from such filter.
|
||||
|
||||
|
||||
LZMA compressed file format
|
||||
---------------------------
|
||||
Offset Size Description
|
||||
0 1 Special LZMA properties (lc,lp, pb in encoded form)
|
||||
1 4 Dictionary size (little endian)
|
||||
5 8 Uncompressed size (little endian). -1 means unknown size
|
||||
13 Compressed data
|
||||
|
||||
|
||||
ANSI-C LZMA Decoder
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Please note that interfaces for ANSI-C code were changed in LZMA SDK 4.58.
|
||||
If you want to use old interfaces you can download previous version of LZMA SDK
|
||||
from sourceforge.net site.
|
||||
|
||||
To use ANSI-C LZMA Decoder you need the following files:
|
||||
1) LzmaDec.h + LzmaDec.c + Types.h
|
||||
LzmaUtil/LzmaUtil.c is example application that uses these files.
|
||||
|
||||
|
||||
Memory requirements for LZMA decoding
|
||||
-------------------------------------
|
||||
|
||||
Stack usage of LZMA decoding function for local variables is not
|
||||
larger than 200-400 bytes.
|
||||
|
||||
LZMA Decoder uses dictionary buffer and internal state structure.
|
||||
Internal state structure consumes
|
||||
state_size = (4 + (1.5 << (lc + lp))) KB
|
||||
by default (lc=3, lp=0), state_size = 16 KB.
|
||||
|
||||
|
||||
How To decompress data
|
||||
----------------------
|
||||
|
||||
LZMA Decoder (ANSI-C version) now supports 2 interfaces:
|
||||
1) Single-call Decompressing
|
||||
2) Multi-call State Decompressing (zlib-like interface)
|
||||
|
||||
You must use external allocator:
|
||||
Example:
|
||||
void *SzAlloc(void *p, size_t size) { p = p; return malloc(size); }
|
||||
void SzFree(void *p, void *address) { p = p; free(address); }
|
||||
ISzAlloc alloc = { SzAlloc, SzFree };
|
||||
|
||||
You can use p = p; operator to disable compiler warnings.
|
||||
|
||||
|
||||
Single-call Decompressing
|
||||
-------------------------
|
||||
When to use: RAM->RAM decompressing
|
||||
Compile files: LzmaDec.h + LzmaDec.c + Types.h
|
||||
Compile defines: no defines
|
||||
Memory Requirements:
|
||||
- Input buffer: compressed size
|
||||
- Output buffer: uncompressed size
|
||||
- LZMA Internal Structures: state_size (16 KB for default settings)
|
||||
|
||||
Interface:
|
||||
int LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
|
||||
const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
|
||||
ELzmaStatus *status, ISzAlloc *alloc);
|
||||
In:
|
||||
dest - output data
|
||||
destLen - output data size
|
||||
src - input data
|
||||
srcLen - input data size
|
||||
propData - LZMA properties (5 bytes)
|
||||
propSize - size of propData buffer (5 bytes)
|
||||
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).
|
||||
You can use LZMA_FINISH_END, when you know that
|
||||
current output buffer covers last bytes of stream.
|
||||
alloc - Memory allocator.
|
||||
|
||||
Out:
|
||||
destLen - processed output size
|
||||
srcLen - processed input size
|
||||
|
||||
Output:
|
||||
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).
|
||||
|
||||
If LZMA decoder sees end_marker before reaching output limit, it returns OK result,
|
||||
and output value of destLen will be less than output buffer size limit.
|
||||
|
||||
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. */
|
||||
|
||||
|
||||
Multi-call State Decompressing (zlib-like interface)
|
||||
----------------------------------------------------
|
||||
|
||||
When to use: file->file decompressing
|
||||
Compile files: LzmaDec.h + LzmaDec.c + Types.h
|
||||
|
||||
Memory Requirements:
|
||||
- Buffer for input stream: any size (for example, 16 KB)
|
||||
- Buffer for output stream: any size (for example, 16 KB)
|
||||
- LZMA Internal Structures: state_size (16 KB for default settings)
|
||||
- LZMA dictionary (dictionary size is encoded in LZMA properties header)
|
||||
|
||||
1) read LZMA properties (5 bytes) and uncompressed size (8 bytes, little-endian) to header:
|
||||
unsigned char header[LZMA_PROPS_SIZE + 8];
|
||||
ReadFile(inFile, header, sizeof(header)
|
||||
|
||||
2) Allocate CLzmaDec structures (state + dictionary) using LZMA properties
|
||||
|
||||
CLzmaDec state;
|
||||
LzmaDec_Constr(&state);
|
||||
res = LzmaDec_Allocate(&state, header, LZMA_PROPS_SIZE, &g_Alloc);
|
||||
if (res != SZ_OK)
|
||||
return res;
|
||||
|
||||
3) Init LzmaDec structure before any new LZMA stream. And call LzmaDec_DecodeToBuf in loop
|
||||
|
||||
LzmaDec_Init(&state);
|
||||
for (;;)
|
||||
{
|
||||
...
|
||||
int res = LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen,
|
||||
const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode);
|
||||
...
|
||||
}
|
||||
|
||||
|
||||
4) Free all allocated structures
|
||||
LzmaDec_Free(&state, &g_Alloc);
|
||||
|
||||
For full code example, look at C/LzmaUtil/LzmaUtil.c code.
|
||||
|
||||
|
||||
How To compress data
|
||||
--------------------
|
||||
|
||||
Compile files: LzmaEnc.h + LzmaEnc.c + Types.h +
|
||||
LzFind.c + LzFind.h + LzFindMt.c + LzFindMt.h + LzHash.h
|
||||
|
||||
Memory Requirements:
|
||||
- (dictSize * 11.5 + 6 MB) + state_size
|
||||
|
||||
Lzma Encoder can use two memory allocators:
|
||||
1) alloc - for small arrays.
|
||||
2) allocBig - for big arrays.
|
||||
|
||||
For example, you can use Large RAM Pages (2 MB) in allocBig allocator for
|
||||
better compression speed. Note that Windows has bad implementation for
|
||||
Large RAM Pages.
|
||||
It's OK to use same allocator for alloc and allocBig.
|
||||
|
||||
|
||||
Single-call Compression with callbacks
|
||||
--------------------------------------
|
||||
|
||||
Check C/LzmaUtil/LzmaUtil.c as example,
|
||||
|
||||
When to use: file->file decompressing
|
||||
|
||||
1) you must implement callback structures for interfaces:
|
||||
ISeqInStream
|
||||
ISeqOutStream
|
||||
ICompressProgress
|
||||
ISzAlloc
|
||||
|
||||
static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); }
|
||||
static void SzFree(void *p, void *address) { p = p; MyFree(address); }
|
||||
static ISzAlloc g_Alloc = { SzAlloc, SzFree };
|
||||
|
||||
CFileSeqInStream inStream;
|
||||
CFileSeqOutStream outStream;
|
||||
|
||||
inStream.funcTable.Read = MyRead;
|
||||
inStream.file = inFile;
|
||||
outStream.funcTable.Write = MyWrite;
|
||||
outStream.file = outFile;
|
||||
|
||||
|
||||
2) Create CLzmaEncHandle object;
|
||||
|
||||
CLzmaEncHandle enc;
|
||||
|
||||
enc = LzmaEnc_Create(&g_Alloc);
|
||||
if (enc == 0)
|
||||
return SZ_ERROR_MEM;
|
||||
|
||||
|
||||
3) initialize CLzmaEncProps properties;
|
||||
|
||||
LzmaEncProps_Init(&props);
|
||||
|
||||
Then you can change some properties in that structure.
|
||||
|
||||
4) Send LZMA properties to LZMA Encoder
|
||||
|
||||
res = LzmaEnc_SetProps(enc, &props);
|
||||
|
||||
5) Write encoded properties to header
|
||||
|
||||
Byte header[LZMA_PROPS_SIZE + 8];
|
||||
size_t headerSize = LZMA_PROPS_SIZE;
|
||||
UInt64 fileSize;
|
||||
int i;
|
||||
|
||||
res = LzmaEnc_WriteProperties(enc, header, &headerSize);
|
||||
fileSize = MyGetFileLength(inFile);
|
||||
for (i = 0; i < 8; i++)
|
||||
header[headerSize++] = (Byte)(fileSize >> (8 * i));
|
||||
MyWriteFileAndCheck(outFile, header, headerSize)
|
||||
|
||||
6) Call encoding function:
|
||||
res = LzmaEnc_Encode(enc, &outStream.funcTable, &inStream.funcTable,
|
||||
NULL, &g_Alloc, &g_Alloc);
|
||||
|
||||
7) Destroy LZMA Encoder Object
|
||||
LzmaEnc_Destroy(enc, &g_Alloc, &g_Alloc);
|
||||
|
||||
|
||||
If callback function return some error code, LzmaEnc_Encode also returns that code.
|
||||
|
||||
|
||||
Single-call RAM->RAM Compression
|
||||
--------------------------------
|
||||
|
||||
Single-call RAM->RAM Compression is similar to Compression with callbacks,
|
||||
but you provide pointers to buffers instead of pointers to stream callbacks:
|
||||
|
||||
HRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
|
||||
CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark,
|
||||
ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
|
||||
|
||||
Return code:
|
||||
SZ_OK - OK
|
||||
SZ_ERROR_MEM - Memory allocation error
|
||||
SZ_ERROR_PARAM - Incorrect paramater
|
||||
SZ_ERROR_OUTPUT_EOF - output buffer overflow
|
||||
SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version)
|
||||
|
||||
|
||||
|
||||
LZMA Defines
|
||||
------------
|
||||
|
||||
_LZMA_SIZE_OPT - Enable some optimizations in LZMA Decoder to get smaller executable code.
|
||||
|
||||
_LZMA_PROB32 - It can increase the speed on some 32-bit CPUs, but memory usage for
|
||||
some structures will be doubled in that case.
|
||||
|
||||
_LZMA_UINT32_IS_ULONG - Define it if int is 16-bit on your compiler and long is 32-bit.
|
||||
|
||||
_LZMA_NO_SYSTEM_SIZE_T - Define it if you don't want to use size_t type.
|
||||
|
||||
|
||||
C++ LZMA Encoder/Decoder
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
C++ LZMA code use COM-like interfaces. So if you want to use it,
|
||||
you can study basics of COM/OLE.
|
||||
C++ LZMA code is just wrapper over ANSI-C code.
|
||||
|
||||
|
||||
C++ Notes
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
If you use some C++ code folders in 7-Zip (for example, C++ code for .7z handling),
|
||||
you must check that you correctly work with "new" operator.
|
||||
7-Zip can be compiled with MSVC 6.0 that doesn't throw "exception" from "new" operator.
|
||||
So 7-Zip uses "CPP\Common\NewHandler.cpp" that redefines "new" operator:
|
||||
operator new(size_t size)
|
||||
{
|
||||
void *p = ::malloc(size);
|
||||
if (p == 0)
|
||||
throw CNewException();
|
||||
return p;
|
||||
}
|
||||
If you use MSCV that throws exception for "new" operator, you can compile without
|
||||
"NewHandler.cpp". So standard exception will be used. Actually some code of
|
||||
7-Zip catches any exception in internal code and converts it to HRESULT code.
|
||||
So you don't need to catch CNewException, if you call COM interfaces of 7-Zip.
|
||||
|
||||
---
|
||||
|
||||
http://www.7-zip.org
|
||||
http://www.7-zip.org/sdk.html
|
||||
http://www.7-zip.org/support.html
|
@ -1,19 +0,0 @@
|
||||
Modified LZMA 4.65
|
||||
------------------
|
||||
This is just the ANSI C 7-zip extraction code from the LZMA 4.65 source
|
||||
code release, with unnecessary files removed. I've made minor changes to
|
||||
allow the code to compile with almost all warnings enabled in GCC.
|
||||
|
||||
* Made relevant functions extern "C" so that they can be called from
|
||||
C++.
|
||||
|
||||
* Put all files in same directory and removed "../../" from #includes.
|
||||
|
||||
* Made private (unprototyped) functions static.
|
||||
|
||||
* #if'd out code that is never called.
|
||||
|
||||
* Removed a couple of Windows references.
|
||||
|
||||
--
|
||||
Shay Green <gblargg@gmail.com>
|
@ -1,77 +0,0 @@
|
||||
// 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 +0,0 @@
|
||||
// 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
|
@ -1,551 +0,0 @@
|
||||
// File_Extractor 1.0.0. http://www.slack.net/~ant/
|
||||
|
||||
#include "Data_Reader.h"
|
||||
|
||||
#include "blargg_endian.h"
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#if BLARGG_UTF8_PATHS
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
/* 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"
|
||||
|
||||
// Data_Reader
|
||||
|
||||
blargg_err_t Data_Reader::read( void* p, int n )
|
||||
{
|
||||
assert( n >= 0 );
|
||||
|
||||
if ( n < 0 )
|
||||
return blargg_err_caller;
|
||||
|
||||
if ( n <= 0 )
|
||||
return blargg_ok;
|
||||
|
||||
if ( n > remain() )
|
||||
return blargg_err_file_eof;
|
||||
|
||||
blargg_err_t err = read_v( p, n );
|
||||
if ( !err )
|
||||
remain_ -= n;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
blargg_err_t Data_Reader::read_avail( void* p, int* n_ )
|
||||
{
|
||||
assert( *n_ >= 0 );
|
||||
|
||||
int n = min( *n_, remain() );
|
||||
*n_ = 0;
|
||||
|
||||
if ( n < 0 )
|
||||
return blargg_err_caller;
|
||||
|
||||
if ( n <= 0 )
|
||||
return blargg_ok;
|
||||
|
||||
blargg_err_t err = read_v( p, n );
|
||||
if ( !err )
|
||||
{
|
||||
remain_ -= n;
|
||||
*n_ = n;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
blargg_err_t Data_Reader::read_avail( void* p, long* n )
|
||||
{
|
||||
int i = STATIC_CAST(int, *n);
|
||||
blargg_err_t err = read_avail( p, &i );
|
||||
*n = i;
|
||||
return err;
|
||||
}
|
||||
|
||||
blargg_err_t Data_Reader::skip_v( int count )
|
||||
{
|
||||
char buf [512];
|
||||
while ( count )
|
||||
{
|
||||
int n = min( count, (int) sizeof buf );
|
||||
count -= n;
|
||||
RETURN_ERR( read_v( buf, n ) );
|
||||
}
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
blargg_err_t Data_Reader::skip( int n )
|
||||
{
|
||||
assert( n >= 0 );
|
||||
|
||||
if ( n < 0 )
|
||||
return blargg_err_caller;
|
||||
|
||||
if ( n <= 0 )
|
||||
return blargg_ok;
|
||||
|
||||
if ( n > remain() )
|
||||
return blargg_err_file_eof;
|
||||
|
||||
blargg_err_t err = skip_v( n );
|
||||
if ( !err )
|
||||
remain_ -= n;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
// File_Reader
|
||||
|
||||
blargg_err_t File_Reader::seek( int n )
|
||||
{
|
||||
assert( n >= 0 );
|
||||
|
||||
if ( n < 0 )
|
||||
return blargg_err_caller;
|
||||
|
||||
if ( n == tell() )
|
||||
return blargg_ok;
|
||||
|
||||
if ( n > size() )
|
||||
return blargg_err_file_eof;
|
||||
|
||||
blargg_err_t err = seek_v( n );
|
||||
if ( !err )
|
||||
set_tell( n );
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
blargg_err_t File_Reader::skip_v( int n )
|
||||
{
|
||||
return seek_v( tell() + n );
|
||||
}
|
||||
|
||||
|
||||
// Subset_Reader
|
||||
|
||||
Subset_Reader::Subset_Reader( Data_Reader* dr, int size ) :
|
||||
in( dr )
|
||||
{
|
||||
set_remain( min( size, dr->remain() ) );
|
||||
}
|
||||
|
||||
blargg_err_t Subset_Reader::read_v( void* p, int s )
|
||||
{
|
||||
return in->read( p, s );
|
||||
}
|
||||
|
||||
|
||||
// Remaining_Reader
|
||||
|
||||
Remaining_Reader::Remaining_Reader( void const* h, int size, Data_Reader* r ) :
|
||||
in( r )
|
||||
{
|
||||
header = h;
|
||||
header_remain = size;
|
||||
|
||||
set_remain( size + r->remain() );
|
||||
}
|
||||
|
||||
blargg_err_t Remaining_Reader::read_v( void* out, int count )
|
||||
{
|
||||
int first = min( count, header_remain );
|
||||
if ( first )
|
||||
{
|
||||
memcpy( out, header, first );
|
||||
header = STATIC_CAST(char const*, header) + first;
|
||||
header_remain -= first;
|
||||
}
|
||||
|
||||
return in->read( STATIC_CAST(char*, out) + first, count - first );
|
||||
}
|
||||
|
||||
|
||||
// Mem_File_Reader
|
||||
|
||||
Mem_File_Reader::Mem_File_Reader( const void* p, long s ) :
|
||||
begin( STATIC_CAST(const char*, p) )
|
||||
{
|
||||
set_size( s );
|
||||
}
|
||||
|
||||
blargg_err_t Mem_File_Reader::read_v( void* p, int s )
|
||||
{
|
||||
memcpy( p, begin + tell(), s );
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
blargg_err_t Mem_File_Reader::seek_v( int )
|
||||
{
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
|
||||
// Callback_Reader
|
||||
|
||||
Callback_Reader::Callback_Reader( callback_t c, long s, void* d ) :
|
||||
callback( c ),
|
||||
user_data( d )
|
||||
{
|
||||
set_remain( s );
|
||||
}
|
||||
|
||||
blargg_err_t Callback_Reader::read_v( void* out, int count )
|
||||
{
|
||||
return callback( user_data, out, count );
|
||||
}
|
||||
|
||||
|
||||
// Callback_File_Reader
|
||||
|
||||
Callback_File_Reader::Callback_File_Reader( callback_t c, long s, void* d ) :
|
||||
callback( c ),
|
||||
user_data( d )
|
||||
{
|
||||
set_size( s );
|
||||
}
|
||||
|
||||
blargg_err_t Callback_File_Reader::read_v( void* out, int count )
|
||||
{
|
||||
return callback( user_data, out, count, tell() );
|
||||
}
|
||||
|
||||
blargg_err_t Callback_File_Reader::seek_v( int )
|
||||
{
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
|
||||
// BLARGG_UTF8_PATHS
|
||||
|
||||
#if BLARGG_UTF8_PATHS
|
||||
|
||||
// Thanks to byuu for the idea for BLARGG_UTF8_PATHS and the implementations
|
||||
|
||||
// Converts wide-character path to UTF-8. Free result with free(). Only supported on Windows.
|
||||
char* blargg_to_utf8( const wchar_t* wpath )
|
||||
{
|
||||
if ( wpath == NULL )
|
||||
return NULL;
|
||||
|
||||
int needed = WideCharToMultiByte( CP_UTF8, 0, wpath, -1, NULL, 0, NULL, NULL );
|
||||
if ( needed <= 0 )
|
||||
return NULL;
|
||||
|
||||
char* path = (char*) malloc( needed );
|
||||
if ( path == NULL )
|
||||
return NULL;
|
||||
|
||||
int actual = WideCharToMultiByte( CP_UTF8, 0, wpath, -1, path, needed, NULL, NULL );
|
||||
if ( actual == 0 )
|
||||
{
|
||||
free( path );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
assert( actual == needed );
|
||||
return path;
|
||||
}
|
||||
|
||||
// Converts UTF-8 path to wide-character. Free result with free() Only supported on Windows.
|
||||
wchar_t* blargg_to_wide( const char* path )
|
||||
{
|
||||
if ( path == NULL )
|
||||
return NULL;
|
||||
|
||||
int needed = MultiByteToWideChar( CP_UTF8, 0, path, -1, NULL, 0 );
|
||||
if ( needed <= 0 )
|
||||
return NULL;
|
||||
|
||||
wchar_t* wpath = (wchar_t*) malloc( needed * sizeof *wpath );
|
||||
if ( wpath == NULL )
|
||||
return NULL;
|
||||
|
||||
int actual = MultiByteToWideChar( CP_UTF8, 0, path, -1, wpath, needed );
|
||||
if ( actual == 0 )
|
||||
{
|
||||
free( wpath );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
assert( actual == needed );
|
||||
return wpath;
|
||||
}
|
||||
|
||||
static FILE* blargg_fopen( const char path [], const char mode [] )
|
||||
{
|
||||
FILE* file = NULL;
|
||||
wchar_t* wmode = NULL;
|
||||
wchar_t* wpath = NULL;
|
||||
|
||||
wpath = blargg_to_wide( path );
|
||||
if ( wpath )
|
||||
{
|
||||
wmode = blargg_to_wide( mode );
|
||||
if ( wmode )
|
||||
file = _wfopen( wpath, wmode );
|
||||
}
|
||||
|
||||
// Save and restore errno in case free() clears it
|
||||
int saved_errno = errno;
|
||||
free( wmode );
|
||||
free( wpath );
|
||||
errno = saved_errno;
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline FILE* blargg_fopen( const char path [], const char mode [] )
|
||||
{
|
||||
return fopen( path, mode );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
// Std_File_Reader
|
||||
|
||||
Std_File_Reader::Std_File_Reader()
|
||||
{
|
||||
file_ = NULL;
|
||||
}
|
||||
|
||||
Std_File_Reader::~Std_File_Reader()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
static blargg_err_t blargg_fopen( FILE** out, const char path [] )
|
||||
{
|
||||
errno = 0;
|
||||
*out = blargg_fopen( path, "rb" );
|
||||
if ( !*out )
|
||||
{
|
||||
#ifdef ENOENT
|
||||
if ( errno == ENOENT )
|
||||
return blargg_err_file_missing;
|
||||
#endif
|
||||
#ifdef ENOMEM
|
||||
if ( errno == ENOMEM )
|
||||
return blargg_err_memory;
|
||||
#endif
|
||||
return blargg_err_file_read;
|
||||
}
|
||||
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
static blargg_err_t blargg_fsize( FILE* f, long* out )
|
||||
{
|
||||
if ( fseek( f, 0, SEEK_END ) )
|
||||
return blargg_err_file_io;
|
||||
|
||||
*out = ftell( f );
|
||||
if ( *out < 0 )
|
||||
return blargg_err_file_io;
|
||||
|
||||
if ( fseek( f, 0, SEEK_SET ) )
|
||||
return blargg_err_file_io;
|
||||
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
blargg_err_t Std_File_Reader::open( const char path [] )
|
||||
{
|
||||
close();
|
||||
|
||||
FILE* f;
|
||||
RETURN_ERR( blargg_fopen( &f, path ) );
|
||||
|
||||
long s;
|
||||
blargg_err_t err = blargg_fsize( f, &s );
|
||||
if ( err )
|
||||
{
|
||||
fclose( f );
|
||||
return err;
|
||||
}
|
||||
|
||||
file_ = f;
|
||||
set_size( s );
|
||||
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
void Std_File_Reader::make_unbuffered()
|
||||
{
|
||||
if ( setvbuf( STATIC_CAST(FILE*, file_), NULL, _IONBF, 0 ) )
|
||||
check( false ); // shouldn't fail, but OK if it does
|
||||
}
|
||||
|
||||
blargg_err_t Std_File_Reader::read_v( void* p, int s )
|
||||
{
|
||||
if ( (size_t) s != fread( p, 1, s, STATIC_CAST(FILE*, file_) ) )
|
||||
{
|
||||
// Data_Reader's wrapper should prevent EOF
|
||||
check( !feof( STATIC_CAST(FILE*, file_) ) );
|
||||
|
||||
return blargg_err_file_io;
|
||||
}
|
||||
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
blargg_err_t Std_File_Reader::seek_v( int n )
|
||||
{
|
||||
if ( fseek( STATIC_CAST(FILE*, file_), n, SEEK_SET ) )
|
||||
{
|
||||
// Data_Reader's wrapper should prevent EOF
|
||||
check( !feof( STATIC_CAST(FILE*, file_) ) );
|
||||
|
||||
return blargg_err_file_io;
|
||||
}
|
||||
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
void Std_File_Reader::close()
|
||||
{
|
||||
if ( file_ )
|
||||
{
|
||||
fclose( STATIC_CAST(FILE*, file_) );
|
||||
file_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Gzip_File_Reader
|
||||
|
||||
#ifdef HAVE_ZLIB_H
|
||||
|
||||
#include "zlib.h"
|
||||
|
||||
static const char* get_gzip_eof( const char path [], long* eof )
|
||||
{
|
||||
FILE* file;
|
||||
RETURN_ERR( blargg_fopen( &file, path ) );
|
||||
|
||||
int const h_size = 4;
|
||||
unsigned char h [h_size];
|
||||
|
||||
// read four bytes to ensure that we can seek to -4 later
|
||||
if ( fread( h, 1, h_size, file ) != (size_t) h_size || h[0] != 0x1F || h[1] != 0x8B )
|
||||
{
|
||||
// Not gzipped
|
||||
if ( ferror( file ) )
|
||||
return blargg_err_file_io;
|
||||
|
||||
if ( fseek( file, 0, SEEK_END ) )
|
||||
return blargg_err_file_io;
|
||||
|
||||
*eof = ftell( file );
|
||||
if ( *eof < 0 )
|
||||
return blargg_err_file_io;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Gzipped; get uncompressed size from end
|
||||
if ( fseek( file, -h_size, SEEK_END ) )
|
||||
return blargg_err_file_io;
|
||||
|
||||
if ( fread( h, 1, h_size, file ) != (size_t) h_size )
|
||||
return blargg_err_file_io;
|
||||
|
||||
*eof = get_le32( h );
|
||||
}
|
||||
|
||||
if ( fclose( file ) )
|
||||
check( false );
|
||||
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
Gzip_File_Reader::Gzip_File_Reader()
|
||||
{
|
||||
file_ = NULL;
|
||||
}
|
||||
|
||||
Gzip_File_Reader::~Gzip_File_Reader()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
blargg_err_t Gzip_File_Reader::open( const char path [] )
|
||||
{
|
||||
close();
|
||||
|
||||
long s;
|
||||
RETURN_ERR( get_gzip_eof( path, &s ) );
|
||||
|
||||
file_ = gzopen( path, "rb" );
|
||||
if ( !file_ )
|
||||
return blargg_err_file_read;
|
||||
|
||||
set_size( s );
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
static blargg_err_t convert_gz_error( gzFile file )
|
||||
{
|
||||
int err;
|
||||
gzerror( file, &err );
|
||||
|
||||
switch ( err )
|
||||
{
|
||||
case Z_STREAM_ERROR: break;
|
||||
case Z_DATA_ERROR: return blargg_err_file_corrupt;
|
||||
case Z_MEM_ERROR: return blargg_err_memory;
|
||||
case Z_BUF_ERROR: break;
|
||||
}
|
||||
return blargg_err_internal;
|
||||
}
|
||||
|
||||
blargg_err_t Gzip_File_Reader::read_v( void* p, int s )
|
||||
{
|
||||
int result = gzread( file_, p, s );
|
||||
if ( result != s )
|
||||
{
|
||||
if ( result < 0 )
|
||||
return convert_gz_error( file_ );
|
||||
|
||||
return blargg_err_file_corrupt;
|
||||
}
|
||||
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
blargg_err_t Gzip_File_Reader::seek_v( int n )
|
||||
{
|
||||
if ( gzseek( file_, n, SEEK_SET ) < 0 )
|
||||
return convert_gz_error( file_ );
|
||||
|
||||
return blargg_ok;
|
||||
}
|
||||
|
||||
void Gzip_File_Reader::close()
|
||||
{
|
||||
if ( file_ )
|
||||
{
|
||||
if ( gzclose( file_ ) )
|
||||
check( false );
|
||||
file_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -1,264 +0,0 @@
|
||||
// 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 +0,0 @@
|
||||
// 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 +0,0 @@
|
||||
// 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 +0,0 @@
|
||||
// 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 +0,0 @@
|
||||
// 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 +0,0 @@
|
||||
// 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 +0,0 @@
|
||||
// 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 +0,0 @@
|
||||
// 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 +0,0 @@
|
||||
// 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,252 +0,0 @@
|
||||
// File_Extractor 1.0.0. http://www.slack.net/~ant/
|
||||
|
||||
#include "Zip7_Extractor.h"
|
||||
|
||||
#include "7z_C/7zExtract.h"
|
||||
#include "7z_C/7zAlloc.h"
|
||||
#include "7z_C/7zCrc.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;
|
||||
}
|
||||
}
|
||||
|
||||
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 )
|
||||
{
|
||||
// TODO: Support date.
|
||||
// NTFS representation, stored as 64-bit value.
|
||||
// Divide by 10000000 (ten million) to get seconds
|
||||
//item.MTime.Low + (.High << 32)
|
||||
// How to convert to DOS style?
|
||||
|
||||
set_name( item.Name );
|
||||
set_info( item.Size, 0, (item.FileCRCDefined ? item.FileCRC : 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( SzAr_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,34 +0,0 @@
|
||||
// 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 );
|
||||
|
||||
private:
|
||||
Zip7_Extractor_Impl* impl;
|
||||
int index;
|
||||
|
||||
blargg_err_t zip7_err( int err );
|
||||
};
|
||||
|
||||
#endif
|
@ -1,390 +0,0 @@
|
||||
// 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 +0,0 @@
|
||||
// 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 +0,0 @@
|
||||
// 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 +0,0 @@
|
||||
// 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 +0,0 @@
|
||||
// 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,206 +0,0 @@
|
||||
// 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
|
||||
const char *const blargg_ok = (const char *const)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; }
|
||||
};
|
||||
|
||||
#ifndef _WIN32
|
||||
// Not supported on any other platforms
|
||||
#undef BLARGG_UTF8_PATHS
|
||||
#endif
|
||||
|
||||
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,34 +0,0 @@
|
||||
// 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_rar_type,\
|
||||
fex_zip_type,
|
||||
*/
|
||||
|
||||
// Use standard config.h if present
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,185 +0,0 @@
|
||||
// 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 +0,0 @@
|
||||
// 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 +0,0 @@
|
||||
// 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 +0,0 @@
|
||||
/* 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
|
323
fex/fex/fex.cpp
323
fex/fex/fex.cpp
@ -1,323 +0,0 @@
|
||||
// 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
|
||||
|
||||
#if BLARGG_UTF8_PATHS
|
||||
char* fex_wide_to_path( const wchar_t* wide )
|
||||
{
|
||||
return blargg_to_utf8( wide );
|
||||
}
|
||||
|
||||
void fex_free_path( char* path )
|
||||
{
|
||||
free( path );
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//// 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 ); }
|
206
fex/fex/fex.h
206
fex/fex/fex.h
@ -1,206 +0,0 @@
|
||||
/** 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 (Windows only) ****/
|
||||
|
||||
/** Converts wide-character path to form suitable for use with fex functions.
|
||||
Only supported when BLARGG_UTF8_PATHS is defined and building on Windows. */
|
||||
char* fex_wide_to_path( const wchar_t* wide );
|
||||
|
||||
/** Frees converted path. OK to pass NULL. Only supported when BLARGG_UTF8_PATHS
|
||||
is defined and building on Windows */
|
||||
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,97 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include "rar.hpp"
|
||||
|
||||
#include "unrar.h"
|
||||
|
||||
Archive::Archive() : Raw( this )
|
||||
{
|
||||
OldFormat=false;
|
||||
Solid=false;
|
||||
|
||||
CurBlockPos=0;
|
||||
NextBlockPos=0;
|
||||
|
||||
memset(&NewMhd,0,sizeof(NewMhd));
|
||||
NewMhd.HeadType=MAIN_HEAD;
|
||||
NewMhd.HeadSize=SIZEOF_NEWMHD;
|
||||
HeaderCRC=0;
|
||||
}
|
||||
|
||||
bool Archive::IsSignature(byte *D)
|
||||
{
|
||||
bool Valid=false;
|
||||
if (D[0]==0x52)
|
||||
#ifndef SFX_MODULE
|
||||
if (D[1]==0x45 && D[2]==0x7e && D[3]==0x5e)
|
||||
{
|
||||
OldFormat=true;
|
||||
Valid=true;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (D[1]==0x61 && D[2]==0x72 && D[3]==0x21 && D[4]==0x1a && D[5]==0x07 && D[6]==0x00)
|
||||
{
|
||||
OldFormat=false;
|
||||
Valid=true;
|
||||
}
|
||||
return(Valid);
|
||||
}
|
||||
|
||||
|
||||
unrar_err_t Archive::IsArchive()
|
||||
{
|
||||
if (Read(MarkHead.Mark,SIZEOF_MARKHEAD)!=SIZEOF_MARKHEAD)
|
||||
return unrar_err_not_arc;
|
||||
|
||||
if (IsSignature(MarkHead.Mark))
|
||||
{
|
||||
if (OldFormat)
|
||||
Seek(0,SEEK_SET);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SFXSize==0)
|
||||
return unrar_err_not_arc;
|
||||
}
|
||||
|
||||
unrar_err_t error =
|
||||
ReadHeader();
|
||||
// (no need to seek to next)
|
||||
if ( error != unrar_ok )
|
||||
return error;
|
||||
|
||||
#ifndef SFX_MODULE
|
||||
if (OldFormat)
|
||||
{
|
||||
NewMhd.Flags=OldMhd.Flags & 0x3f;
|
||||
NewMhd.HeadSize=OldMhd.HeadSize;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (HeaderCRC!=NewMhd.HeadCRC)
|
||||
{
|
||||
return unrar_err_corrupt;
|
||||
}
|
||||
}
|
||||
bool
|
||||
Volume=(NewMhd.Flags & MHD_VOLUME);
|
||||
Solid=(NewMhd.Flags & MHD_SOLID)!=0;
|
||||
bool
|
||||
Encrypted=(NewMhd.Flags & MHD_PASSWORD)!=0;
|
||||
|
||||
// (removed decryption and volume handling)
|
||||
|
||||
if ( Encrypted )
|
||||
return unrar_err_encrypted;
|
||||
|
||||
if ( Volume )
|
||||
return unrar_err_segmented;
|
||||
|
||||
return unrar_ok;
|
||||
}
|
||||
|
||||
void Archive::SeekToNext()
|
||||
{
|
||||
Seek(NextBlockPos,SEEK_SET);
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
#ifndef _RAR_ARCHIVE_
|
||||
#define _RAR_ARCHIVE_
|
||||
|
||||
typedef ComprDataIO File;
|
||||
#include "rawread.hpp"
|
||||
|
||||
class Archive:public File
|
||||
{
|
||||
private:
|
||||
bool IsSignature(byte *D);
|
||||
void ConvertUnknownHeader();
|
||||
int ReadOldHeader();
|
||||
|
||||
RawRead Raw;
|
||||
|
||||
MarkHeader MarkHead;
|
||||
OldMainHeader OldMhd;
|
||||
|
||||
int CurHeaderType;
|
||||
|
||||
public:
|
||||
Archive();
|
||||
unrar_err_t IsArchive();
|
||||
unrar_err_t ReadHeader();
|
||||
void SeekToNext();
|
||||
bool IsArcDir();
|
||||
bool IsArcLabel();
|
||||
int GetHeaderType() {return(CurHeaderType);};
|
||||
|
||||
BaseBlock ShortBlock;
|
||||
MainHeader NewMhd;
|
||||
FileHeader NewLhd;
|
||||
SubBlockHeader SubBlockHead;
|
||||
FileHeader SubHead;
|
||||
ProtectHeader ProtectHead;
|
||||
|
||||
Int64 CurBlockPos;
|
||||
Int64 NextBlockPos;
|
||||
|
||||
bool Solid;
|
||||
enum { SFXSize = 0 }; // self-extracting not supported
|
||||
ushort HeaderCRC;
|
||||
};
|
||||
|
||||
#endif
|
@ -1,314 +0,0 @@
|
||||
#include "rar.hpp"
|
||||
|
||||
#include "unrar.h"
|
||||
#include "unicode.hpp"
|
||||
#include "encname.hpp"
|
||||
|
||||
// arcread.cpp
|
||||
unrar_err_t Archive::ReadHeader()
|
||||
{
|
||||
CurBlockPos=Tell();
|
||||
|
||||
#ifndef SFX_MODULE
|
||||
if (OldFormat)
|
||||
{
|
||||
ReadOldHeader();
|
||||
|
||||
if ( Raw.Size() == 0 )
|
||||
return unrar_err_arc_eof; // right at end of file
|
||||
|
||||
if ( Raw.PaddedSize() > 0 ) // added check
|
||||
return unrar_err_corrupt; // missing data
|
||||
|
||||
return unrar_ok;
|
||||
}
|
||||
#endif
|
||||
|
||||
Raw.Reset();
|
||||
|
||||
// (removed decryption)
|
||||
|
||||
Raw.Read(SIZEOF_SHORTBLOCKHEAD);
|
||||
if (Raw.Size()==0)
|
||||
{
|
||||
return unrar_err_arc_eof; // right at end of file
|
||||
}
|
||||
|
||||
Raw.Get(ShortBlock.HeadCRC);
|
||||
byte HeadType;
|
||||
Raw.Get(HeadType);
|
||||
ShortBlock.HeadType=(HEADER_TYPE)HeadType;
|
||||
Raw.Get(ShortBlock.Flags);
|
||||
Raw.Get(ShortBlock.HeadSize);
|
||||
if (ShortBlock.HeadSize<SIZEOF_SHORTBLOCKHEAD)
|
||||
{
|
||||
return unrar_err_corrupt; // invalid HeadSize
|
||||
}
|
||||
|
||||
// catches unknown block types and reading something that isn't even a header
|
||||
check( MARK_HEAD <= ShortBlock.HeadType && ShortBlock.HeadType <= ENDARC_HEAD );
|
||||
|
||||
if (ShortBlock.HeadType==COMM_HEAD)
|
||||
Raw.Read(SIZEOF_COMMHEAD-SIZEOF_SHORTBLOCKHEAD);
|
||||
else
|
||||
if (ShortBlock.HeadType==MAIN_HEAD && (ShortBlock.Flags & MHD_COMMENT)!=0)
|
||||
Raw.Read(SIZEOF_NEWMHD-SIZEOF_SHORTBLOCKHEAD);
|
||||
else
|
||||
Raw.Read(ShortBlock.HeadSize-SIZEOF_SHORTBLOCKHEAD);
|
||||
|
||||
if ( Raw.PaddedSize() > 0 ) // fewer than requested bytes read above?
|
||||
return unrar_err_corrupt; // missing data
|
||||
|
||||
NextBlockPos=CurBlockPos+ShortBlock.HeadSize;
|
||||
|
||||
switch(ShortBlock.HeadType)
|
||||
{
|
||||
case MAIN_HEAD:
|
||||
*(BaseBlock *)&NewMhd=ShortBlock;
|
||||
Raw.Get(NewMhd.HighPosAV);
|
||||
Raw.Get(NewMhd.PosAV);
|
||||
check( Raw.ReadPos == Raw.DataSize ); // we should have read all fields
|
||||
break;
|
||||
case FILE_HEAD:
|
||||
case NEWSUB_HEAD:
|
||||
{
|
||||
FileHeader *hd=ShortBlock.HeadType==FILE_HEAD ? &NewLhd:&SubHead;
|
||||
*(BaseBlock *)hd=ShortBlock;
|
||||
Raw.Get(hd->PackSize);
|
||||
Raw.Get(hd->UnpSize);
|
||||
Raw.Get(hd->HostOS);
|
||||
Raw.Get(hd->FileCRC);
|
||||
Raw.Get(hd->FileTime);
|
||||
Raw.Get(hd->UnpVer);
|
||||
Raw.Get(hd->Method);
|
||||
Raw.Get(hd->NameSize);
|
||||
Raw.Get(hd->FileAttr);
|
||||
if (hd->Flags & LHD_LARGE)
|
||||
{
|
||||
Raw.Get(hd->HighPackSize);
|
||||
Raw.Get(hd->HighUnpSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
hd->HighPackSize=hd->HighUnpSize=0;
|
||||
if (hd->UnpSize==0xffffffff)
|
||||
{
|
||||
// TODO: what the heck is this for anyway?
|
||||
hd->UnpSize=0;
|
||||
hd->HighUnpSize=0x7fffffff;
|
||||
}
|
||||
}
|
||||
hd->FullPackSize=int32to64(hd->HighPackSize,hd->PackSize);
|
||||
hd->FullUnpSize=int32to64(hd->HighUnpSize,hd->UnpSize);
|
||||
|
||||
if ( int32to64( 1, 0 ) == 0 && (hd->HighPackSize || hd->HighUnpSize) )
|
||||
return unrar_err_huge;
|
||||
|
||||
char (&FileName) [sizeof hd->FileName] = hd->FileName; // eliminated local buffer
|
||||
int NameSize=Min(hd->NameSize,sizeof(FileName)-1);
|
||||
Raw.Get((byte *)FileName,NameSize);
|
||||
FileName[NameSize]=0;
|
||||
|
||||
if (hd->HeadType==NEWSUB_HEAD)
|
||||
{
|
||||
// have to adjust this, even through we're ignoring this block
|
||||
NextBlockPos+=hd->FullPackSize;
|
||||
break;
|
||||
}
|
||||
else
|
||||
if (hd->HeadType==FILE_HEAD)
|
||||
{
|
||||
if (hd->Flags & LHD_UNICODE)
|
||||
{
|
||||
EncodeFileName NameCoder;
|
||||
int Length=strlen(FileName);
|
||||
if (Length==hd->NameSize)
|
||||
{
|
||||
UtfToWide(FileName,hd->FileNameW,sizeof(hd->FileNameW)/sizeof(hd->FileNameW[0])-1);
|
||||
WideToChar(hd->FileNameW,hd->FileName,sizeof(hd->FileName)/sizeof(hd->FileName[0])-1);
|
||||
ExtToInt(hd->FileName,hd->FileName);
|
||||
}
|
||||
else
|
||||
{
|
||||
Length++;
|
||||
NameCoder.Decode(FileName,(byte *)FileName+Length,
|
||||
hd->NameSize-Length,hd->FileNameW,
|
||||
sizeof(hd->FileNameW)/sizeof(hd->FileNameW[0]));
|
||||
}
|
||||
if (*hd->FileNameW==0)
|
||||
hd->Flags &= ~LHD_UNICODE;
|
||||
}
|
||||
else
|
||||
*hd->FileNameW=0;
|
||||
|
||||
ConvertUnknownHeader();
|
||||
}
|
||||
if (hd->Flags & LHD_SALT)
|
||||
Raw.Get(hd->Salt,SALT_SIZE);
|
||||
hd->mtime.SetDos(hd->FileTime);
|
||||
if (hd->Flags & LHD_EXTTIME)
|
||||
{
|
||||
ushort Flags;
|
||||
Raw.Get(Flags);
|
||||
// Ignore additional time information
|
||||
for (int I=0;I<4;I++)
|
||||
{
|
||||
uint rmode=Flags>>(3-I)*4;
|
||||
if ((rmode & 8)==0)
|
||||
continue;
|
||||
if (I!=0)
|
||||
{
|
||||
uint DosTime;
|
||||
Raw.Get(DosTime);
|
||||
}
|
||||
|
||||
// skip time info
|
||||
int count=rmode&3;
|
||||
for (int J=0;J<count;J++)
|
||||
{
|
||||
byte CurByte;
|
||||
Raw.Get(CurByte);
|
||||
}
|
||||
}
|
||||
}
|
||||
NextBlockPos+=hd->FullPackSize;
|
||||
bool CRCProcessedOnly=(hd->Flags & LHD_COMMENT)!=0;
|
||||
HeaderCRC=~Raw.GetCRC(CRCProcessedOnly)&0xffff;
|
||||
if (hd->HeadCRC!=HeaderCRC)
|
||||
return unrar_err_corrupt;
|
||||
check( CRCProcessedOnly == false ); // I need to test on archives where this doesn't hold
|
||||
check( Raw.ReadPos == Raw.DataSize ); // we should have read all fields
|
||||
}
|
||||
break;
|
||||
#ifndef SFX_MODULE
|
||||
// Handle these block types just so we can adjust NextBlockPos properly
|
||||
case PROTECT_HEAD:
|
||||
Raw.Get(ProtectHead.DataSize);
|
||||
NextBlockPos+=ProtectHead.DataSize;
|
||||
break;
|
||||
case SUB_HEAD:
|
||||
Raw.Get(SubBlockHead.DataSize);
|
||||
NextBlockPos+=SubBlockHead.DataSize;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
if (ShortBlock.Flags & LONG_BLOCK)
|
||||
{
|
||||
uint DataSize;
|
||||
Raw.Get(DataSize);
|
||||
NextBlockPos+=DataSize;
|
||||
}
|
||||
break;
|
||||
}
|
||||
HeaderCRC=~Raw.GetCRC(false)&0xffff;
|
||||
CurHeaderType=ShortBlock.HeadType;
|
||||
// (removed decryption)
|
||||
|
||||
if (NextBlockPos<CurBlockPos+Raw.Size())
|
||||
return unrar_err_corrupt; // next block isn't past end of current block's header
|
||||
|
||||
// If pos went negative, then unrar_pos_t is only 32 bits and it overflowed
|
||||
if ( NextBlockPos < 0 )
|
||||
return unrar_err_huge;
|
||||
|
||||
return unrar_ok;
|
||||
}
|
||||
|
||||
// Rar.Read()s are checked by caller of ReadOldHeader() (see above)
|
||||
#ifndef SFX_MODULE
|
||||
int Archive::ReadOldHeader()
|
||||
{
|
||||
Raw.Reset();
|
||||
if (CurBlockPos<=SFXSize)
|
||||
{
|
||||
Raw.Read(SIZEOF_OLDMHD);
|
||||
Raw.Get(OldMhd.Mark,4);
|
||||
Raw.Get(OldMhd.HeadSize);
|
||||
Raw.Get(OldMhd.Flags);
|
||||
NextBlockPos=CurBlockPos+OldMhd.HeadSize;
|
||||
CurHeaderType=MAIN_HEAD;
|
||||
}
|
||||
else
|
||||
{
|
||||
OldFileHeader OldLhd;
|
||||
Raw.Read(SIZEOF_OLDLHD);
|
||||
NewLhd.HeadType=FILE_HEAD;
|
||||
Raw.Get(NewLhd.PackSize);
|
||||
Raw.Get(NewLhd.UnpSize);
|
||||
Raw.Get(OldLhd.FileCRC);
|
||||
Raw.Get(NewLhd.HeadSize);
|
||||
Raw.Get(NewLhd.FileTime);
|
||||
Raw.Get(OldLhd.FileAttr);
|
||||
Raw.Get(OldLhd.Flags);
|
||||
Raw.Get(OldLhd.UnpVer);
|
||||
Raw.Get(OldLhd.NameSize);
|
||||
Raw.Get(OldLhd.Method);
|
||||
|
||||
NewLhd.Flags=OldLhd.Flags|LONG_BLOCK;
|
||||
NewLhd.UnpVer=(OldLhd.UnpVer==2) ? 13 : 10;
|
||||
NewLhd.Method=OldLhd.Method+0x30;
|
||||
NewLhd.NameSize=OldLhd.NameSize;
|
||||
NewLhd.FileAttr=OldLhd.FileAttr;
|
||||
NewLhd.FileCRC=OldLhd.FileCRC;
|
||||
NewLhd.FullPackSize=NewLhd.PackSize;
|
||||
NewLhd.FullUnpSize=NewLhd.UnpSize;
|
||||
|
||||
NewLhd.mtime.SetDos(NewLhd.FileTime);
|
||||
// (removed other times)
|
||||
|
||||
Raw.Read(OldLhd.NameSize);
|
||||
Raw.Get((byte *)NewLhd.FileName,OldLhd.NameSize);
|
||||
NewLhd.FileName[OldLhd.NameSize]=0;
|
||||
// (removed name case conversion)
|
||||
*NewLhd.FileNameW=0;
|
||||
|
||||
if (Raw.Size()!=0)
|
||||
NextBlockPos=CurBlockPos+NewLhd.HeadSize+NewLhd.PackSize;
|
||||
CurHeaderType=FILE_HEAD;
|
||||
}
|
||||
return(NextBlockPos>CurBlockPos ? Raw.Size():0);
|
||||
}
|
||||
#endif
|
||||
|
||||
// (removed name case and attribute conversion)
|
||||
|
||||
bool Archive::IsArcDir()
|
||||
{
|
||||
return((NewLhd.Flags & LHD_WINDOWMASK)==LHD_DIRECTORY);
|
||||
}
|
||||
|
||||
|
||||
bool Archive::IsArcLabel()
|
||||
{
|
||||
return(NewLhd.HostOS<=HOST_WIN32 && (NewLhd.FileAttr & 8));
|
||||
}
|
||||
|
||||
// TODO: use '\\' on Windows?
|
||||
char const CPATHDIVIDER = '/';
|
||||
#define charnext(s) ((s)+1)
|
||||
|
||||
void Archive::ConvertUnknownHeader()
|
||||
{
|
||||
if (NewLhd.UnpVer<20 && (NewLhd.FileAttr & 0x10))
|
||||
NewLhd.Flags|=LHD_DIRECTORY;
|
||||
if (NewLhd.HostOS>=HOST_MAX)
|
||||
{
|
||||
if ((NewLhd.Flags & LHD_WINDOWMASK)==LHD_DIRECTORY)
|
||||
NewLhd.FileAttr=0x10;
|
||||
else
|
||||
NewLhd.FileAttr=0x20;
|
||||
}
|
||||
{
|
||||
for (char *s=NewLhd.FileName;*s!=0;s=charnext(s))
|
||||
{
|
||||
if (*s=='/' || *s=='\\')
|
||||
*s=CPATHDIVIDER;
|
||||
}
|
||||
}
|
||||
// (removed Apple Unicode handling)
|
||||
for (wchar *s=NewLhd.FileNameW;*s!=0;s++)
|
||||
{
|
||||
if (*s=='/' || *s=='\\')
|
||||
*s=CPATHDIVIDER;
|
||||
}
|
||||
}
|
@ -1,135 +0,0 @@
|
||||
#ifndef _RAR_ARRAY_
|
||||
#define _RAR_ARRAY_
|
||||
|
||||
template <class T> class Array
|
||||
{
|
||||
private:
|
||||
T *Buffer;
|
||||
int BufSize;
|
||||
int AllocSize;
|
||||
public:
|
||||
Rar_Error_Handler& ErrHandler;
|
||||
Array(Rar_Error_Handler*);
|
||||
Array(int Size,Rar_Error_Handler*);
|
||||
~Array();
|
||||
inline void CleanData();
|
||||
inline T& operator [](int Item);
|
||||
inline int Size();
|
||||
void Add(int Items);
|
||||
void Alloc(int Items);
|
||||
void Reset();
|
||||
void operator = (Array<T> &Src);
|
||||
void Push(T Item);
|
||||
T* Addr() {return(Buffer);}
|
||||
};
|
||||
|
||||
template <class T> void Array<T>::CleanData()
|
||||
{
|
||||
Buffer=NULL;
|
||||
BufSize=0;
|
||||
AllocSize=0;
|
||||
}
|
||||
|
||||
|
||||
template <class T> Array<T>::Array(Rar_Error_Handler* eh) : ErrHandler( *eh )
|
||||
{
|
||||
CleanData();
|
||||
}
|
||||
|
||||
|
||||
template <class T> Array<T>::Array(int Size, Rar_Error_Handler* eh) : ErrHandler( *eh )
|
||||
{
|
||||
Buffer=(T *)rarmalloc(sizeof(T)*Size);
|
||||
if (Buffer==NULL && Size!=0)
|
||||
ErrHandler.MemoryError();
|
||||
|
||||
AllocSize=BufSize=Size;
|
||||
}
|
||||
|
||||
|
||||
template <class T> Array<T>::~Array()
|
||||
{
|
||||
if (Buffer!=NULL)
|
||||
rarfree(Buffer);
|
||||
}
|
||||
|
||||
|
||||
template <class T> inline T& Array<T>::operator [](int Item)
|
||||
{
|
||||
return(Buffer[Item]);
|
||||
}
|
||||
|
||||
|
||||
template <class T> inline int Array<T>::Size()
|
||||
{
|
||||
return(BufSize);
|
||||
}
|
||||
|
||||
|
||||
template <class T> void Array<T>::Add(int Items)
|
||||
{
|
||||
int BufSize = this->BufSize; // don't change actual vars until alloc succeeds
|
||||
T* Buffer = this->Buffer;
|
||||
|
||||
BufSize+=Items;
|
||||
if (BufSize>AllocSize)
|
||||
{
|
||||
int Suggested=AllocSize+AllocSize/4+32;
|
||||
int NewSize=Max(BufSize,Suggested);
|
||||
|
||||
Buffer=(T *)rarrealloc(Buffer,NewSize*sizeof(T));
|
||||
if (Buffer==NULL)
|
||||
ErrHandler.MemoryError();
|
||||
AllocSize=NewSize;
|
||||
}
|
||||
|
||||
this->Buffer = Buffer;
|
||||
this->BufSize = BufSize;
|
||||
}
|
||||
|
||||
|
||||
template <class T> void Array<T>::Alloc(int Items)
|
||||
{
|
||||
if (Items>AllocSize)
|
||||
Add(Items-BufSize);
|
||||
else
|
||||
BufSize=Items;
|
||||
}
|
||||
|
||||
|
||||
template <class T> void Array<T>::Reset()
|
||||
{
|
||||
// Keep memory allocated if it's small
|
||||
// Eliminates constant reallocation when scanning archive
|
||||
if ( AllocSize < 1024/sizeof(T) )
|
||||
{
|
||||
BufSize = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Buffer!=NULL)
|
||||
{
|
||||
rarfree(Buffer);
|
||||
Buffer=NULL;
|
||||
}
|
||||
BufSize=0;
|
||||
AllocSize=0;
|
||||
}
|
||||
|
||||
|
||||
template <class T> void Array<T>::operator =(Array<T> &Src)
|
||||
{
|
||||
Reset();
|
||||
Alloc(Src.BufSize);
|
||||
if (Src.BufSize!=0)
|
||||
memcpy((void *)Buffer,(void *)Src.Buffer,Src.BufSize*sizeof(T));
|
||||
}
|
||||
|
||||
|
||||
template <class T> void Array<T>::Push(T Item)
|
||||
{
|
||||
Add(1);
|
||||
(*this)[Size()-1]=Item;
|
||||
}
|
||||
|
||||
#endif
|
@ -1,141 +0,0 @@
|
||||
unrar_core source code changes
|
||||
------------------------------
|
||||
Unrar_core is based on UnRAR (unrarsrc-3.8.5.tar.gz) by Alexander L.
|
||||
Roshal. The original sources have been HEAVILY modified, trimmed down,
|
||||
and purged of all OS-specific calls for file access and other
|
||||
unnecessary operations. Support for encryption, recovery records, and
|
||||
segmentation has been REMOVED. See license.txt for licensing. In
|
||||
particular, this code cannot be used to re-create the RAR compression
|
||||
algorithm, which is proprietary.
|
||||
|
||||
If you obtained this code as a part of my File_Extractor library and
|
||||
want to use it on its own, get my unrar_core library, which includes
|
||||
examples and documentation.
|
||||
|
||||
The source is as close as possible to the original, to make it simple to
|
||||
update when a new version of UnRAR comes out. In many places the
|
||||
original names and object nesting are kept, even though it's a bit
|
||||
harder to follow. See rar.hpp for the main "glue".
|
||||
|
||||
Website: http://www.slack.net/~ant/
|
||||
E-mail : Shay Green <gblargg@gmail.com>
|
||||
|
||||
|
||||
Contents
|
||||
--------
|
||||
* Diff-friendly changes
|
||||
* Removal of features
|
||||
* Error reporting changes
|
||||
* Minor tweaks
|
||||
* Unrar findings
|
||||
|
||||
|
||||
Diff-friendly changes
|
||||
---------------------
|
||||
To make my source code changes more easily visible with a line-based
|
||||
file diff, I've tried to make changes by inserting or deleting lines,
|
||||
rather than modifying them. So if the original declared a static array
|
||||
|
||||
static int array [4] = { 1, 2, 3, 4 };
|
||||
|
||||
and I want to make it const, I add the const on a line before
|
||||
|
||||
const // added
|
||||
static int array [4] = { 1, 2, 3, 4 };
|
||||
|
||||
rather than on the same line
|
||||
|
||||
static const int array [4] = { 1, 2, 3, 4 };
|
||||
|
||||
This way a diff will simply show an added line, making it clear what was
|
||||
added. If I simply inserted const on the same line, it wouldn't be as
|
||||
clear what all I had changed.
|
||||
|
||||
I've also made use of several macros rather than changing the source
|
||||
text. For example, since a class name like Unpack might easily conflict,
|
||||
I've renamed it to Rar_Unpack by using #define Unpack Rar_Unpack rather
|
||||
than changing the source text. These macros are only defined when
|
||||
compiling the library sources; the user-visible unrar.h is very clean.
|
||||
|
||||
|
||||
Removal of features
|
||||
-------------------
|
||||
This library is meant for simple access to common archives without
|
||||
having to extract them first. Encryption, segmentation, huge files, and
|
||||
self-extracting archives aren't common for things that need to be
|
||||
accessed in this manner, so I've removed support for them. Also,
|
||||
encryption adds complexity to the code that must be maintained.
|
||||
Segmentation would require a way to specify the other segments.
|
||||
|
||||
|
||||
Error reporting changes
|
||||
-----------------------
|
||||
The original used C++ exceptions to report errors. I've eliminated use
|
||||
of these through a combination of error codes and longjmp. This allows
|
||||
use of the library from C or some other language which doesn't easily
|
||||
support exceptions.
|
||||
|
||||
I tried to make as few changes as possible in the conversion. Due to the
|
||||
number of places file reads occur, propagating an error code via return
|
||||
statements would have required too many code changes. Instead, I perform
|
||||
the read, save the error code, and return 0 bytes read in case of an
|
||||
error. I also ensure that the calling code interprets this zero in an
|
||||
acceptable way. I then check this saved error code after the operation
|
||||
completes, and have it take priority over the error the RAR code
|
||||
returned. I do a similar thing for write errors.
|
||||
|
||||
|
||||
Minor tweaks
|
||||
------------
|
||||
- Eliminated as many GCC warnings as reasonably possible.
|
||||
|
||||
- Non-class array allocations now use malloc(), allowing the code to be
|
||||
linked without the standard C++ library (particularly, operator new).
|
||||
Class object allocations use a class-specific allocator that just calls
|
||||
malloc(), also avoiding calls to operator new.
|
||||
|
||||
- Made all unchanging static data const. Several pieces of static data
|
||||
in the original code weren't marked const where they could be.
|
||||
|
||||
- Initialization of some static tables was done on an as-needed basis,
|
||||
creating a problem when extracting from archives in multiple threads.
|
||||
This initialization can now be done by the user before any archives are
|
||||
opened.
|
||||
|
||||
- Tweaked CopyString, the major bottleneck during compression. I inlined
|
||||
it, cached some variables in locals in case the compiler couldn't easily
|
||||
see that the memory accesses don't modify them, and made them use
|
||||
memcpy() where possible. This improved performance by at least 20% on
|
||||
x86. Perhaps it won't work as well on files with lots of smaller string
|
||||
matches.
|
||||
|
||||
- Some .cpp files are #included by others. I've added guards to these so
|
||||
that you can simply compile all .cpp files and not get any redefinition
|
||||
errors.
|
||||
|
||||
- The current solid extraction position is kept track of, allowing the
|
||||
user to randomly extract files without regard to proper extraction
|
||||
order. The library optimizes solid extraction and only restarts it if
|
||||
the user is extracting a file earlier in the archive than the last
|
||||
solid-extracted one.
|
||||
|
||||
- Most of the time a solid file's data is already contiguously in the
|
||||
internal Unpack::Window, which unrar_extract_mem() takes advantage of.
|
||||
This avoids extra allocation in many cases.
|
||||
|
||||
- Allocation of Unpack is delayed until the first extraction, rather
|
||||
than being allocated immediately on opening the archive. This allows
|
||||
scanning with minimal memory usage.
|
||||
|
||||
|
||||
Unrar findings
|
||||
--------------
|
||||
- Apparently the LHD_SOLID flag indicates that file depends on previous
|
||||
files, rather than that later files depend on the current file's
|
||||
contents. Thus this flag can't be used to intelligently decide which
|
||||
files need to be internally extracted when skipping them, making it
|
||||
necessary to internally extract every file before the one to be
|
||||
extracted, if the archive is solid.
|
||||
|
||||
--
|
||||
Shay Green <gblargg@gmail.com>
|
@ -1,49 +0,0 @@
|
||||
// #included by unpack.cpp
|
||||
#ifdef RAR_COMMON_HPP
|
||||
|
||||
inline unsigned int RangeCoder::GetChar()
|
||||
{
|
||||
return(UnpackRead->GetChar());
|
||||
}
|
||||
|
||||
|
||||
void RangeCoder::InitDecoder(Unpack *UnpackRead)
|
||||
{
|
||||
RangeCoder::UnpackRead=UnpackRead;
|
||||
|
||||
low=code=0;
|
||||
range=uint(-1);
|
||||
for (int i=0;i < 4;i++)
|
||||
code=(code << 8) | GetChar();
|
||||
}
|
||||
|
||||
|
||||
#define ARI_DEC_NORMALIZE(code,low,range,read) \
|
||||
{ \
|
||||
while ((low^(low+range))<TOP || range<BOT && ((range=-low&(BOT-1)),1)) \
|
||||
{ \
|
||||
code=(code << 8) | read->GetChar(); \
|
||||
range <<= 8; \
|
||||
low <<= 8; \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
inline int RangeCoder::GetCurrentCount()
|
||||
{
|
||||
return (code-low)/(range /= SubRange.scale);
|
||||
}
|
||||
|
||||
|
||||
inline uint RangeCoder::GetCurrentShiftCount(uint SHIFT)
|
||||
{
|
||||
return (code-low)/(range >>= SHIFT);
|
||||
}
|
||||
|
||||
|
||||
inline void RangeCoder::Decode()
|
||||
{
|
||||
low += range*SubRange.LowCount;
|
||||
range *= SubRange.HighCount-SubRange.LowCount;
|
||||
}
|
||||
#endif
|
@ -1,24 +0,0 @@
|
||||
/****************************************************************************
|
||||
* Contents: 'Carryless rangecoder' by Dmitry Subbotin *
|
||||
****************************************************************************/
|
||||
|
||||
const uint TOP=1 << 24, BOT=1 << 15;
|
||||
|
||||
class RangeCoder
|
||||
{
|
||||
public:
|
||||
void InitDecoder(Unpack *UnpackRead);
|
||||
inline int GetCurrentCount();
|
||||
inline uint GetCurrentShiftCount(uint SHIFT);
|
||||
inline void Decode();
|
||||
inline void PutChar(unsigned int c);
|
||||
inline unsigned int GetChar();
|
||||
|
||||
uint low, code, range;
|
||||
struct SUBRANGE
|
||||
{
|
||||
uint LowCount, HighCount, scale;
|
||||
} SubRange;
|
||||
|
||||
Unpack *UnpackRead;
|
||||
};
|
@ -1,36 +0,0 @@
|
||||
#ifndef _RAR_COMPRESS_
|
||||
#define _RAR_COMPRESS_
|
||||
|
||||
class ComprDataIO;
|
||||
class PackingFileTable;
|
||||
|
||||
#define CODEBUFSIZE 0x4000
|
||||
#define MAXWINSIZE 0x400000
|
||||
#define MAXWINMASK (MAXWINSIZE-1)
|
||||
|
||||
#define LOW_DIST_REP_COUNT 16
|
||||
|
||||
#define NC 299 /* alphabet = {0, 1, 2, ..., NC - 1} */
|
||||
#define DC 60
|
||||
#define LDC 17
|
||||
#define RC 28
|
||||
#define HUFF_TABLE_SIZE (NC+DC+RC+LDC)
|
||||
#define BC 20
|
||||
|
||||
#define NC20 298 /* alphabet = {0, 1, 2, ..., NC - 1} */
|
||||
#define DC20 48
|
||||
#define RC20 28
|
||||
#define BC20 19
|
||||
#define MC20 257
|
||||
|
||||
enum {CODE_HUFFMAN,CODE_LZ,CODE_LZ2,CODE_REPEATLZ,CODE_CACHELZ,
|
||||
CODE_STARTFILE,CODE_ENDFILE,CODE_VM,CODE_VMDATA};
|
||||
|
||||
|
||||
enum FilterType {
|
||||
FILTER_NONE, FILTER_PPM /*dummy*/, FILTER_E8, FILTER_E8E9,
|
||||
FILTER_UPCASETOLOW, FILTER_AUDIO, FILTER_RGB, FILTER_DELTA,
|
||||
FILTER_ITANIUM, FILTER_E8E9V2
|
||||
};
|
||||
|
||||
#endif
|
@ -1,69 +0,0 @@
|
||||
#include "rar.hpp"
|
||||
|
||||
uint CRCTab[256];
|
||||
|
||||
void InitCRC()
|
||||
{
|
||||
for (int I=0;I<256;I++)
|
||||
{
|
||||
uint C=I;
|
||||
for (int J=0;J<8;J++)
|
||||
C=(C & 1) ? (C>>1)^0xEDB88320L : (C>>1);
|
||||
CRCTab[I]=C;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint CRC(uint StartCRC,const void *Addr,size_t Size)
|
||||
{
|
||||
// Always initialized ahead of time, and this func call makes it a non-leaf func.
|
||||
if (false)
|
||||
if (CRCTab[1]==0)
|
||||
InitCRC();
|
||||
byte *Data=(byte *)Addr;
|
||||
#if defined(LITTLE_ENDIAN) && defined(PRESENT_INT32) && defined(ALLOW_NOT_ALIGNED_INT)
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// avoid a warning about 'Data' pointer truncation in 64 bit mode
|
||||
#pragma warning( disable : 4311 )
|
||||
#endif
|
||||
|
||||
while (Size>0 && ((long)Data & 7))
|
||||
{
|
||||
StartCRC=CRCTab[(byte)(StartCRC^Data[0])]^(StartCRC>>8);
|
||||
Size--;
|
||||
Data++;
|
||||
}
|
||||
while (Size>=8)
|
||||
{
|
||||
StartCRC^=*(uint32 *)Data;
|
||||
StartCRC=CRCTab[(byte)StartCRC]^(StartCRC>>8);
|
||||
StartCRC=CRCTab[(byte)StartCRC]^(StartCRC>>8);
|
||||
StartCRC=CRCTab[(byte)StartCRC]^(StartCRC>>8);
|
||||
StartCRC=CRCTab[(byte)StartCRC]^(StartCRC>>8);
|
||||
StartCRC^=*(uint32 *)(Data+4);
|
||||
StartCRC=CRCTab[(byte)StartCRC]^(StartCRC>>8);
|
||||
StartCRC=CRCTab[(byte)StartCRC]^(StartCRC>>8);
|
||||
StartCRC=CRCTab[(byte)StartCRC]^(StartCRC>>8);
|
||||
StartCRC=CRCTab[(byte)StartCRC]^(StartCRC>>8);
|
||||
Data+=8;
|
||||
Size-=8;
|
||||
}
|
||||
#endif
|
||||
for (size_t I=0;I<Size;I++)
|
||||
StartCRC=CRCTab[(byte)(StartCRC^Data[I])]^(StartCRC>>8);
|
||||
return(StartCRC);
|
||||
}
|
||||
|
||||
#ifndef SFX_MODULE
|
||||
ushort OldCRC(ushort StartCRC,const void *Addr,size_t Size)
|
||||
{
|
||||
byte *Data=(byte *)Addr;
|
||||
for (size_t I=0;I<Size;I++)
|
||||
{
|
||||
StartCRC=(StartCRC+Data[I])&0xffff;
|
||||
StartCRC=((StartCRC<<1)|(StartCRC>>15))&0xffff;
|
||||
}
|
||||
return(StartCRC);
|
||||
}
|
||||
#endif
|
@ -1,57 +0,0 @@
|
||||
#include "rar.hpp"
|
||||
|
||||
EncodeFileName::EncodeFileName()
|
||||
{
|
||||
Flags=0;
|
||||
FlagBits=0;
|
||||
FlagsPos=0;
|
||||
DestSize=0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void EncodeFileName::Decode(char *Name,byte *EncName,int EncSize,wchar *NameW,
|
||||
int MaxDecSize)
|
||||
{
|
||||
int EncPos=0,DecPos=0;
|
||||
byte HighByte=EncName[EncPos++];
|
||||
while (EncPos<EncSize && DecPos<MaxDecSize)
|
||||
{
|
||||
if (FlagBits==0)
|
||||
{
|
||||
Flags=EncName[EncPos++];
|
||||
FlagBits=8;
|
||||
}
|
||||
switch(Flags>>6)
|
||||
{
|
||||
case 0:
|
||||
NameW[DecPos++]=EncName[EncPos++];
|
||||
break;
|
||||
case 1:
|
||||
NameW[DecPos++]=EncName[EncPos++]+(HighByte<<8);
|
||||
break;
|
||||
case 2:
|
||||
NameW[DecPos++]=EncName[EncPos]+(EncName[EncPos+1]<<8);
|
||||
EncPos+=2;
|
||||
break;
|
||||
case 3:
|
||||
{
|
||||
int Length=EncName[EncPos++];
|
||||
if (Length & 0x80)
|
||||
{
|
||||
byte Correction=EncName[EncPos++];
|
||||
for (Length=(Length&0x7f)+2;Length>0 && DecPos<MaxDecSize;Length--,DecPos++)
|
||||
NameW[DecPos]=((Name[DecPos]+Correction)&0xff)+(HighByte<<8);
|
||||
}
|
||||
else
|
||||
for (Length+=2;Length>0 && DecPos<MaxDecSize;Length--,DecPos++)
|
||||
NameW[DecPos]=Name[DecPos];
|
||||
}
|
||||
break;
|
||||
}
|
||||
Flags<<=2;
|
||||
FlagBits-=2;
|
||||
}
|
||||
NameW[DecPos<MaxDecSize ? DecPos:MaxDecSize-1]=0;
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
#ifndef _RAR_ENCNAME_
|
||||
#define _RAR_ENCNAME_
|
||||
|
||||
class EncodeFileName
|
||||
{
|
||||
private:
|
||||
void AddFlags(int Value);
|
||||
|
||||
byte *EncName;
|
||||
byte Flags;
|
||||
int FlagBits;
|
||||
int FlagsPos;
|
||||
int DestSize;
|
||||
public:
|
||||
EncodeFileName();
|
||||
int Encode(char *Name,wchar *NameW,byte *EncName);
|
||||
void Decode(char *Name,byte *EncName,int EncSize,wchar *NameW,int MaxDecSize);
|
||||
};
|
||||
|
||||
#endif
|
@ -1,110 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include "rar.hpp"
|
||||
|
||||
#include "unrar.h"
|
||||
|
||||
#define DataIO Arc
|
||||
|
||||
unrar_err_t CmdExtract::ExtractCurrentFile( bool SkipSolid, bool check_compatibility_only )
|
||||
{
|
||||
check( Arc.GetHeaderType() == FILE_HEAD );
|
||||
|
||||
if ( Arc.NewLhd.Flags & (LHD_SPLIT_AFTER | LHD_SPLIT_BEFORE) )
|
||||
return unrar_err_segmented;
|
||||
|
||||
if ( Arc.NewLhd.Flags & LHD_PASSWORD )
|
||||
return unrar_err_encrypted;
|
||||
|
||||
if ( !check_compatibility_only )
|
||||
{
|
||||
check( Arc.NextBlockPos-Arc.NewLhd.FullPackSize == Arc.Tell() );
|
||||
Arc.Seek(Arc.NextBlockPos-Arc.NewLhd.FullPackSize,SEEK_SET);
|
||||
}
|
||||
|
||||
// (removed lots of command-line handling)
|
||||
|
||||
#ifdef SFX_MODULE
|
||||
if ((Arc.NewLhd.UnpVer!=UNP_VER && Arc.NewLhd.UnpVer!=29) &&
|
||||
Arc.NewLhd.Method!=0x30)
|
||||
#else
|
||||
if (Arc.NewLhd.UnpVer<13 || Arc.NewLhd.UnpVer>UNP_VER)
|
||||
#endif
|
||||
{
|
||||
if (Arc.NewLhd.UnpVer>UNP_VER)
|
||||
return unrar_err_new_algo;
|
||||
return unrar_err_old_algo;
|
||||
}
|
||||
|
||||
if ( check_compatibility_only )
|
||||
return unrar_ok;
|
||||
|
||||
// (removed lots of command-line/encryption/volume handling)
|
||||
|
||||
update_first_file_pos();
|
||||
FileCount++;
|
||||
DataIO.UnpFileCRC=Arc.OldFormat ? 0 : 0xffffffff;
|
||||
// (removed decryption)
|
||||
DataIO.SetPackedSizeToRead(Arc.NewLhd.FullPackSize);
|
||||
// (removed command-line handling)
|
||||
DataIO.SetSkipUnpCRC(SkipSolid);
|
||||
|
||||
if (Arc.NewLhd.Method==0x30)
|
||||
UnstoreFile(Arc.NewLhd.FullUnpSize);
|
||||
else
|
||||
{
|
||||
// Defer creation of Unpack until first extraction
|
||||
if ( !Unp )
|
||||
{
|
||||
Unp = new Unpack( &Arc );
|
||||
if ( !Unp )
|
||||
return unrar_err_memory;
|
||||
|
||||
Unp->Init( NULL );
|
||||
}
|
||||
|
||||
Unp->SetDestSize(Arc.NewLhd.FullUnpSize);
|
||||
#ifndef SFX_MODULE
|
||||
if (Arc.NewLhd.UnpVer<=15)
|
||||
Unp->DoUnpack(15,FileCount>1 && Arc.Solid);
|
||||
else
|
||||
#endif
|
||||
Unp->DoUnpack(Arc.NewLhd.UnpVer,Arc.NewLhd.Flags & LHD_SOLID);
|
||||
}
|
||||
|
||||
// (no need to seek to next file)
|
||||
|
||||
if (!SkipSolid)
|
||||
{
|
||||
if (Arc.OldFormat && UINT32(DataIO.UnpFileCRC)==UINT32(Arc.NewLhd.FileCRC) ||
|
||||
!Arc.OldFormat && UINT32(DataIO.UnpFileCRC)==UINT32(Arc.NewLhd.FileCRC^0xffffffff))
|
||||
{
|
||||
// CRC is correct
|
||||
}
|
||||
else
|
||||
{
|
||||
return unrar_err_corrupt;
|
||||
}
|
||||
}
|
||||
|
||||
// (removed broken file handling)
|
||||
// (removed command-line handling)
|
||||
|
||||
return unrar_ok;
|
||||
}
|
||||
|
||||
|
||||
void CmdExtract::UnstoreFile(Int64 DestUnpSize)
|
||||
{
|
||||
Buffer.Alloc(Min(DestUnpSize,0x10000));
|
||||
while (1)
|
||||
{
|
||||
unsigned int Code=DataIO.UnpRead(&Buffer[0],Buffer.Size());
|
||||
if (Code==0 || (int)Code==-1)
|
||||
break;
|
||||
Code=Code<DestUnpSize ? Code:int64to32(DestUnpSize);
|
||||
DataIO.UnpWrite(&Buffer[0],Code);
|
||||
if (DestUnpSize>=0)
|
||||
DestUnpSize-=Code;
|
||||
}
|
||||
Buffer.Reset();
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
#include "rar.hpp"
|
||||
|
||||
BitInput::BitInput()
|
||||
{
|
||||
InBuf = (byte*) rarmalloc( MAX_SIZE );
|
||||
|
||||
// Otherwise getbits() reads uninitialized memory
|
||||
// TODO: instead of clearing entire block, just clear last two
|
||||
// bytes after reading from file
|
||||
if ( InBuf )
|
||||
memset( InBuf, 0, MAX_SIZE );
|
||||
}
|
||||
|
||||
BitInput::~BitInput()
|
||||
{
|
||||
rarfree( InBuf );
|
||||
}
|
||||
|
||||
void BitInput::handle_mem_error( Rar_Error_Handler& ErrHandler )
|
||||
{
|
||||
if ( !InBuf )
|
||||
ErrHandler.MemoryError();
|
||||
}
|
||||
|
||||
void BitInput::faddbits(int Bits)
|
||||
{
|
||||
addbits(Bits);
|
||||
}
|
||||
|
||||
|
||||
unsigned int BitInput::fgetbits()
|
||||
{
|
||||
return(getbits());
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
#ifndef _RAR_GETBITS_
|
||||
#define _RAR_GETBITS_
|
||||
|
||||
class BitInput
|
||||
: public Rar_Allocator
|
||||
{
|
||||
public:
|
||||
enum BufferSize {MAX_SIZE=0x8000};
|
||||
protected:
|
||||
int InAddr,InBit;
|
||||
public:
|
||||
BitInput();
|
||||
~BitInput();
|
||||
void handle_mem_error( Rar_Error_Handler& );
|
||||
|
||||
byte *InBuf;
|
||||
|
||||
void InitBitInput()
|
||||
{
|
||||
InAddr=InBit=0;
|
||||
}
|
||||
void addbits(int Bits)
|
||||
{
|
||||
Bits+=InBit;
|
||||
InAddr+=Bits>>3;
|
||||
InBit=Bits&7;
|
||||
}
|
||||
unsigned int getbits()
|
||||
{
|
||||
unsigned int BitField=(uint)InBuf[InAddr] << 16;
|
||||
BitField|=(uint)InBuf[InAddr+1] << 8;
|
||||
BitField|=(uint)InBuf[InAddr+2];
|
||||
BitField >>= (8-InBit);
|
||||
return(BitField & 0xffff);
|
||||
}
|
||||
void faddbits(int Bits);
|
||||
unsigned int fgetbits();
|
||||
bool Overflow(int IncPtr) {return(InAddr+IncPtr>=MAX_SIZE);}
|
||||
};
|
||||
#endif
|
@ -1,145 +0,0 @@
|
||||
#ifndef _RAR_HEADERS_
|
||||
#define _RAR_HEADERS_
|
||||
|
||||
#define SIZEOF_MARKHEAD 7
|
||||
#define SIZEOF_OLDMHD 7
|
||||
#define SIZEOF_NEWMHD 13
|
||||
#define SIZEOF_OLDLHD 21
|
||||
#define SIZEOF_NEWLHD 32
|
||||
#define SIZEOF_SHORTBLOCKHEAD 7
|
||||
#define SIZEOF_SUBBLOCKHEAD 14
|
||||
#define SIZEOF_COMMHEAD 13
|
||||
|
||||
#define UNP_VER 36
|
||||
|
||||
#define MHD_VOLUME 0x0001
|
||||
#define MHD_COMMENT 0x0002
|
||||
#define MHD_SOLID 0x0008
|
||||
#define MHD_PASSWORD 0x0080
|
||||
|
||||
#define LHD_SPLIT_BEFORE 0x0001
|
||||
#define LHD_SPLIT_AFTER 0x0002
|
||||
#define LHD_PASSWORD 0x0004
|
||||
#define LHD_COMMENT 0x0008
|
||||
#define LHD_SOLID 0x0010
|
||||
|
||||
#define LHD_WINDOWMASK 0x00e0
|
||||
#define LHD_DIRECTORY 0x00e0
|
||||
|
||||
#define LHD_LARGE 0x0100
|
||||
#define LHD_UNICODE 0x0200
|
||||
#define LHD_SALT 0x0400
|
||||
#define LHD_EXTTIME 0x1000
|
||||
|
||||
#define LONG_BLOCK 0x8000
|
||||
|
||||
enum HEADER_TYPE {
|
||||
MARK_HEAD=0x72,MAIN_HEAD=0x73,FILE_HEAD=0x74,COMM_HEAD=0x75,AV_HEAD=0x76,
|
||||
SUB_HEAD=0x77,PROTECT_HEAD=0x78,SIGN_HEAD=0x79,NEWSUB_HEAD=0x7a,
|
||||
ENDARC_HEAD=0x7b
|
||||
};
|
||||
|
||||
enum HOST_SYSTEM {
|
||||
HOST_MSDOS=0,HOST_OS2=1,HOST_WIN32=2,HOST_UNIX=3,HOST_MACOS=4,
|
||||
HOST_BEOS=5,HOST_MAX
|
||||
};
|
||||
|
||||
struct OldMainHeader
|
||||
{
|
||||
byte Mark[4];
|
||||
ushort HeadSize;
|
||||
byte Flags;
|
||||
};
|
||||
|
||||
|
||||
struct OldFileHeader
|
||||
{
|
||||
uint PackSize;
|
||||
uint UnpSize;
|
||||
ushort FileCRC;
|
||||
ushort HeadSize;
|
||||
uint FileTime;
|
||||
byte FileAttr;
|
||||
byte Flags;
|
||||
byte UnpVer;
|
||||
byte NameSize;
|
||||
byte Method;
|
||||
};
|
||||
|
||||
|
||||
struct MarkHeader
|
||||
{
|
||||
byte Mark[7];
|
||||
};
|
||||
|
||||
|
||||
struct BaseBlock
|
||||
{
|
||||
ushort HeadCRC;
|
||||
HEADER_TYPE HeadType;//byte
|
||||
ushort Flags;
|
||||
ushort HeadSize;
|
||||
};
|
||||
|
||||
struct BlockHeader:BaseBlock
|
||||
{
|
||||
union {
|
||||
uint DataSize;
|
||||
uint PackSize;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
struct MainHeader:BaseBlock
|
||||
{
|
||||
ushort HighPosAV;
|
||||
uint PosAV;
|
||||
};
|
||||
|
||||
#define SALT_SIZE 8
|
||||
|
||||
struct FileHeader:BlockHeader
|
||||
{
|
||||
uint UnpSize;
|
||||
byte HostOS;
|
||||
uint FileCRC;
|
||||
uint FileTime;
|
||||
byte UnpVer;
|
||||
byte Method;
|
||||
ushort NameSize;
|
||||
union {
|
||||
uint FileAttr;
|
||||
uint SubFlags;
|
||||
};
|
||||
/* optional */
|
||||
uint HighPackSize;
|
||||
uint HighUnpSize;
|
||||
/* names */
|
||||
char FileName[NM*4]; // *4 to avoid using lots of stack in arcread
|
||||
wchar FileNameW[NM];
|
||||
/* optional */
|
||||
byte Salt[SALT_SIZE];
|
||||
|
||||
RarTime mtime;
|
||||
/* dummy */
|
||||
Int64 FullPackSize;
|
||||
Int64 FullUnpSize;
|
||||
};
|
||||
|
||||
// SubBlockHeader and its successors were used in RAR 2.x format.
|
||||
// RAR 3.x uses FileHeader with NEWSUB_HEAD HeadType for subblocks.
|
||||
struct SubBlockHeader:BlockHeader
|
||||
{
|
||||
ushort SubType;
|
||||
byte Level;
|
||||
};
|
||||
|
||||
struct ProtectHeader:BlockHeader
|
||||
{
|
||||
byte Version;
|
||||
ushort RecSectors;
|
||||
uint TotalBlocks;
|
||||
byte Mark[8];
|
||||
};
|
||||
|
||||
#endif
|
@ -1,40 +0,0 @@
|
||||
****** ***** ****** UnRAR - free utility for RAR archives
|
||||
** ** ** ** ** ** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
****** ******* ****** License for use and distribution of
|
||||
** ** ** ** ** ** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
** ** ** ** ** ** FREE portable version
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The source code of UnRAR utility is freeware. This means:
|
||||
|
||||
1. All copyrights to RAR and the utility UnRAR are exclusively
|
||||
owned by the author - Alexander Roshal.
|
||||
|
||||
2. The UnRAR sources may be used in any software to handle RAR
|
||||
archives without limitations free of charge, but cannot be used
|
||||
to re-create the RAR compression algorithm, which is proprietary.
|
||||
Distribution of modified UnRAR sources in separate form or as a
|
||||
part of other software is permitted, provided that it is clearly
|
||||
stated in the documentation and source comments that the code may
|
||||
not be used to develop a RAR (WinRAR) compatible archiver.
|
||||
|
||||
3. The UnRAR utility may be freely distributed. It is allowed
|
||||
to distribute UnRAR inside of other software packages.
|
||||
|
||||
4. THE RAR ARCHIVER AND THE UnRAR UTILITY ARE DISTRIBUTED "AS IS".
|
||||
NO WARRANTY OF ANY KIND IS EXPRESSED OR IMPLIED. YOU USE AT
|
||||
YOUR OWN RISK. THE AUTHOR WILL NOT BE LIABLE FOR DATA LOSS,
|
||||
DAMAGES, LOSS OF PROFITS OR ANY OTHER KIND OF LOSS WHILE USING
|
||||
OR MISUSING THIS SOFTWARE.
|
||||
|
||||
5. Installing and using the UnRAR utility signifies acceptance of
|
||||
these terms and conditions of the license.
|
||||
|
||||
6. If you don't agree with terms of the license you must remove
|
||||
UnRAR files from your storage devices and cease to use the
|
||||
utility.
|
||||
|
||||
Thank you for your interest in RAR and UnRAR.
|
||||
|
||||
|
||||
Alexander L. Roshal
|
@ -1,612 +0,0 @@
|
||||
// #included by unpack.cpp
|
||||
#ifdef RAR_COMMON_HPP
|
||||
/****************************************************************************
|
||||
* This file is part of PPMd project *
|
||||
* Written and distributed to public domain by Dmitry Shkarin 1997, *
|
||||
* 1999-2000 *
|
||||
* Contents: model description and encoding/decoding routines *
|
||||
****************************************************************************/
|
||||
|
||||
inline PPM_CONTEXT* PPM_CONTEXT::createChild(ModelPPM *Model,STATE* pStats,
|
||||
STATE& FirstState)
|
||||
{
|
||||
PPM_CONTEXT* pc = (PPM_CONTEXT*) Model->SubAlloc.AllocContext();
|
||||
if ( pc )
|
||||
{
|
||||
pc->NumStats=1;
|
||||
pc->OneState=FirstState;
|
||||
pc->Suffix=this;
|
||||
pStats->Successor=pc;
|
||||
}
|
||||
return pc;
|
||||
}
|
||||
|
||||
|
||||
ModelPPM::ModelPPM()
|
||||
{
|
||||
MinContext=NULL;
|
||||
MaxContext=NULL;
|
||||
MedContext=NULL;
|
||||
}
|
||||
|
||||
|
||||
void ModelPPM::RestartModelRare()
|
||||
{
|
||||
int i, k, m;
|
||||
memset(CharMask,0,sizeof(CharMask));
|
||||
SubAlloc.InitSubAllocator();
|
||||
InitRL=-(MaxOrder < 12 ? MaxOrder:12)-1;
|
||||
MinContext = MaxContext = (PPM_CONTEXT*) SubAlloc.AllocContext();
|
||||
MinContext->Suffix=NULL;
|
||||
OrderFall=MaxOrder;
|
||||
MinContext->U.SummFreq=(MinContext->NumStats=256)+1;
|
||||
FoundState=MinContext->U.Stats=(STATE*)SubAlloc.AllocUnits(256/2);
|
||||
for (RunLength=InitRL, PrevSuccess=i=0;i < 256;i++)
|
||||
{
|
||||
MinContext->U.Stats[i].Symbol=i;
|
||||
MinContext->U.Stats[i].Freq=1;
|
||||
MinContext->U.Stats[i].Successor=NULL;
|
||||
}
|
||||
|
||||
static const ushort InitBinEsc[]={
|
||||
0x3CDD,0x1F3F,0x59BF,0x48F3,0x64A1,0x5ABC,0x6632,0x6051
|
||||
};
|
||||
|
||||
for (i=0;i < 128;i++)
|
||||
for (k=0;k < 8;k++)
|
||||
for (m=0;m < 64;m += 8)
|
||||
BinSumm[i][k+m]=BIN_SCALE-InitBinEsc[k]/(i+2);
|
||||
for (i=0;i < 25;i++)
|
||||
for (k=0;k < 16;k++)
|
||||
SEE2Cont[i][k].init(5*i+10);
|
||||
}
|
||||
|
||||
|
||||
void ModelPPM::StartModelRare(int MaxOrder)
|
||||
{
|
||||
int i, k, m ,Step;
|
||||
EscCount=1;
|
||||
/*
|
||||
if (MaxOrder < 2)
|
||||
{
|
||||
memset(CharMask,0,sizeof(CharMask));
|
||||
OrderFall=ModelPPM::MaxOrder;
|
||||
MinContext=MaxContext;
|
||||
while (MinContext->Suffix != NULL)
|
||||
{
|
||||
MinContext=MinContext->Suffix;
|
||||
OrderFall--;
|
||||
}
|
||||
FoundState=MinContext->U.Stats;
|
||||
MinContext=MaxContext;
|
||||
}
|
||||
else
|
||||
*/
|
||||
{
|
||||
ModelPPM::MaxOrder=MaxOrder;
|
||||
RestartModelRare();
|
||||
NS2BSIndx[0]=2*0;
|
||||
NS2BSIndx[1]=2*1;
|
||||
memset(NS2BSIndx+2,2*2,9);
|
||||
memset(NS2BSIndx+11,2*3,256-11);
|
||||
for (i=0;i < 3;i++)
|
||||
NS2Indx[i]=i;
|
||||
for (m=i, k=Step=1;i < 256;i++)
|
||||
{
|
||||
NS2Indx[i]=m;
|
||||
if ( !--k )
|
||||
{
|
||||
k = ++Step;
|
||||
m++;
|
||||
}
|
||||
}
|
||||
memset(HB2Flag,0,0x40);
|
||||
memset(HB2Flag+0x40,0x08,0x100-0x40);
|
||||
DummySEE2Cont.Shift=PERIOD_BITS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PPM_CONTEXT::rescale(ModelPPM *Model)
|
||||
{
|
||||
int OldNS=NumStats, i=NumStats-1, Adder, EscFreq;
|
||||
STATE* p1, * p;
|
||||
for (p=Model->FoundState;p != U.Stats;p--)
|
||||
_PPMD_SWAP(p[0],p[-1]);
|
||||
U.Stats->Freq += 4;
|
||||
U.SummFreq += 4;
|
||||
EscFreq=U.SummFreq-p->Freq;
|
||||
Adder=(Model->OrderFall != 0);
|
||||
U.SummFreq = (p->Freq=(p->Freq+Adder) >> 1);
|
||||
do
|
||||
{
|
||||
EscFreq -= (++p)->Freq;
|
||||
U.SummFreq += (p->Freq=(p->Freq+Adder) >> 1);
|
||||
if (p[0].Freq > p[-1].Freq)
|
||||
{
|
||||
STATE tmp=*(p1=p);
|
||||
do
|
||||
{
|
||||
p1[0]=p1[-1];
|
||||
} while (--p1 != U.Stats && tmp.Freq > p1[-1].Freq);
|
||||
*p1=tmp;
|
||||
}
|
||||
} while ( --i );
|
||||
if (p->Freq == 0)
|
||||
{
|
||||
do
|
||||
{
|
||||
i++;
|
||||
} while ((--p)->Freq == 0);
|
||||
EscFreq += i;
|
||||
if ((NumStats -= i) == 1)
|
||||
{
|
||||
STATE tmp=*U.Stats;
|
||||
do
|
||||
{
|
||||
tmp.Freq-=(tmp.Freq >> 1);
|
||||
EscFreq>>=1;
|
||||
} while (EscFreq > 1);
|
||||
Model->SubAlloc.FreeUnits(U.Stats,(OldNS+1) >> 1);
|
||||
*(Model->FoundState=&OneState)=tmp; return;
|
||||
}
|
||||
}
|
||||
U.SummFreq += (EscFreq -= (EscFreq >> 1));
|
||||
int n0=(OldNS+1) >> 1, n1=(NumStats+1) >> 1;
|
||||
if (n0 != n1)
|
||||
U.Stats = (STATE*) Model->SubAlloc.ShrinkUnits(U.Stats,n0,n1);
|
||||
Model->FoundState=U.Stats;
|
||||
}
|
||||
|
||||
|
||||
inline PPM_CONTEXT* ModelPPM::CreateSuccessors(bool Skip,STATE* p1)
|
||||
{
|
||||
// (removed conditional static)
|
||||
STATE UpState;
|
||||
PPM_CONTEXT* pc=MinContext, * UpBranch=FoundState->Successor;
|
||||
STATE * p, * ps[MAX_O], ** pps=ps;
|
||||
if ( !Skip )
|
||||
{
|
||||
*pps++ = FoundState;
|
||||
if ( !pc->Suffix )
|
||||
goto NO_LOOP;
|
||||
}
|
||||
if ( p1 )
|
||||
{
|
||||
p=p1;
|
||||
pc=pc->Suffix;
|
||||
goto LOOP_ENTRY;
|
||||
}
|
||||
do
|
||||
{
|
||||
pc=pc->Suffix;
|
||||
if (pc->NumStats != 1)
|
||||
{
|
||||
if ((p=pc->U.Stats)->Symbol != FoundState->Symbol)
|
||||
do
|
||||
{
|
||||
p++;
|
||||
} while (p->Symbol != FoundState->Symbol);
|
||||
}
|
||||
else
|
||||
p=&(pc->OneState);
|
||||
LOOP_ENTRY:
|
||||
if (p->Successor != UpBranch)
|
||||
{
|
||||
pc=p->Successor;
|
||||
break;
|
||||
}
|
||||
*pps++ = p;
|
||||
} while ( pc->Suffix );
|
||||
NO_LOOP:
|
||||
if (pps == ps)
|
||||
return pc;
|
||||
UpState.Symbol=*(byte*) UpBranch;
|
||||
UpState.Successor=(PPM_CONTEXT*) (((byte*) UpBranch)+1);
|
||||
if (pc->NumStats != 1)
|
||||
{
|
||||
if ((byte*) pc <= SubAlloc.pText)
|
||||
return(NULL);
|
||||
if ((p=pc->U.Stats)->Symbol != UpState.Symbol)
|
||||
do
|
||||
{
|
||||
p++;
|
||||
} while (p->Symbol != UpState.Symbol);
|
||||
uint cf=p->Freq-1;
|
||||
uint s0=pc->U.SummFreq-pc->NumStats-cf;
|
||||
UpState.Freq=1+((2*cf <= s0)?(5*cf > s0):((2*cf+3*s0-1)/(2*s0)));
|
||||
}
|
||||
else
|
||||
UpState.Freq=pc->OneState.Freq;
|
||||
do
|
||||
{
|
||||
pc = pc->createChild(this,*--pps,UpState);
|
||||
if ( !pc )
|
||||
return NULL;
|
||||
} while (pps != ps);
|
||||
return pc;
|
||||
}
|
||||
|
||||
|
||||
inline void ModelPPM::UpdateModel()
|
||||
{
|
||||
STATE fs = *FoundState, *p = NULL;
|
||||
PPM_CONTEXT *pc, *Successor;
|
||||
uint ns1, ns, cf, sf, s0;
|
||||
if (fs.Freq < MAX_FREQ/4 && (pc=MinContext->Suffix) != NULL)
|
||||
{
|
||||
if (pc->NumStats != 1)
|
||||
{
|
||||
if ((p=pc->U.Stats)->Symbol != fs.Symbol)
|
||||
{
|
||||
do
|
||||
{
|
||||
p++;
|
||||
} while (p->Symbol != fs.Symbol);
|
||||
if (p[0].Freq >= p[-1].Freq)
|
||||
{
|
||||
_PPMD_SWAP(p[0],p[-1]);
|
||||
p--;
|
||||
}
|
||||
}
|
||||
if (p->Freq < MAX_FREQ-9)
|
||||
{
|
||||
p->Freq += 2;
|
||||
pc->U.SummFreq += 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
p=&(pc->OneState);
|
||||
p->Freq += (p->Freq < 32);
|
||||
}
|
||||
}
|
||||
if ( !OrderFall )
|
||||
{
|
||||
MinContext=MaxContext=FoundState->Successor=CreateSuccessors(true,p);
|
||||
if ( !MinContext )
|
||||
goto RESTART_MODEL;
|
||||
return;
|
||||
}
|
||||
*SubAlloc.pText++ = fs.Symbol;
|
||||
Successor = (PPM_CONTEXT*) SubAlloc.pText;
|
||||
if (SubAlloc.pText >= SubAlloc.FakeUnitsStart)
|
||||
goto RESTART_MODEL;
|
||||
if ( fs.Successor )
|
||||
{
|
||||
if ((byte*) fs.Successor <= SubAlloc.pText &&
|
||||
(fs.Successor=CreateSuccessors(false,p)) == NULL)
|
||||
goto RESTART_MODEL;
|
||||
if ( !--OrderFall )
|
||||
{
|
||||
Successor=fs.Successor;
|
||||
SubAlloc.pText -= (MaxContext != MinContext);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FoundState->Successor=Successor;
|
||||
fs.Successor=MinContext;
|
||||
}
|
||||
s0=MinContext->U.SummFreq-(ns=MinContext->NumStats)-(fs.Freq-1);
|
||||
for (pc=MaxContext;pc != MinContext;pc=pc->Suffix)
|
||||
{
|
||||
if ((ns1=pc->NumStats) != 1)
|
||||
{
|
||||
if ((ns1 & 1) == 0)
|
||||
{
|
||||
pc->U.Stats=(STATE*) SubAlloc.ExpandUnits(pc->U.Stats,ns1 >> 1);
|
||||
if ( !pc->U.Stats )
|
||||
goto RESTART_MODEL;
|
||||
}
|
||||
pc->U.SummFreq += (2*ns1 < ns)+2*((4*ns1 <= ns) & (pc->U.SummFreq <= 8*ns1));
|
||||
}
|
||||
else
|
||||
{
|
||||
p=(STATE*) SubAlloc.AllocUnits(1);
|
||||
if ( !p )
|
||||
goto RESTART_MODEL;
|
||||
*p=pc->OneState;
|
||||
pc->U.Stats=p;
|
||||
if (p->Freq < MAX_FREQ/4-1)
|
||||
p->Freq += p->Freq;
|
||||
else
|
||||
p->Freq = MAX_FREQ-4;
|
||||
pc->U.SummFreq=p->Freq+InitEsc+(ns > 3);
|
||||
}
|
||||
cf=2*fs.Freq*(pc->U.SummFreq+6);
|
||||
sf=s0+pc->U.SummFreq;
|
||||
if (cf < 6*sf)
|
||||
{
|
||||
cf=1+(cf > sf)+(cf >= 4*sf);
|
||||
pc->U.SummFreq += 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
cf=4+(cf >= 9*sf)+(cf >= 12*sf)+(cf >= 15*sf);
|
||||
pc->U.SummFreq += cf;
|
||||
}
|
||||
p=pc->U.Stats+ns1;
|
||||
p->Successor=Successor;
|
||||
p->Symbol = fs.Symbol;
|
||||
p->Freq = cf;
|
||||
pc->NumStats=++ns1;
|
||||
}
|
||||
MaxContext=MinContext=fs.Successor;
|
||||
return;
|
||||
RESTART_MODEL:
|
||||
RestartModelRare();
|
||||
EscCount=0;
|
||||
}
|
||||
|
||||
|
||||
// Tabulated escapes for exponential symbol distribution
|
||||
static const byte ExpEscape[16]={ 25,14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 };
|
||||
#define GET_MEAN(SUMM,SHIFT,ROUND) ((SUMM+(1 << (SHIFT-ROUND))) >> (SHIFT))
|
||||
|
||||
|
||||
|
||||
inline void PPM_CONTEXT::decodeBinSymbol(ModelPPM *Model)
|
||||
{
|
||||
STATE& rs=OneState;
|
||||
Model->HiBitsFlag=Model->HB2Flag[Model->FoundState->Symbol];
|
||||
ushort& bs=Model->BinSumm[rs.Freq-1][Model->PrevSuccess+
|
||||
Model->NS2BSIndx[Suffix->NumStats-1]+
|
||||
Model->HiBitsFlag+2*Model->HB2Flag[rs.Symbol]+
|
||||
((Model->RunLength >> 26) & 0x20)];
|
||||
if (Model->Coder.GetCurrentShiftCount(TOT_BITS) < bs)
|
||||
{
|
||||
Model->FoundState=&rs;
|
||||
rs.Freq += (rs.Freq < 128);
|
||||
Model->Coder.SubRange.LowCount=0;
|
||||
Model->Coder.SubRange.HighCount=bs;
|
||||
bs = SHORT16(bs+INTERVAL-GET_MEAN(bs,PERIOD_BITS,2));
|
||||
Model->PrevSuccess=1;
|
||||
Model->RunLength++;
|
||||
}
|
||||
else
|
||||
{
|
||||
Model->Coder.SubRange.LowCount=bs;
|
||||
bs = SHORT16(bs-GET_MEAN(bs,PERIOD_BITS,2));
|
||||
Model->Coder.SubRange.HighCount=BIN_SCALE;
|
||||
Model->InitEsc=ExpEscape[bs >> 10];
|
||||
Model->NumMasked=1;
|
||||
Model->CharMask[rs.Symbol]=Model->EscCount;
|
||||
Model->PrevSuccess=0;
|
||||
Model->FoundState=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline void PPM_CONTEXT::update1(ModelPPM *Model,STATE* p)
|
||||
{
|
||||
(Model->FoundState=p)->Freq += 4;
|
||||
U.SummFreq += 4;
|
||||
if (p[0].Freq > p[-1].Freq)
|
||||
{
|
||||
_PPMD_SWAP(p[0],p[-1]);
|
||||
Model->FoundState=--p;
|
||||
if (p->Freq > MAX_FREQ)
|
||||
rescale(Model);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
inline bool PPM_CONTEXT::decodeSymbol1(ModelPPM *Model)
|
||||
{
|
||||
Model->Coder.SubRange.scale=U.SummFreq;
|
||||
STATE* p=U.Stats;
|
||||
int i, HiCnt;
|
||||
int count=Model->Coder.GetCurrentCount();
|
||||
if (count>=Model->Coder.SubRange.scale)
|
||||
return(false);
|
||||
if (count < (HiCnt=p->Freq))
|
||||
{
|
||||
Model->PrevSuccess=(2*(Model->Coder.SubRange.HighCount=HiCnt) > Model->Coder.SubRange.scale);
|
||||
Model->RunLength += Model->PrevSuccess;
|
||||
(Model->FoundState=p)->Freq=(HiCnt += 4);
|
||||
U.SummFreq += 4;
|
||||
if (HiCnt > MAX_FREQ)
|
||||
rescale(Model);
|
||||
Model->Coder.SubRange.LowCount=0;
|
||||
return(true);
|
||||
}
|
||||
else
|
||||
if (Model->FoundState==NULL)
|
||||
return(false);
|
||||
Model->PrevSuccess=0;
|
||||
i=NumStats-1;
|
||||
while ((HiCnt += (++p)->Freq) <= count)
|
||||
if (--i == 0)
|
||||
{
|
||||
Model->HiBitsFlag=Model->HB2Flag[Model->FoundState->Symbol];
|
||||
Model->Coder.SubRange.LowCount=HiCnt;
|
||||
Model->CharMask[p->Symbol]=Model->EscCount;
|
||||
i=(Model->NumMasked=NumStats)-1;
|
||||
Model->FoundState=NULL;
|
||||
do
|
||||
{
|
||||
Model->CharMask[(--p)->Symbol]=Model->EscCount;
|
||||
} while ( --i );
|
||||
Model->Coder.SubRange.HighCount=Model->Coder.SubRange.scale;
|
||||
return(true);
|
||||
}
|
||||
Model->Coder.SubRange.LowCount=(Model->Coder.SubRange.HighCount=HiCnt)-p->Freq;
|
||||
update1(Model,p);
|
||||
return(true);
|
||||
}
|
||||
|
||||
|
||||
inline void PPM_CONTEXT::update2(ModelPPM *Model,STATE* p)
|
||||
{
|
||||
(Model->FoundState=p)->Freq += 4;
|
||||
U.SummFreq += 4;
|
||||
if (p->Freq > MAX_FREQ)
|
||||
rescale(Model);
|
||||
Model->EscCount++;
|
||||
Model->RunLength=Model->InitRL;
|
||||
}
|
||||
|
||||
|
||||
inline SEE2_CONTEXT* PPM_CONTEXT::makeEscFreq2(ModelPPM *Model,int Diff)
|
||||
{
|
||||
SEE2_CONTEXT* psee2c;
|
||||
if (NumStats != 256)
|
||||
{
|
||||
psee2c=Model->SEE2Cont[Model->NS2Indx[Diff-1]]+
|
||||
(Diff < Suffix->NumStats-NumStats)+
|
||||
2*(U.SummFreq < 11*NumStats)+4*(Model->NumMasked > Diff)+
|
||||
Model->HiBitsFlag;
|
||||
Model->Coder.SubRange.scale=psee2c->getMean();
|
||||
}
|
||||
else
|
||||
{
|
||||
psee2c=&Model->DummySEE2Cont;
|
||||
Model->Coder.SubRange.scale=1;
|
||||
}
|
||||
return psee2c;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
inline bool PPM_CONTEXT::decodeSymbol2(ModelPPM *Model)
|
||||
{
|
||||
int count, HiCnt, i=NumStats-Model->NumMasked;
|
||||
SEE2_CONTEXT* psee2c=makeEscFreq2(Model,i);
|
||||
STATE* ps[256], ** pps=ps, * p=U.Stats-1;
|
||||
HiCnt=0;
|
||||
do
|
||||
{
|
||||
do
|
||||
{
|
||||
p++;
|
||||
} while (Model->CharMask[p->Symbol] == Model->EscCount);
|
||||
HiCnt += p->Freq;
|
||||
*pps++ = p;
|
||||
} while ( --i );
|
||||
Model->Coder.SubRange.scale += HiCnt;
|
||||
count=Model->Coder.GetCurrentCount();
|
||||
if (count>=Model->Coder.SubRange.scale)
|
||||
return(false);
|
||||
p=*(pps=ps);
|
||||
if (count < HiCnt)
|
||||
{
|
||||
HiCnt=0;
|
||||
while ((HiCnt += p->Freq) <= count)
|
||||
p=*++pps;
|
||||
Model->Coder.SubRange.LowCount = (Model->Coder.SubRange.HighCount=HiCnt)-p->Freq;
|
||||
psee2c->update();
|
||||
update2(Model,p);
|
||||
}
|
||||
else
|
||||
{
|
||||
Model->Coder.SubRange.LowCount=HiCnt;
|
||||
Model->Coder.SubRange.HighCount=Model->Coder.SubRange.scale;
|
||||
i=NumStats-Model->NumMasked;
|
||||
pps--;
|
||||
do
|
||||
{
|
||||
Model->CharMask[(*++pps)->Symbol]=Model->EscCount;
|
||||
} while ( --i );
|
||||
psee2c->Summ += Model->Coder.SubRange.scale;
|
||||
Model->NumMasked = NumStats;
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
|
||||
|
||||
inline void ModelPPM::ClearMask()
|
||||
{
|
||||
EscCount=1;
|
||||
memset(CharMask,0,sizeof(CharMask));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// reset PPM variables after data error allowing safe resuming
|
||||
// of further data processing
|
||||
void ModelPPM::CleanUp()
|
||||
{
|
||||
SubAlloc.StopSubAllocator();
|
||||
SubAlloc.StartSubAllocator(1);
|
||||
StartModelRare(2);
|
||||
}
|
||||
|
||||
|
||||
bool ModelPPM::DecodeInit(Unpack *UnpackRead,int &EscChar)
|
||||
{
|
||||
int MaxOrder=UnpackRead->GetChar();
|
||||
bool Reset=MaxOrder & 0x20;
|
||||
|
||||
int MaxMB;
|
||||
MaxMB = 0; // avoids warning of being uninitialized
|
||||
if (Reset)
|
||||
MaxMB=UnpackRead->GetChar();
|
||||
else
|
||||
if (SubAlloc.GetAllocatedMemory()==0)
|
||||
return(false);
|
||||
if (MaxOrder & 0x40)
|
||||
EscChar=UnpackRead->GetChar();
|
||||
Coder.InitDecoder(UnpackRead);
|
||||
if (Reset)
|
||||
{
|
||||
MaxOrder=(MaxOrder & 0x1f)+1;
|
||||
if (MaxOrder>16)
|
||||
MaxOrder=16+(MaxOrder-16)*3;
|
||||
if (MaxOrder==1)
|
||||
{
|
||||
SubAlloc.StopSubAllocator();
|
||||
return(false);
|
||||
}
|
||||
SubAlloc.StartSubAllocator(MaxMB+1);
|
||||
StartModelRare(MaxOrder);
|
||||
}
|
||||
return(MinContext!=NULL);
|
||||
}
|
||||
|
||||
|
||||
int ModelPPM::DecodeChar()
|
||||
{
|
||||
if ((byte*)MinContext <= SubAlloc.pText || (byte*)MinContext>SubAlloc.HeapEnd)
|
||||
return(-1);
|
||||
if (MinContext->NumStats != 1)
|
||||
{
|
||||
if ((byte*)MinContext->U.Stats <= SubAlloc.pText || (byte*)MinContext->U.Stats>SubAlloc.HeapEnd)
|
||||
return(-1);
|
||||
if (!MinContext->decodeSymbol1(this))
|
||||
return(-1);
|
||||
}
|
||||
else
|
||||
MinContext->decodeBinSymbol(this);
|
||||
Coder.Decode();
|
||||
while ( !FoundState )
|
||||
{
|
||||
ARI_DEC_NORMALIZE(Coder.code,Coder.low,Coder.range,Coder.UnpackRead);
|
||||
do
|
||||
{
|
||||
OrderFall++;
|
||||
MinContext=MinContext->Suffix;
|
||||
if ((byte*)MinContext <= SubAlloc.pText || (byte*)MinContext>SubAlloc.HeapEnd)
|
||||
return(-1);
|
||||
} while (MinContext->NumStats == NumMasked);
|
||||
if (!MinContext->decodeSymbol2(this))
|
||||
return(-1);
|
||||
Coder.Decode();
|
||||
}
|
||||
int Symbol=FoundState->Symbol;
|
||||
if (!OrderFall && (byte*) FoundState->Successor > SubAlloc.pText)
|
||||
MinContext=MaxContext=FoundState->Successor;
|
||||
else
|
||||
{
|
||||
UpdateModel();
|
||||
if (EscCount == 0)
|
||||
ClearMask();
|
||||
}
|
||||
ARI_DEC_NORMALIZE(Coder.code,Coder.low,Coder.range,Coder.UnpackRead);
|
||||
return(Symbol);
|
||||
}
|
||||
#endif
|
@ -1,133 +0,0 @@
|
||||
#ifndef _RAR_PPMMODEL_
|
||||
#define _RAR_PPMMODEL_
|
||||
|
||||
#include "coder.hpp"
|
||||
#include "suballoc.hpp"
|
||||
|
||||
const int MAX_O=64; /* maximum allowed model order */
|
||||
|
||||
const int INT_BITS=7, PERIOD_BITS=7, TOT_BITS=INT_BITS+PERIOD_BITS,
|
||||
INTERVAL=1 << INT_BITS, BIN_SCALE=1 << TOT_BITS, MAX_FREQ=124;
|
||||
|
||||
#ifndef STRICT_ALIGNMENT_REQUIRED
|
||||
#pragma pack(1)
|
||||
#endif
|
||||
|
||||
struct SEE2_CONTEXT
|
||||
{ // SEE-contexts for PPM-contexts with masked symbols
|
||||
ushort Summ;
|
||||
byte Shift, Count;
|
||||
void init(int InitVal)
|
||||
{
|
||||
Summ=InitVal << (Shift=PERIOD_BITS-4);
|
||||
Count=4;
|
||||
}
|
||||
uint getMean()
|
||||
{
|
||||
uint RetVal=SHORT16(Summ) >> Shift;
|
||||
Summ -= RetVal;
|
||||
return RetVal+(RetVal == 0);
|
||||
}
|
||||
void update()
|
||||
{
|
||||
if (Shift < PERIOD_BITS && --Count == 0)
|
||||
{
|
||||
Summ += Summ;
|
||||
Count=3 << Shift++;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class ModelPPM;
|
||||
struct PPM_CONTEXT;
|
||||
|
||||
struct STATE
|
||||
{
|
||||
byte Symbol;
|
||||
byte Freq;
|
||||
PPM_CONTEXT* Successor;
|
||||
};
|
||||
|
||||
struct FreqData
|
||||
{
|
||||
ushort SummFreq;
|
||||
STATE _PACK_ATTR * Stats;
|
||||
};
|
||||
|
||||
struct PPM_CONTEXT
|
||||
{
|
||||
ushort NumStats;
|
||||
union
|
||||
{
|
||||
FreqData U;
|
||||
STATE OneState;
|
||||
};
|
||||
|
||||
PPM_CONTEXT* Suffix;
|
||||
inline void encodeBinSymbol(ModelPPM *Model,int symbol); // MaxOrder:
|
||||
inline void encodeSymbol1(ModelPPM *Model,int symbol); // ABCD context
|
||||
inline void encodeSymbol2(ModelPPM *Model,int symbol); // BCD suffix
|
||||
inline void decodeBinSymbol(ModelPPM *Model); // BCDE successor
|
||||
inline bool decodeSymbol1(ModelPPM *Model); // other orders:
|
||||
inline bool decodeSymbol2(ModelPPM *Model); // BCD context
|
||||
inline void update1(ModelPPM *Model,STATE* p); // CD suffix
|
||||
inline void update2(ModelPPM *Model,STATE* p); // BCDE successor
|
||||
void rescale(ModelPPM *Model);
|
||||
inline PPM_CONTEXT* createChild(ModelPPM *Model,STATE* pStats,STATE& FirstState);
|
||||
inline SEE2_CONTEXT* makeEscFreq2(ModelPPM *Model,int Diff);
|
||||
};
|
||||
|
||||
#ifndef STRICT_ALIGNMENT_REQUIRED
|
||||
#ifdef _AIX
|
||||
#pragma pack(pop)
|
||||
#else
|
||||
#pragma pack()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
const uint UNIT_SIZE=Max(sizeof(PPM_CONTEXT),sizeof(RAR_MEM_BLK));
|
||||
const uint FIXED_UNIT_SIZE=12;
|
||||
|
||||
/*
|
||||
inline PPM_CONTEXT::PPM_CONTEXT(STATE* pStats,PPM_CONTEXT* ShorterContext):
|
||||
NumStats(1), Suffix(ShorterContext) { pStats->Successor=this; }
|
||||
inline PPM_CONTEXT::PPM_CONTEXT(): NumStats(0) {}
|
||||
*/
|
||||
|
||||
template <class T>
|
||||
inline void _PPMD_SWAP(T& t1,T& t2) { T tmp=t1; t1=t2; t2=tmp; }
|
||||
|
||||
|
||||
class ModelPPM
|
||||
{
|
||||
private:
|
||||
friend struct PPM_CONTEXT;
|
||||
|
||||
/*_PACK_ATTR*/ SEE2_CONTEXT SEE2Cont[25][16], DummySEE2Cont;
|
||||
|
||||
struct PPM_CONTEXT *MinContext, *MedContext, *MaxContext;
|
||||
STATE* FoundState; // found next state transition
|
||||
int NumMasked, InitEsc, OrderFall, MaxOrder, RunLength, InitRL;
|
||||
byte CharMask[256], NS2Indx[256], NS2BSIndx[256], HB2Flag[256];
|
||||
byte EscCount, PrevSuccess, HiBitsFlag;
|
||||
ushort BinSumm[128][64]; // binary SEE-contexts
|
||||
|
||||
RangeCoder Coder;
|
||||
SubAllocator SubAlloc;
|
||||
|
||||
void RestartModelRare();
|
||||
void StartModelRare(int MaxOrder);
|
||||
inline PPM_CONTEXT* CreateSuccessors(bool Skip,STATE* p1);
|
||||
|
||||
inline void UpdateModel();
|
||||
inline void ClearMask();
|
||||
friend class Unpack;
|
||||
public:
|
||||
ModelPPM();
|
||||
void CleanUp(); // reset PPM variables after data error
|
||||
bool DecodeInit(Unpack *UnpackRead,int &EscChar);
|
||||
int DecodeChar();
|
||||
};
|
||||
|
||||
#endif
|
@ -1,209 +0,0 @@
|
||||
// This source code is a heavily modified version based on the unrar package.
|
||||
// It may NOT be used to develop a RAR (WinRAR) compatible archiver.
|
||||
// See license.txt for copyright and licensing.
|
||||
|
||||
// unrar_core 3.8.5
|
||||
#ifndef RAR_COMMON_HPP
|
||||
#define RAR_COMMON_HPP
|
||||
|
||||
#include "unrar.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <setjmp.h>
|
||||
#include <limits.h>
|
||||
|
||||
//// Glue
|
||||
|
||||
// One goal is to keep source code as close to original as possible, so
|
||||
// that changes to the original can be found and merged more easily.
|
||||
|
||||
// These names are too generic and might clash (or have already, hmpf)
|
||||
#define Array Rar_Array
|
||||
#define uint32 rar_uint32
|
||||
#define sint32 rar_sint32
|
||||
#define Unpack Rar_Unpack
|
||||
#define Archive Rar_Archive
|
||||
#define RawRead Rar_RawRead
|
||||
#define BitInput Rar_BitInput
|
||||
#define ModelPPM Rar_ModelPPM
|
||||
#define RangeCoder Rar_RangeCoder
|
||||
#define SubAllocator Rar_SubAllocator
|
||||
#define UnpackFilter Rar_UnpackFilter
|
||||
#define VM_PreparedProgram Rar_VM_PreparedProgram
|
||||
#define CRCTab Rar_CRCTab
|
||||
|
||||
// original source used rar* names for these as well
|
||||
#define rarmalloc malloc
|
||||
#define rarrealloc realloc
|
||||
#define rarfree free
|
||||
|
||||
// Internal flags, possibly set later
|
||||
#undef SFX_MODULE
|
||||
#undef VM_OPTIMIZE
|
||||
#undef VM_STANDARDFILTERS
|
||||
#undef NORARVM
|
||||
|
||||
// During debugging if expr is false, prints message then continues execution
|
||||
#ifndef check
|
||||
#define check( expr ) ((void) 0)
|
||||
#endif
|
||||
|
||||
struct Rar_Error_Handler
|
||||
{
|
||||
jmp_buf jmp_env;
|
||||
|
||||
void MemoryError();
|
||||
void ReportError( unrar_err_t );
|
||||
};
|
||||
|
||||
// throw spec is mandatory in ISO C++ if operator new can return NULL
|
||||
#if __cplusplus >= 199711 || __GNUC__ >= 3
|
||||
#define UNRAR_NOTHROW throw ()
|
||||
#else
|
||||
#define UNRAR_NOTHROW
|
||||
#endif
|
||||
|
||||
struct Rar_Allocator
|
||||
{
|
||||
// provides allocator that doesn't throw an exception on failure
|
||||
static void operator delete ( void* p ) { free( p ); }
|
||||
static void* operator new ( size_t s ) UNRAR_NOTHROW { return malloc( s ); }
|
||||
static void* operator new ( size_t, void* p ) UNRAR_NOTHROW { return p; }
|
||||
};
|
||||
|
||||
//// os.hpp
|
||||
#undef STRICT_ALIGNMENT_REQUIRED
|
||||
#undef LITTLE_ENDIAN
|
||||
#define NM 1024
|
||||
|
||||
#if defined (__i386__) || defined (__x86_64__) || defined (_M_IX86) || defined (_M_X64)
|
||||
// Optimizations mostly only apply to x86
|
||||
#define LITTLE_ENDIAN
|
||||
#define ALLOW_NOT_ALIGNED_INT
|
||||
#endif
|
||||
|
||||
#if defined(__sparc) || defined(sparc) || defined(__sparcv9)
|
||||
/* prohibit not aligned access to data structures in text comression
|
||||
algorithm, increases memory requirements */
|
||||
#define STRICT_ALIGNMENT_REQUIRED
|
||||
#endif
|
||||
|
||||
//// rartypes.hpp
|
||||
#if INT_MAX == 0x7FFFFFFF && UINT_MAX == 0xFFFFFFFF
|
||||
typedef unsigned int uint32; //32 bits exactly
|
||||
typedef int sint32; //signed 32 bits exactly
|
||||
#define PRESENT_INT32
|
||||
#endif
|
||||
|
||||
typedef unsigned char byte; //8 bits
|
||||
typedef unsigned short ushort; //preferably 16 bits, but can be more
|
||||
typedef unsigned int uint; //32 bits or more
|
||||
|
||||
typedef wchar_t wchar;
|
||||
|
||||
#define SHORT16(x) (sizeof(ushort)==2 ? (ushort)(x):((x)&0xffff))
|
||||
#define UINT32(x) (sizeof(uint )==4 ? (uint )(x):((x)&0xffffffff))
|
||||
|
||||
//// rardefs.hpp
|
||||
#define Min(x,y) (((x)<(y)) ? (x):(y))
|
||||
#define Max(x,y) (((x)>(y)) ? (x):(y))
|
||||
|
||||
//// int64.hpp
|
||||
typedef unrar_long_long Int64;
|
||||
|
||||
#define int64to32(x) ((uint)(x))
|
||||
#define int32to64(high,low) ((((Int64)(high))<<31<<1)+(low))
|
||||
#define is64plus(x) (x>=0)
|
||||
|
||||
#define INT64MAX int32to64(0x7fffffff,0)
|
||||
|
||||
//// crc.hpp
|
||||
extern uint CRCTab[256];
|
||||
void InitCRC();
|
||||
uint CRC(uint StartCRC,const void *Addr,size_t Size);
|
||||
ushort OldCRC(ushort StartCRC,const void *Addr,size_t Size);
|
||||
|
||||
//// rartime.hpp
|
||||
struct RarTime
|
||||
{
|
||||
unsigned time;
|
||||
void SetDos(uint DosTime) { time = DosTime; }
|
||||
};
|
||||
|
||||
//// rdwrfn.hpp
|
||||
class ComprDataIO
|
||||
: public Rar_Error_Handler
|
||||
{
|
||||
public:
|
||||
unrar_read_func user_read;
|
||||
unrar_write_func user_write;
|
||||
void* user_read_data;
|
||||
void* user_write_data;
|
||||
unrar_err_t write_error; // once write error occurs, no more writes are made
|
||||
Int64 Tell_;
|
||||
bool OldFormat;
|
||||
|
||||
private:
|
||||
Int64 UnpPackedSize;
|
||||
bool SkipUnpCRC;
|
||||
|
||||
public:
|
||||
int UnpRead(byte *Addr,uint Count);
|
||||
void UnpWrite(byte *Addr,uint Count);
|
||||
void SetSkipUnpCRC( bool b ) { SkipUnpCRC = b; }
|
||||
void SetPackedSizeToRead( Int64 n ) { UnpPackedSize = n; }
|
||||
|
||||
uint UnpFileCRC;
|
||||
|
||||
void Seek(Int64 Offset, int Method = 0 ) { (void)Method; Tell_ = Offset; }
|
||||
Int64 Tell() { return Tell_; }
|
||||
int Read( void* p, int n );
|
||||
};
|
||||
|
||||
//// rar.hpp
|
||||
class Unpack;
|
||||
#include "array.hpp"
|
||||
#include "headers.hpp"
|
||||
#include "getbits.hpp"
|
||||
#include "archive.hpp"
|
||||
#include "rawread.hpp"
|
||||
#include "encname.hpp"
|
||||
#include "compress.hpp"
|
||||
#include "rarvm.hpp"
|
||||
#include "model.hpp"
|
||||
#include "unpack.hpp"
|
||||
|
||||
//// extract.hpp
|
||||
/** RAR archive */
|
||||
struct unrar_t
|
||||
: public Rar_Allocator
|
||||
{
|
||||
unrar_info_t info;
|
||||
unrar_pos_t begin_pos;
|
||||
unrar_pos_t solid_pos;
|
||||
unrar_pos_t first_file_pos;
|
||||
void const* data_;
|
||||
void* own_data_;
|
||||
void (*close_file)( void* ); // func ptr to avoid linking fclose() in unnecessarily
|
||||
bool done;
|
||||
long FileCount;
|
||||
Unpack* Unp;
|
||||
Array<byte> Buffer;
|
||||
// large items last
|
||||
Archive Arc;
|
||||
|
||||
unrar_t();
|
||||
~unrar_t();
|
||||
void UnstoreFile( Int64 );
|
||||
unrar_err_t ExtractCurrentFile( bool SkipSolid = false, bool check_compatibility_only = false );
|
||||
void update_first_file_pos()
|
||||
{
|
||||
if ( FileCount == 0 )
|
||||
first_file_pos = Arc.CurBlockPos;
|
||||
}
|
||||
};
|
||||
|
||||
typedef unrar_t CmdExtract;
|
||||
|
||||
#endif
|
1158
fex/unrar/rarvm.cpp
1158
fex/unrar/rarvm.cpp
File diff suppressed because it is too large
Load Diff
@ -1,112 +0,0 @@
|
||||
#ifndef _RAR_VM_
|
||||
#define _RAR_VM_
|
||||
|
||||
#define VM_STANDARDFILTERS
|
||||
|
||||
#ifndef SFX_MODULE
|
||||
#define VM_OPTIMIZE
|
||||
#endif
|
||||
|
||||
|
||||
#define VM_MEMSIZE 0x40000
|
||||
#define VM_MEMMASK (VM_MEMSIZE-1)
|
||||
#define VM_GLOBALMEMADDR 0x3C000
|
||||
#define VM_GLOBALMEMSIZE 0x2000
|
||||
#define VM_FIXEDGLOBALSIZE 64
|
||||
|
||||
enum VM_Commands
|
||||
{
|
||||
VM_MOV, VM_CMP, VM_ADD, VM_SUB, VM_JZ, VM_JNZ, VM_INC, VM_DEC,
|
||||
VM_JMP, VM_XOR, VM_AND, VM_OR, VM_TEST, VM_JS, VM_JNS, VM_JB,
|
||||
VM_JBE, VM_JA, VM_JAE, VM_PUSH, VM_POP, VM_CALL, VM_RET, VM_NOT,
|
||||
VM_SHL, VM_SHR, VM_SAR, VM_NEG, VM_PUSHA,VM_POPA, VM_PUSHF,VM_POPF,
|
||||
VM_MOVZX,VM_MOVSX,VM_XCHG, VM_MUL, VM_DIV, VM_ADC, VM_SBB, VM_PRINT,
|
||||
|
||||
#ifdef VM_OPTIMIZE
|
||||
VM_MOVB, VM_MOVD, VM_CMPB, VM_CMPD,
|
||||
|
||||
VM_ADDB, VM_ADDD, VM_SUBB, VM_SUBD, VM_INCB, VM_INCD, VM_DECB, VM_DECD,
|
||||
VM_NEGB, VM_NEGD,
|
||||
#endif
|
||||
|
||||
VM_STANDARD
|
||||
};
|
||||
|
||||
enum VM_StandardFilters {
|
||||
VMSF_NONE, VMSF_E8, VMSF_E8E9, VMSF_ITANIUM, VMSF_RGB, VMSF_AUDIO,
|
||||
VMSF_DELTA, VMSF_UPCASE
|
||||
};
|
||||
|
||||
enum VM_Flags {VM_FC=1,VM_FZ=2,VM_FS=0x80000000};
|
||||
|
||||
enum VM_OpType {VM_OPREG,VM_OPINT,VM_OPREGMEM,VM_OPNONE};
|
||||
|
||||
struct VM_PreparedOperand
|
||||
{
|
||||
VM_OpType Type;
|
||||
uint Data;
|
||||
uint Base;
|
||||
uint *Addr;
|
||||
};
|
||||
|
||||
struct VM_PreparedCommand
|
||||
{
|
||||
VM_Commands OpCode;
|
||||
bool ByteMode;
|
||||
VM_PreparedOperand Op1,Op2;
|
||||
};
|
||||
|
||||
|
||||
struct VM_PreparedProgram
|
||||
{
|
||||
VM_PreparedProgram( Rar_Error_Handler* eh ) : Cmd( eh ), GlobalData( eh ), StaticData( eh )
|
||||
{AltCmd=NULL;}
|
||||
|
||||
Array<VM_PreparedCommand> Cmd;
|
||||
VM_PreparedCommand *AltCmd;
|
||||
int CmdCount;
|
||||
|
||||
Array<byte> GlobalData;
|
||||
Array<byte> StaticData; // static data contained in DB operators
|
||||
uint InitR[7];
|
||||
|
||||
byte *FilteredData;
|
||||
unsigned int FilteredDataSize;
|
||||
};
|
||||
|
||||
class RarVM:private BitInput
|
||||
{
|
||||
private:
|
||||
inline uint GetValue(bool ByteMode,uint *Addr);
|
||||
inline void SetValue(bool ByteMode,uint *Addr,uint Value);
|
||||
inline uint* GetOperand(VM_PreparedOperand *CmdOp);
|
||||
void DecodeArg(VM_PreparedOperand &Op,bool ByteMode);
|
||||
#ifdef VM_OPTIMIZE
|
||||
void Optimize(VM_PreparedProgram *Prg);
|
||||
#endif
|
||||
bool ExecuteCode(VM_PreparedCommand *PreparedCode,int CodeSize);
|
||||
#ifdef VM_STANDARDFILTERS
|
||||
VM_StandardFilters IsStandardFilter(byte *Code,int CodeSize);
|
||||
void ExecuteStandardFilter(VM_StandardFilters FilterType);
|
||||
unsigned int FilterItanium_GetBits(byte *Data,int BitPos,int BitCount);
|
||||
void FilterItanium_SetBits(byte *Data,unsigned int BitField,int BitPos,
|
||||
int BitCount);
|
||||
#endif
|
||||
|
||||
byte *Mem;
|
||||
uint R[8];
|
||||
uint Flags;
|
||||
public:
|
||||
RarVM();
|
||||
~RarVM();
|
||||
void Init();
|
||||
void handle_mem_error( Rar_Error_Handler& );
|
||||
friend class Unpack;
|
||||
void Prepare(byte *Code,int CodeSize,VM_PreparedProgram *Prg);
|
||||
void Execute(VM_PreparedProgram *Prg);
|
||||
void SetLowEndianValue(uint *Addr,uint Value);
|
||||
void SetMemory(unsigned int Pos,byte *Data,unsigned int DataSize);
|
||||
static uint ReadData(BitInput &Inp);
|
||||
};
|
||||
|
||||
#endif
|
@ -1,57 +0,0 @@
|
||||
// #included by rarvm.cpp
|
||||
#ifdef RAR_COMMON_HPP
|
||||
#define VMCF_OP0 0
|
||||
#define VMCF_OP1 1
|
||||
#define VMCF_OP2 2
|
||||
#define VMCF_OPMASK 3
|
||||
#define VMCF_BYTEMODE 4
|
||||
#define VMCF_JUMP 8
|
||||
#define VMCF_PROC 16
|
||||
#define VMCF_USEFLAGS 32
|
||||
#define VMCF_CHFLAGS 64
|
||||
|
||||
const
|
||||
static byte VM_CmdFlags[]=
|
||||
{
|
||||
/* VM_MOV */ VMCF_OP2 | VMCF_BYTEMODE ,
|
||||
/* VM_CMP */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
|
||||
/* VM_ADD */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
|
||||
/* VM_SUB */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
|
||||
/* VM_JZ */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS ,
|
||||
/* VM_JNZ */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS ,
|
||||
/* VM_INC */ VMCF_OP1 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
|
||||
/* VM_DEC */ VMCF_OP1 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
|
||||
/* VM_JMP */ VMCF_OP1 | VMCF_JUMP ,
|
||||
/* VM_XOR */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
|
||||
/* VM_AND */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
|
||||
/* VM_OR */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
|
||||
/* VM_TEST */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
|
||||
/* VM_JS */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS ,
|
||||
/* VM_JNS */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS ,
|
||||
/* VM_JB */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS ,
|
||||
/* VM_JBE */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS ,
|
||||
/* VM_JA */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS ,
|
||||
/* VM_JAE */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS ,
|
||||
/* VM_PUSH */ VMCF_OP1 ,
|
||||
/* VM_POP */ VMCF_OP1 ,
|
||||
/* VM_CALL */ VMCF_OP1 | VMCF_PROC ,
|
||||
/* VM_RET */ VMCF_OP0 | VMCF_PROC ,
|
||||
/* VM_NOT */ VMCF_OP1 | VMCF_BYTEMODE ,
|
||||
/* VM_SHL */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
|
||||
/* VM_SHR */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
|
||||
/* VM_SAR */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
|
||||
/* VM_NEG */ VMCF_OP1 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
|
||||
/* VM_PUSHA */ VMCF_OP0 ,
|
||||
/* VM_POPA */ VMCF_OP0 ,
|
||||
/* VM_PUSHF */ VMCF_OP0 | VMCF_USEFLAGS ,
|
||||
/* VM_POPF */ VMCF_OP0 | VMCF_CHFLAGS ,
|
||||
/* VM_MOVZX */ VMCF_OP2 ,
|
||||
/* VM_MOVSX */ VMCF_OP2 ,
|
||||
/* VM_XCHG */ VMCF_OP2 | VMCF_BYTEMODE ,
|
||||
/* VM_MUL */ VMCF_OP2 | VMCF_BYTEMODE ,
|
||||
/* VM_DIV */ VMCF_OP2 | VMCF_BYTEMODE ,
|
||||
/* VM_ADC */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_USEFLAGS | VMCF_CHFLAGS ,
|
||||
/* VM_SBB */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_USEFLAGS | VMCF_CHFLAGS ,
|
||||
/* VM_PRINT */ VMCF_OP0
|
||||
};
|
||||
#endif
|
@ -1,86 +0,0 @@
|
||||
#include "rar.hpp"
|
||||
|
||||
RawRead::RawRead(ComprDataIO *SrcFile) : Data( SrcFile )
|
||||
{
|
||||
RawRead::SrcFile=SrcFile;
|
||||
ReadPos=0;
|
||||
DataSize=0;
|
||||
}
|
||||
|
||||
void RawRead::Reset()
|
||||
{
|
||||
ReadPos=0;
|
||||
DataSize=0;
|
||||
Data.Reset();
|
||||
}
|
||||
|
||||
void RawRead::Read(int Size)
|
||||
{
|
||||
// (removed decryption)
|
||||
if (Size!=0)
|
||||
{
|
||||
Data.Add(Size);
|
||||
DataSize+=SrcFile->Read(&Data[DataSize],Size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void RawRead::Get(byte &Field)
|
||||
{
|
||||
if (ReadPos<DataSize)
|
||||
{
|
||||
Field=Data[ReadPos];
|
||||
ReadPos++;
|
||||
}
|
||||
else
|
||||
Field=0;
|
||||
}
|
||||
|
||||
|
||||
void RawRead::Get(ushort &Field)
|
||||
{
|
||||
if (ReadPos+1<DataSize)
|
||||
{
|
||||
Field=Data[ReadPos]+(Data[ReadPos+1]<<8);
|
||||
ReadPos+=2;
|
||||
}
|
||||
else
|
||||
Field=0;
|
||||
}
|
||||
|
||||
|
||||
void RawRead::Get(uint &Field)
|
||||
{
|
||||
if (ReadPos+3<DataSize)
|
||||
{
|
||||
Field=Data[ReadPos]+(Data[ReadPos+1]<<8)+(Data[ReadPos+2]<<16)+
|
||||
(Data[ReadPos+3]<<24);
|
||||
ReadPos+=4;
|
||||
}
|
||||
else
|
||||
Field=0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void RawRead::Get(byte *Field,int Size)
|
||||
{
|
||||
if (ReadPos+Size-1<DataSize)
|
||||
{
|
||||
memcpy(Field,&Data[ReadPos],Size);
|
||||
ReadPos+=Size;
|
||||
}
|
||||
else
|
||||
memset(Field,0,Size);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
uint RawRead::GetCRC(bool ProcessedOnly)
|
||||
{
|
||||
return(DataSize>2 ? CRC(0xffffffff,&Data[2],(ProcessedOnly ? ReadPos:DataSize)-2):0xffffffff);
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
#ifndef _RAR_RAWREAD_
|
||||
#define _RAR_RAWREAD_
|
||||
|
||||
class RawRead
|
||||
{
|
||||
private:
|
||||
Array<byte> Data;
|
||||
File *SrcFile;
|
||||
int DataSize;
|
||||
int ReadPos;
|
||||
friend class Archive;
|
||||
public:
|
||||
RawRead(File *SrcFile);
|
||||
void Reset();
|
||||
void Read(int Size);
|
||||
void Get(byte &Field);
|
||||
void Get(ushort &Field);
|
||||
void Get(uint &Field);
|
||||
void Get(byte *Field,int Size);
|
||||
uint GetCRC(bool ProcessedOnly);
|
||||
int Size() {return DataSize;}
|
||||
int PaddedSize() {return Data.Size()-DataSize;}
|
||||
};
|
||||
|
||||
#endif
|
@ -1,63 +0,0 @@
|
||||
|
||||
Portable UnRAR version
|
||||
|
||||
|
||||
1. General
|
||||
|
||||
This package includes freeware Unrar C++ source and a few makefiles
|
||||
(makefile.bcc, makefile.msc+msc.dep, makefile.unix). Unrar source
|
||||
is subset of RAR and generated from RAR source automatically,
|
||||
by a small program removing blocks like '#ifndef UNRAR ... #endif'.
|
||||
Such method is not perfect and you may find some RAR related
|
||||
stuff unnecessary in Unrar, especially in header files.
|
||||
|
||||
If you wish to port Unrar to a new platform, you may need to edit
|
||||
'#define LITTLE_ENDIAN' in os.hpp and data type definitions
|
||||
in rartypes.hpp.
|
||||
|
||||
if computer architecture does not allow not aligned data access,
|
||||
you need to undefine ALLOW_NOT_ALIGNED_INT and define
|
||||
STRICT_ALIGNMENT_REQUIRED in os.h. Note that it will increase memory
|
||||
requirements.
|
||||
|
||||
If you use Borland C++ makefile (makefile.bcc), you need to define
|
||||
BASEPATHCC environment (or makefile) variable containing
|
||||
the path to Borland C++ installation.
|
||||
|
||||
Makefile.unix contains numerous compiler option sets.
|
||||
GCC Linux is selected by default. If you need to compile Unrar
|
||||
for other platforms, uncomment corresponding lines.
|
||||
|
||||
|
||||
2. Unrar binaries
|
||||
|
||||
If you compiled Unrar for OS, which is not present in "Downloads"
|
||||
and "RAR extras" on www.rarlab.com, we will appreciate if you send
|
||||
us the compiled executable to place it to our site.
|
||||
|
||||
|
||||
3. Acknowledgements
|
||||
|
||||
This source includes parts of code written by the following authors:
|
||||
|
||||
Dmitry Shkarin PPMII v.H text compression
|
||||
Dmitry Subbotin Carryless rangecoder
|
||||
Szymon Stefanek AES encryption
|
||||
Brian Gladman AES encryption
|
||||
Steve Reid SHA-1 hash function
|
||||
Marcus Herbert makefile.unix file
|
||||
Tomasz Klim fixes for libunrar.so
|
||||
Robert Riebisch makefile.dj and patches for DJGPP
|
||||
|
||||
|
||||
4. Legal stuff
|
||||
|
||||
Unrar source may be used in any software to handle RAR archives
|
||||
without limitations free of charge, but cannot be used to re-create
|
||||
the RAR compression algorithm, which is proprietary. Distribution
|
||||
of modified Unrar source in separate form or as a part of other
|
||||
software is permitted, provided that it is clearly stated in
|
||||
the documentation and source comments that the code may not be used
|
||||
to develop a RAR (WinRAR) compatible archiver.
|
||||
|
||||
More detailed license text is available in license.txt.
|
@ -1,261 +0,0 @@
|
||||
/****************************************************************************
|
||||
* This file is part of PPMd project *
|
||||
* Written and distributed to public domain by Dmitry Shkarin 1997, *
|
||||
* 1999-2000 *
|
||||
* Contents: memory allocation routines *
|
||||
****************************************************************************/
|
||||
|
||||
// #included by unpack.cpp
|
||||
#ifdef RAR_COMMON_HPP
|
||||
SubAllocator::SubAllocator()
|
||||
{
|
||||
Clean();
|
||||
}
|
||||
|
||||
|
||||
void SubAllocator::Clean()
|
||||
{
|
||||
SubAllocatorSize=0;
|
||||
}
|
||||
|
||||
|
||||
inline void SubAllocator::InsertNode(void* p,int indx)
|
||||
{
|
||||
((RAR_NODE*) p)->next=FreeList[indx].next;
|
||||
FreeList[indx].next=(RAR_NODE*) p;
|
||||
}
|
||||
|
||||
|
||||
inline void* SubAllocator::RemoveNode(int indx)
|
||||
{
|
||||
RAR_NODE* RetVal=FreeList[indx].next;
|
||||
FreeList[indx].next=RetVal->next;
|
||||
return RetVal;
|
||||
}
|
||||
|
||||
|
||||
inline uint SubAllocator::U2B(int NU)
|
||||
{
|
||||
return /*8*NU+4*NU*/UNIT_SIZE*NU;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
calculate RAR_MEM_BLK + Items address. Real RAR_MEM_BLK size must be
|
||||
equal to UNIT_SIZE, so we cannot just add Items to RAR_MEM_BLK address
|
||||
*/
|
||||
inline RAR_MEM_BLK* SubAllocator::MBPtr(RAR_MEM_BLK *BasePtr,int Items)
|
||||
{
|
||||
return((RAR_MEM_BLK*)( ((byte *)(BasePtr))+U2B(Items) ));
|
||||
}
|
||||
|
||||
|
||||
inline void SubAllocator::SplitBlock(void* pv,int OldIndx,int NewIndx)
|
||||
{
|
||||
int i, UDiff=Indx2Units[OldIndx]-Indx2Units[NewIndx];
|
||||
byte* p=((byte*) pv)+U2B(Indx2Units[NewIndx]);
|
||||
if (Indx2Units[i=Units2Indx[UDiff-1]] != UDiff)
|
||||
{
|
||||
InsertNode(p,--i);
|
||||
p += U2B(i=Indx2Units[i]);
|
||||
UDiff -= i;
|
||||
}
|
||||
InsertNode(p,Units2Indx[UDiff-1]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void SubAllocator::StopSubAllocator()
|
||||
{
|
||||
if ( SubAllocatorSize )
|
||||
{
|
||||
SubAllocatorSize=0;
|
||||
rarfree(HeapStart);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool SubAllocator::StartSubAllocator(int SASize)
|
||||
{
|
||||
uint t=SASize << 20;
|
||||
if (SubAllocatorSize == t)
|
||||
return true;
|
||||
StopSubAllocator();
|
||||
uint AllocSize=t/FIXED_UNIT_SIZE*UNIT_SIZE+UNIT_SIZE;
|
||||
#ifdef STRICT_ALIGNMENT_REQUIRED
|
||||
AllocSize+=UNIT_SIZE;
|
||||
#endif
|
||||
if ((HeapStart=(byte *)rarmalloc(AllocSize)) == NULL)
|
||||
{
|
||||
ErrHandler->MemoryError();
|
||||
return false;
|
||||
}
|
||||
HeapEnd=HeapStart+AllocSize-UNIT_SIZE;
|
||||
SubAllocatorSize=t;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void SubAllocator::InitSubAllocator()
|
||||
{
|
||||
int i, k;
|
||||
memset(FreeList,0,sizeof(FreeList));
|
||||
pText=HeapStart;
|
||||
uint Size2=FIXED_UNIT_SIZE*(SubAllocatorSize/8/FIXED_UNIT_SIZE*7);
|
||||
uint RealSize2=Size2/FIXED_UNIT_SIZE*UNIT_SIZE;
|
||||
uint Size1=SubAllocatorSize-Size2;
|
||||
uint RealSize1=Size1/FIXED_UNIT_SIZE*UNIT_SIZE+Size1%FIXED_UNIT_SIZE;
|
||||
#ifdef STRICT_ALIGNMENT_REQUIRED
|
||||
if (Size1%FIXED_UNIT_SIZE!=0)
|
||||
RealSize1+=UNIT_SIZE-Size1%FIXED_UNIT_SIZE;
|
||||
#endif
|
||||
HiUnit=HeapStart+SubAllocatorSize;
|
||||
LoUnit=UnitsStart=HeapStart+RealSize1;
|
||||
FakeUnitsStart=HeapStart+Size1;
|
||||
HiUnit=LoUnit+RealSize2;
|
||||
for (i=0,k=1;i < N1 ;i++,k += 1)
|
||||
Indx2Units[i]=k;
|
||||
for (k++;i < N1+N2 ;i++,k += 2)
|
||||
Indx2Units[i]=k;
|
||||
for (k++;i < N1+N2+N3 ;i++,k += 3)
|
||||
Indx2Units[i]=k;
|
||||
for (k++;i < N1+N2+N3+N4;i++,k += 4)
|
||||
Indx2Units[i]=k;
|
||||
for (GlueCount=k=i=0;k < 128;k++)
|
||||
{
|
||||
i += (Indx2Units[i] < k+1);
|
||||
Units2Indx[k]=i;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline void SubAllocator::GlueFreeBlocks()
|
||||
{
|
||||
RAR_MEM_BLK s0, * p, * p1;
|
||||
int i, k, sz;
|
||||
if (LoUnit != HiUnit)
|
||||
*LoUnit=0;
|
||||
for (i=0, s0.next=s0.prev=&s0;i < N_INDEXES;i++)
|
||||
while ( FreeList[i].next )
|
||||
{
|
||||
p=(RAR_MEM_BLK*)RemoveNode(i);
|
||||
p->insertAt(&s0);
|
||||
p->Stamp=0xFFFF;
|
||||
p->NU=Indx2Units[i];
|
||||
}
|
||||
for (p=s0.next;p != &s0;p=p->next)
|
||||
while ((p1=MBPtr(p,p->NU))->Stamp == 0xFFFF && int(p->NU)+p1->NU < 0x10000)
|
||||
{
|
||||
p1->remove();
|
||||
p->NU += p1->NU;
|
||||
}
|
||||
while ((p=s0.next) != &s0)
|
||||
{
|
||||
for (p->remove(), sz=p->NU;sz > 128;sz -= 128, p=MBPtr(p,128))
|
||||
InsertNode(p,N_INDEXES-1);
|
||||
if (Indx2Units[i=Units2Indx[sz-1]] != sz)
|
||||
{
|
||||
k=sz-Indx2Units[--i];
|
||||
InsertNode(MBPtr(p,sz-k),k-1);
|
||||
}
|
||||
InsertNode(p,i);
|
||||
}
|
||||
}
|
||||
|
||||
void* SubAllocator::AllocUnitsRare(int indx)
|
||||
{
|
||||
if ( !GlueCount )
|
||||
{
|
||||
GlueCount = 255;
|
||||
GlueFreeBlocks();
|
||||
if ( FreeList[indx].next )
|
||||
return RemoveNode(indx);
|
||||
}
|
||||
int i=indx;
|
||||
do
|
||||
{
|
||||
if (++i == N_INDEXES)
|
||||
{
|
||||
GlueCount--;
|
||||
i=U2B(Indx2Units[indx]);
|
||||
int j=FIXED_UNIT_SIZE*Indx2Units[indx];
|
||||
if (FakeUnitsStart-pText > j)
|
||||
{
|
||||
FakeUnitsStart-=j;
|
||||
UnitsStart -= i;
|
||||
return(UnitsStart);
|
||||
}
|
||||
return(NULL);
|
||||
}
|
||||
} while ( !FreeList[i].next );
|
||||
void* RetVal=RemoveNode(i);
|
||||
SplitBlock(RetVal,i,indx);
|
||||
return RetVal;
|
||||
}
|
||||
|
||||
|
||||
inline void* SubAllocator::AllocUnits(int NU)
|
||||
{
|
||||
int indx=Units2Indx[NU-1];
|
||||
if ( FreeList[indx].next )
|
||||
return RemoveNode(indx);
|
||||
void* RetVal=LoUnit;
|
||||
LoUnit += U2B(Indx2Units[indx]);
|
||||
if (LoUnit <= HiUnit)
|
||||
return RetVal;
|
||||
LoUnit -= U2B(Indx2Units[indx]);
|
||||
return AllocUnitsRare(indx);
|
||||
}
|
||||
|
||||
|
||||
void* SubAllocator::AllocContext()
|
||||
{
|
||||
if (HiUnit != LoUnit)
|
||||
return (HiUnit -= UNIT_SIZE);
|
||||
if ( FreeList->next )
|
||||
return RemoveNode(0);
|
||||
return AllocUnitsRare(0);
|
||||
}
|
||||
|
||||
|
||||
void* SubAllocator::ExpandUnits(void* OldPtr,int OldNU)
|
||||
{
|
||||
int i0=Units2Indx[OldNU-1], i1=Units2Indx[OldNU-1+1];
|
||||
if (i0 == i1)
|
||||
return OldPtr;
|
||||
void* ptr=AllocUnits(OldNU+1);
|
||||
if ( ptr )
|
||||
{
|
||||
memcpy(ptr,OldPtr,U2B(OldNU));
|
||||
InsertNode(OldPtr,i0);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
void* SubAllocator::ShrinkUnits(void* OldPtr,int OldNU,int NewNU)
|
||||
{
|
||||
int i0=Units2Indx[OldNU-1], i1=Units2Indx[NewNU-1];
|
||||
if (i0 == i1)
|
||||
return OldPtr;
|
||||
if ( FreeList[i1].next )
|
||||
{
|
||||
void* ptr=RemoveNode(i1);
|
||||
memcpy(ptr,OldPtr,U2B(NewNU));
|
||||
InsertNode(OldPtr,i0);
|
||||
return ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
SplitBlock(OldPtr,i0,i1);
|
||||
return OldPtr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SubAllocator::FreeUnits(void* ptr,int OldNU)
|
||||
{
|
||||
InsertNode(ptr,Units2Indx[OldNU-1]);
|
||||
}
|
||||
#endif
|
@ -1,88 +0,0 @@
|
||||
/****************************************************************************
|
||||
* This file is part of PPMd project *
|
||||
* Written and distributed to public domain by Dmitry Shkarin 1997, *
|
||||
* 1999-2000 *
|
||||
* Contents: interface to memory allocation routines *
|
||||
****************************************************************************/
|
||||
#if !defined(_SUBALLOC_H_)
|
||||
#define _SUBALLOC_H_
|
||||
|
||||
const int N1=4, N2=4, N3=4, N4=(128+3-1*N1-2*N2-3*N3)/4;
|
||||
const int N_INDEXES=N1+N2+N3+N4;
|
||||
|
||||
#if defined(__GNUC__) && !defined(STRICT_ALIGNMENT_REQUIRED)
|
||||
#define _PACK_ATTR __attribute__ ((packed))
|
||||
#else
|
||||
#define _PACK_ATTR
|
||||
#endif /* defined(__GNUC__) */
|
||||
|
||||
#ifndef STRICT_ALIGNMENT_REQUIRED
|
||||
#pragma pack(1)
|
||||
#endif
|
||||
|
||||
struct RAR_MEM_BLK
|
||||
{
|
||||
ushort Stamp, NU;
|
||||
RAR_MEM_BLK* next, * prev;
|
||||
void insertAt(RAR_MEM_BLK* p)
|
||||
{
|
||||
next=(prev=p)->next;
|
||||
p->next=next->prev=this;
|
||||
}
|
||||
void remove()
|
||||
{
|
||||
prev->next=next;
|
||||
next->prev=prev;
|
||||
}
|
||||
} _PACK_ATTR;
|
||||
|
||||
#ifndef STRICT_ALIGNMENT_REQUIRED
|
||||
#ifdef _AIX
|
||||
#pragma pack(pop)
|
||||
#else
|
||||
#pragma pack()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
struct RAR_NODE
|
||||
{
|
||||
RAR_NODE* next;
|
||||
};
|
||||
|
||||
class SubAllocator
|
||||
{
|
||||
private:
|
||||
inline void InsertNode(void* p,int indx);
|
||||
inline void* RemoveNode(int indx);
|
||||
inline uint U2B(int NU);
|
||||
inline void SplitBlock(void* pv,int OldIndx,int NewIndx);
|
||||
uint GetUsedMemory();
|
||||
inline void GlueFreeBlocks();
|
||||
void* AllocUnitsRare(int indx);
|
||||
inline RAR_MEM_BLK* MBPtr(RAR_MEM_BLK *BasePtr,int Items);
|
||||
|
||||
long SubAllocatorSize;
|
||||
byte Indx2Units[N_INDEXES], Units2Indx[128], GlueCount;
|
||||
byte *HeapStart,*LoUnit, *HiUnit;
|
||||
struct RAR_NODE FreeList[N_INDEXES];
|
||||
public:
|
||||
Rar_Error_Handler* ErrHandler;
|
||||
SubAllocator();
|
||||
~SubAllocator() {StopSubAllocator();}
|
||||
void Clean();
|
||||
bool StartSubAllocator(int SASize);
|
||||
void StopSubAllocator();
|
||||
void InitSubAllocator();
|
||||
inline void* AllocContext();
|
||||
inline void* AllocUnits(int NU);
|
||||
inline void* ExpandUnits(void* ptr,int OldNU);
|
||||
inline void* ShrinkUnits(void* ptr,int OldNU,int NewNU);
|
||||
inline void FreeUnits(void* ptr,int OldNU);
|
||||
long GetAllocatedMemory() {return(SubAllocatorSize);};
|
||||
|
||||
byte *pText, *UnitsStart,*HeapEnd,*FakeUnitsStart;
|
||||
};
|
||||
|
||||
|
||||
#endif /* !defined(_SUBALLOC_H_) */
|
@ -1,275 +0,0 @@
|
||||
|
||||
RAR version 3.80 - Technical information
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
THE ARCHIVE FORMAT DESCRIBED BELOW IS ONLY VALID FOR VERSIONS SINCE 1.50
|
||||
|
||||
==========================================================================
|
||||
RAR archive file format
|
||||
==========================================================================
|
||||
|
||||
Archive file consists of variable length blocks. The order of these
|
||||
blocks may vary, but the first block must be a marker block followed by
|
||||
an archive header block.
|
||||
|
||||
Each block begins with the following fields:
|
||||
|
||||
HEAD_CRC 2 bytes CRC of total block or block part
|
||||
HEAD_TYPE 1 byte Block type
|
||||
HEAD_FLAGS 2 bytes Block flags
|
||||
HEAD_SIZE 2 bytes Block size
|
||||
ADD_SIZE 4 bytes Optional field - added block size
|
||||
|
||||
Field ADD_SIZE present only if (HEAD_FLAGS & 0x8000) != 0
|
||||
|
||||
Total block size is HEAD_SIZE if (HEAD_FLAGS & 0x8000) == 0
|
||||
and HEAD_SIZE+ADD_SIZE if the field ADD_SIZE is present - when
|
||||
(HEAD_FLAGS & 0x8000) != 0.
|
||||
|
||||
In each block the followings bits in HEAD_FLAGS have the same meaning:
|
||||
|
||||
0x4000 - if set, older RAR versions will ignore the block
|
||||
and remove it when the archive is updated.
|
||||
if clear, the block is copied to the new archive
|
||||
file when the archive is updated;
|
||||
|
||||
0x8000 - if set, ADD_SIZE field is present and the full block
|
||||
size is HEAD_SIZE+ADD_SIZE.
|
||||
|
||||
Declared block types:
|
||||
|
||||
HEAD_TYPE=0x72 marker block
|
||||
HEAD_TYPE=0x73 archive header
|
||||
HEAD_TYPE=0x74 file header
|
||||
HEAD_TYPE=0x75 old style comment header
|
||||
HEAD_TYPE=0x76 old style authenticity information
|
||||
HEAD_TYPE=0x77 old style subblock
|
||||
HEAD_TYPE=0x78 old style recovery record
|
||||
HEAD_TYPE=0x79 old style authenticity information
|
||||
HEAD_TYPE=0x7a subblock
|
||||
|
||||
Comment block is actually used only within other blocks and doesn't
|
||||
exist separately.
|
||||
|
||||
Archive processing is made in the following manner:
|
||||
|
||||
1. Read and check marker block
|
||||
2. Read archive header
|
||||
3. Read or skip HEAD_SIZE-sizeof(MAIN_HEAD) bytes
|
||||
4. If end of archive encountered then terminate archive processing,
|
||||
else read 7 bytes into fields HEAD_CRC, HEAD_TYPE, HEAD_FLAGS,
|
||||
HEAD_SIZE.
|
||||
5. Check HEAD_TYPE.
|
||||
if HEAD_TYPE==0x74
|
||||
read file header ( first 7 bytes already read )
|
||||
read or skip HEAD_SIZE-sizeof(FILE_HEAD) bytes
|
||||
if (HEAD_FLAGS & 0x100)
|
||||
read or skip HIGH_PACK_SIZE*0x100000000+PACK_SIZE bytes
|
||||
else
|
||||
read or skip PACK_SIZE bytes
|
||||
else
|
||||
read corresponding HEAD_TYPE block:
|
||||
read HEAD_SIZE-7 bytes
|
||||
if (HEAD_FLAGS & 0x8000)
|
||||
read ADD_SIZE bytes
|
||||
6. go to 4.
|
||||
|
||||
|
||||
==========================================================================
|
||||
Block Formats
|
||||
==========================================================================
|
||||
|
||||
|
||||
Marker block ( MARK_HEAD )
|
||||
|
||||
|
||||
HEAD_CRC Always 0x6152
|
||||
2 bytes
|
||||
|
||||
HEAD_TYPE Header type: 0x72
|
||||
1 byte
|
||||
|
||||
HEAD_FLAGS Always 0x1a21
|
||||
2 bytes
|
||||
|
||||
HEAD_SIZE Block size = 0x0007
|
||||
2 bytes
|
||||
|
||||
The marker block is actually considered as a fixed byte
|
||||
sequence: 0x52 0x61 0x72 0x21 0x1a 0x07 0x00
|
||||
|
||||
|
||||
|
||||
Archive header ( MAIN_HEAD )
|
||||
|
||||
|
||||
HEAD_CRC CRC of fields HEAD_TYPE to RESERVED2
|
||||
2 bytes
|
||||
|
||||
HEAD_TYPE Header type: 0x73
|
||||
1 byte
|
||||
|
||||
HEAD_FLAGS Bit flags:
|
||||
2 bytes
|
||||
0x0001 - Volume attribute (archive volume)
|
||||
0x0002 - Archive comment present
|
||||
RAR 3.x uses the separate comment block
|
||||
and does not set this flag.
|
||||
|
||||
0x0004 - Archive lock attribute
|
||||
0x0008 - Solid attribute (solid archive)
|
||||
0x0010 - New volume naming scheme ('volname.partN.rar')
|
||||
0x0020 - Authenticity information present
|
||||
RAR 3.x does not set this flag.
|
||||
|
||||
0x0040 - Recovery record present
|
||||
0x0080 - Block headers are encrypted
|
||||
0x0100 - First volume (set only by RAR 3.0 and later)
|
||||
|
||||
other bits in HEAD_FLAGS are reserved for
|
||||
internal use
|
||||
|
||||
HEAD_SIZE Archive header total size including archive comments
|
||||
2 bytes
|
||||
|
||||
RESERVED1 Reserved
|
||||
2 bytes
|
||||
|
||||
RESERVED2 Reserved
|
||||
4 bytes
|
||||
|
||||
|
||||
|
||||
File header (File in archive)
|
||||
|
||||
|
||||
HEAD_CRC CRC of fields from HEAD_TYPE to FILEATTR
|
||||
2 bytes and file name
|
||||
|
||||
HEAD_TYPE Header type: 0x74
|
||||
1 byte
|
||||
|
||||
HEAD_FLAGS Bit flags:
|
||||
2 bytes
|
||||
0x01 - file continued from previous volume
|
||||
0x02 - file continued in next volume
|
||||
0x04 - file encrypted with password
|
||||
|
||||
0x08 - file comment present
|
||||
RAR 3.x uses the separate comment block
|
||||
and does not set this flag.
|
||||
|
||||
0x10 - information from previous files is used (solid flag)
|
||||
(for RAR 2.0 and later)
|
||||
|
||||
bits 7 6 5 (for RAR 2.0 and later)
|
||||
|
||||
0 0 0 - dictionary size 64 KB
|
||||
0 0 1 - dictionary size 128 KB
|
||||
0 1 0 - dictionary size 256 KB
|
||||
0 1 1 - dictionary size 512 KB
|
||||
1 0 0 - dictionary size 1024 KB
|
||||
1 0 1 - dictionary size 2048 KB
|
||||
1 1 0 - dictionary size 4096 KB
|
||||
1 1 1 - file is directory
|
||||
|
||||
0x100 - HIGH_PACK_SIZE and HIGH_UNP_SIZE fields
|
||||
are present. These fields are used to archive
|
||||
only very large files (larger than 2Gb),
|
||||
for smaller files these fields are absent.
|
||||
|
||||
0x200 - FILE_NAME contains both usual and encoded
|
||||
Unicode name separated by zero. In this case
|
||||
NAME_SIZE field is equal to the length
|
||||
of usual name plus encoded Unicode name plus 1.
|
||||
|
||||
If this flag is present, but FILE_NAME does not
|
||||
contain zero bytes, it means that file name
|
||||
is encoded using UTF-8.
|
||||
|
||||
0x400 - the header contains additional 8 bytes
|
||||
after the file name, which are required to
|
||||
increase encryption security (so called 'salt').
|
||||
|
||||
0x800 - Version flag. It is an old file version,
|
||||
a version number is appended to file name as ';n'.
|
||||
|
||||
0x1000 - Extended time field present.
|
||||
|
||||
0x8000 - this bit always is set, so the complete
|
||||
block size is HEAD_SIZE + PACK_SIZE
|
||||
(and plus HIGH_PACK_SIZE, if bit 0x100 is set)
|
||||
|
||||
HEAD_SIZE File header full size including file name and comments
|
||||
2 bytes
|
||||
|
||||
PACK_SIZE Compressed file size
|
||||
4 bytes
|
||||
|
||||
UNP_SIZE Uncompressed file size
|
||||
4 bytes
|
||||
|
||||
HOST_OS Operating system used for archiving
|
||||
1 byte 0 - MS DOS
|
||||
1 - OS/2
|
||||
2 - Win32
|
||||
3 - Unix
|
||||
4 - Mac OS
|
||||
5 - BeOS
|
||||
|
||||
FILE_CRC File CRC
|
||||
4 bytes
|
||||
|
||||
FTIME Date and time in standard MS DOS format
|
||||
4 bytes
|
||||
|
||||
UNP_VER RAR version needed to extract file
|
||||
1 byte
|
||||
Version number is encoded as
|
||||
10 * Major version + minor version.
|
||||
|
||||
METHOD Packing method
|
||||
1 byte
|
||||
0x30 - storing
|
||||
0x31 - fastest compression
|
||||
0x32 - fast compression
|
||||
0x33 - normal compression
|
||||
0x34 - good compression
|
||||
0x35 - best compression
|
||||
|
||||
NAME_SIZE File name size
|
||||
2 bytes
|
||||
|
||||
ATTR File attributes
|
||||
4 bytes
|
||||
|
||||
HIGH_PACK_SIZE High 4 bytes of 64 bit value of compressed file size.
|
||||
4 bytes Optional value, presents only if bit 0x100 in HEAD_FLAGS
|
||||
is set.
|
||||
|
||||
HIGH_UNP_SIZE High 4 bytes of 64 bit value of uncompressed file size.
|
||||
4 bytes Optional value, presents only if bit 0x100 in HEAD_FLAGS
|
||||
is set.
|
||||
|
||||
FILE_NAME File name - string of NAME_SIZE bytes size
|
||||
|
||||
SALT present if (HEAD_FLAGS & 0x400) != 0
|
||||
8 bytes
|
||||
|
||||
EXT_TIME present if (HEAD_FLAGS & 0x1000) != 0
|
||||
variable size
|
||||
|
||||
other new fields may appear here.
|
||||
|
||||
|
||||
==========================================================================
|
||||
Application notes
|
||||
==========================================================================
|
||||
|
||||
1. To process an SFX archive you need to skip the SFX module searching
|
||||
for the marker block in the archive. There is no marker block sequence (0x52
|
||||
0x61 0x72 0x21 0x1a 0x07 0x00) in the SFX module itself.
|
||||
|
||||
2. The CRC is calculated using the standard polynomial 0xEDB88320. In
|
||||
case the size of the CRC is less than 4 bytes, only the low order bytes
|
||||
are used.
|
@ -1,106 +0,0 @@
|
||||
#include "rar.hpp"
|
||||
|
||||
#include "unicode.hpp"
|
||||
|
||||
bool WideToChar(const wchar *Src,char *Dest,int DestSize)
|
||||
{
|
||||
bool RetCode=true;
|
||||
#ifdef _WIN_32
|
||||
if (WideCharToMultiByte(CP_ACP,0,Src,-1,Dest,DestSize,NULL,NULL)==0)
|
||||
RetCode=false;
|
||||
#else
|
||||
#ifdef _APPLE
|
||||
WideToUtf(Src,Dest,DestSize);
|
||||
#else
|
||||
#ifdef MBFUNCTIONS
|
||||
|
||||
size_t ResultingSize=wcstombs(Dest,Src,DestSize);
|
||||
if (ResultingSize==(size_t)-1)
|
||||
RetCode=false;
|
||||
if (ResultingSize==0 && *Src!=0)
|
||||
RetCode=false;
|
||||
|
||||
if ((!RetCode || *Dest==0 && *Src!=0) && DestSize>NM && strlenw(Src)<NM)
|
||||
{
|
||||
/* Workaround for strange Linux Unicode functions bug.
|
||||
Some of wcstombs and mbstowcs implementations in some situations
|
||||
(we are yet to find out what it depends on) can return an empty
|
||||
string and success code if buffer size value is too large.
|
||||
*/
|
||||
return(WideToChar(Src,Dest,NM));
|
||||
}
|
||||
|
||||
#else
|
||||
// TODO: convert to UTF-8? Would need conversion routine. Ugh.
|
||||
for (int I=0;I<DestSize;I++)
|
||||
{
|
||||
Dest[I]=(char)Src[I];
|
||||
if (Src[I]==0)
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
return(RetCode);
|
||||
}
|
||||
|
||||
void UtfToWide(const char *Src,wchar *Dest,int DestSize)
|
||||
{
|
||||
DestSize--;
|
||||
while (*Src!=0)
|
||||
{
|
||||
uint c=(byte)*(Src++),d;
|
||||
if (c<0x80)
|
||||
d=c;
|
||||
else
|
||||
if ((c>>5)==6)
|
||||
{
|
||||
if ((*Src&0xc0)!=0x80)
|
||||
break;
|
||||
d=((c&0x1f)<<6)|(*Src&0x3f);
|
||||
Src++;
|
||||
}
|
||||
else
|
||||
if ((c>>4)==14)
|
||||
{
|
||||
if ((Src[0]&0xc0)!=0x80 || (Src[1]&0xc0)!=0x80)
|
||||
break;
|
||||
d=((c&0xf)<<12)|((Src[0]&0x3f)<<6)|(Src[1]&0x3f);
|
||||
Src+=2;
|
||||
}
|
||||
else
|
||||
if ((c>>3)==30)
|
||||
{
|
||||
if ((Src[0]&0xc0)!=0x80 || (Src[1]&0xc0)!=0x80 || (Src[2]&0xc0)!=0x80)
|
||||
break;
|
||||
d=((c&7)<<18)|((Src[0]&0x3f)<<12)|((Src[1]&0x3f)<<6)|(Src[2]&0x3f);
|
||||
Src+=3;
|
||||
}
|
||||
else
|
||||
break;
|
||||
if (--DestSize<0)
|
||||
break;
|
||||
if (d>0xffff)
|
||||
{
|
||||
if (--DestSize<0 || d>0x10ffff)
|
||||
break;
|
||||
*(Dest++)=((d-0x10000)>>10)+0xd800;
|
||||
*(Dest++)=(d&0x3ff)+0xdc00;
|
||||
}
|
||||
else
|
||||
*(Dest++)=d;
|
||||
}
|
||||
*Dest=0;
|
||||
}
|
||||
|
||||
|
||||
// strfn.cpp
|
||||
void ExtToInt(const char *Src,char *Dest)
|
||||
{
|
||||
#if defined(_WIN_32)
|
||||
CharToOem(Src,Dest);
|
||||
#else
|
||||
if (Dest!=Src)
|
||||
strcpy(Dest,Src);
|
||||
#endif
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
#ifndef _RAR_UNICODE_
|
||||
#define _RAR_UNICODE_
|
||||
|
||||
bool WideToChar(const wchar *Src,char *Dest,int DestSize=0x1000000);
|
||||
void UtfToWide(const char *Src,wchar *Dest,int DestSize);
|
||||
|
||||
// strfn.cpp
|
||||
void ExtToInt(const char *Src,char *Dest);
|
||||
|
||||
#endif
|
1065
fex/unrar/unpack.cpp
1065
fex/unrar/unpack.cpp
File diff suppressed because it is too large
Load Diff
@ -1,227 +0,0 @@
|
||||
#ifndef _RAR_UNPACK_
|
||||
#define _RAR_UNPACK_
|
||||
|
||||
enum BLOCK_TYPES {BLOCK_LZ,BLOCK_PPM};
|
||||
|
||||
struct Decode
|
||||
{
|
||||
unsigned int MaxNum;
|
||||
unsigned int DecodeLen[16];
|
||||
unsigned int DecodePos[16];
|
||||
unsigned int DecodeNum[2];
|
||||
};
|
||||
|
||||
struct LitDecode
|
||||
{
|
||||
unsigned int MaxNum;
|
||||
unsigned int DecodeLen[16];
|
||||
unsigned int DecodePos[16];
|
||||
unsigned int DecodeNum[NC];
|
||||
};
|
||||
|
||||
struct DistDecode
|
||||
{
|
||||
unsigned int MaxNum;
|
||||
unsigned int DecodeLen[16];
|
||||
unsigned int DecodePos[16];
|
||||
unsigned int DecodeNum[DC];
|
||||
};
|
||||
|
||||
struct LowDistDecode
|
||||
{
|
||||
unsigned int MaxNum;
|
||||
unsigned int DecodeLen[16];
|
||||
unsigned int DecodePos[16];
|
||||
unsigned int DecodeNum[LDC];
|
||||
};
|
||||
|
||||
struct RepDecode
|
||||
{
|
||||
unsigned int MaxNum;
|
||||
unsigned int DecodeLen[16];
|
||||
unsigned int DecodePos[16];
|
||||
unsigned int DecodeNum[RC];
|
||||
};
|
||||
|
||||
struct BitDecode
|
||||
{
|
||||
unsigned int MaxNum;
|
||||
unsigned int DecodeLen[16];
|
||||
unsigned int DecodePos[16];
|
||||
unsigned int DecodeNum[BC];
|
||||
};
|
||||
|
||||
struct UnpackFilter
|
||||
: Rar_Allocator
|
||||
{
|
||||
unsigned int BlockStart;
|
||||
unsigned int BlockLength;
|
||||
unsigned int ExecCount;
|
||||
bool NextWindow;
|
||||
|
||||
// position of parent filter in Filters array used as prototype for filter
|
||||
// in PrgStack array. Not defined for filters in Filters array.
|
||||
unsigned int ParentFilter;
|
||||
|
||||
VM_PreparedProgram Prg;
|
||||
UnpackFilter( Rar_Error_Handler* eh ) : Prg( eh ) { }
|
||||
};
|
||||
|
||||
/***************************** Unpack v 2.0 *********************************/
|
||||
struct MultDecode
|
||||
{
|
||||
unsigned int MaxNum;
|
||||
unsigned int DecodeLen[16];
|
||||
unsigned int DecodePos[16];
|
||||
unsigned int DecodeNum[MC20];
|
||||
};
|
||||
|
||||
struct AudioVariables
|
||||
{
|
||||
int K1,K2,K3,K4,K5;
|
||||
int D1,D2,D3,D4;
|
||||
int LastDelta;
|
||||
unsigned int Dif[11];
|
||||
unsigned int ByteCount;
|
||||
int LastChar;
|
||||
};
|
||||
/***************************** Unpack v 2.0 *********************************/
|
||||
|
||||
|
||||
// public so operator new/delete will be accessible, argh
|
||||
class Unpack:public BitInput
|
||||
{
|
||||
private:
|
||||
friend class Pack;
|
||||
|
||||
void Unpack29(bool Solid);
|
||||
bool UnpReadBuf();
|
||||
void UnpWriteBuf();
|
||||
void ExecuteCode(VM_PreparedProgram *Prg);
|
||||
void UnpWriteArea(unsigned int StartPtr,unsigned int EndPtr);
|
||||
void UnpWriteData(byte *Data,int Size);
|
||||
bool ReadTables();
|
||||
void MakeDecodeTables(unsigned char *LenTab,struct Decode *Dec,int Size);
|
||||
int DecodeNumber(struct Decode *Dec);
|
||||
void CopyString();
|
||||
inline void InsertOldDist(unsigned int Distance);
|
||||
inline void InsertLastMatch(unsigned int Length,unsigned int Distance);
|
||||
void UnpInitData(int Solid);
|
||||
void CopyString(unsigned int Length,unsigned int Distance);
|
||||
bool ReadEndOfBlock();
|
||||
bool ReadVMCode();
|
||||
bool ReadVMCodePPM();
|
||||
bool AddVMCode(unsigned int FirstByte,byte *Code,int CodeSize);
|
||||
void InitFilters();
|
||||
|
||||
ComprDataIO *UnpIO;
|
||||
ModelPPM PPM;
|
||||
int PPMEscChar;
|
||||
|
||||
Array<byte> VMCode; // here to avoid leaks
|
||||
BitInput Inp; // here to avoid leaks
|
||||
|
||||
RarVM VM;
|
||||
|
||||
UnpackFilter* LastStackFilter; // avoids leak for stack-based filter
|
||||
|
||||
/* Filters code, one entry per filter */
|
||||
Array<UnpackFilter*> Filters;
|
||||
|
||||
/* Filters stack, several entrances of same filter are possible */
|
||||
Array<UnpackFilter*> PrgStack;
|
||||
|
||||
/* lengths of preceding blocks, one length per filter. Used to reduce
|
||||
size required to write block length if lengths are repeating */
|
||||
Array<int> OldFilterLengths;
|
||||
|
||||
int LastFilter;
|
||||
|
||||
bool TablesRead;
|
||||
struct LitDecode LD;
|
||||
struct DistDecode DD;
|
||||
struct LowDistDecode LDD;
|
||||
struct RepDecode RD;
|
||||
struct BitDecode BD;
|
||||
|
||||
unsigned int OldDist[4],OldDistPtr;
|
||||
unsigned int LastDist,LastLength;
|
||||
|
||||
unsigned int UnpPtr,WrPtr;
|
||||
|
||||
int ReadTop;
|
||||
int ReadBorder;
|
||||
|
||||
unsigned char UnpOldTable[HUFF_TABLE_SIZE];
|
||||
|
||||
int UnpBlockType;
|
||||
|
||||
byte *Window;
|
||||
bool ExternalWindow;
|
||||
|
||||
|
||||
Int64 DestUnpSize;
|
||||
|
||||
enum { Suspended = false }; // original source could never set to true
|
||||
bool UnpAllBuf;
|
||||
bool UnpSomeRead;
|
||||
Int64 WrittenFileSize;
|
||||
bool FileExtracted;
|
||||
|
||||
int PrevLowDist,LowDistRepCount;
|
||||
|
||||
/***************************** Unpack v 1.5 *********************************/
|
||||
void Unpack15(bool Solid);
|
||||
void ShortLZ();
|
||||
void LongLZ();
|
||||
void HuffDecode();
|
||||
void GetFlagsBuf();
|
||||
void OldUnpInitData(int Solid);
|
||||
void InitHuff();
|
||||
void CorrHuff(unsigned int *CharSet,unsigned int *NumToPlace);
|
||||
void OldCopyString(unsigned int Distance,unsigned int Length);
|
||||
unsigned int DecodeNum(int Num,unsigned int StartPos,
|
||||
const unsigned int *DecTab,const unsigned int *PosTab);
|
||||
void OldUnpWriteBuf();
|
||||
|
||||
unsigned int ChSet[256],ChSetA[256],ChSetB[256],ChSetC[256];
|
||||
unsigned int Place[256],PlaceA[256],PlaceB[256],PlaceC[256];
|
||||
unsigned int NToPl[256],NToPlB[256],NToPlC[256];
|
||||
unsigned int FlagBuf,AvrPlc,AvrPlcB,AvrLn1,AvrLn2,AvrLn3;
|
||||
int Buf60,NumHuf,StMode,LCount,FlagsCnt;
|
||||
unsigned int Nhfb,Nlzb,MaxDist3;
|
||||
/***************************** Unpack v 1.5 *********************************/
|
||||
|
||||
/***************************** Unpack v 2.0 *********************************/
|
||||
void Unpack20(bool Solid);
|
||||
struct MultDecode MD[4];
|
||||
unsigned char UnpOldTable20[MC20*4];
|
||||
int UnpAudioBlock,UnpChannels,UnpCurChannel,UnpChannelDelta;
|
||||
void CopyString20(unsigned int Length,unsigned int Distance);
|
||||
bool ReadTables20();
|
||||
void UnpInitData20(int Solid);
|
||||
void ReadLastTables();
|
||||
byte DecodeAudio(int Delta);
|
||||
struct AudioVariables AudV[4];
|
||||
/***************************** Unpack v 2.0 *********************************/
|
||||
|
||||
public:
|
||||
Rar_Error_Handler& ErrHandler;
|
||||
byte const* window_wrptr() const { return &Window [WrPtr & MAXWINMASK]; }
|
||||
|
||||
static void init_tables();
|
||||
Unpack(ComprDataIO *DataIO);
|
||||
~Unpack();
|
||||
void Init(byte *Window=NULL);
|
||||
void DoUnpack(int Method,bool Solid);
|
||||
void SetDestSize(Int64 DestSize) {DestUnpSize=DestSize;FileExtracted=false;}
|
||||
|
||||
unsigned int GetChar()
|
||||
{
|
||||
if (InAddr>BitInput::MAX_SIZE-30)
|
||||
UnpReadBuf();
|
||||
return(InBuf[InAddr++]);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
@ -1,532 +0,0 @@
|
||||
// #included by unpack.cpp
|
||||
#ifdef RAR_COMMON_HPP
|
||||
#define STARTL1 2
|
||||
const
|
||||
static unsigned int DecL1[]={0x8000,0xa000,0xc000,0xd000,0xe000,0xea00,
|
||||
0xee00,0xf000,0xf200,0xf200,0xffff};
|
||||
const
|
||||
static unsigned int PosL1[]={0,0,0,2,3,5,7,11,16,20,24,32,32};
|
||||
|
||||
#define STARTL2 3
|
||||
const
|
||||
static unsigned int DecL2[]={0xa000,0xc000,0xd000,0xe000,0xea00,0xee00,
|
||||
0xf000,0xf200,0xf240,0xffff};
|
||||
const
|
||||
static unsigned int PosL2[]={0,0,0,0,5,7,9,13,18,22,26,34,36};
|
||||
|
||||
#define STARTHF0 4
|
||||
const
|
||||
static unsigned int DecHf0[]={0x8000,0xc000,0xe000,0xf200,0xf200,0xf200,
|
||||
0xf200,0xf200,0xffff};
|
||||
const
|
||||
static unsigned int PosHf0[]={0,0,0,0,0,8,16,24,33,33,33,33,33};
|
||||
|
||||
|
||||
#define STARTHF1 5
|
||||
const
|
||||
static unsigned int DecHf1[]={0x2000,0xc000,0xe000,0xf000,0xf200,0xf200,
|
||||
0xf7e0,0xffff};
|
||||
const
|
||||
static unsigned int PosHf1[]={0,0,0,0,0,0,4,44,60,76,80,80,127};
|
||||
|
||||
|
||||
#define STARTHF2 5
|
||||
const
|
||||
static unsigned int DecHf2[]={0x1000,0x2400,0x8000,0xc000,0xfa00,0xffff,
|
||||
0xffff,0xffff};
|
||||
const
|
||||
static unsigned int PosHf2[]={0,0,0,0,0,0,2,7,53,117,233,0,0};
|
||||
|
||||
|
||||
#define STARTHF3 6
|
||||
const
|
||||
static unsigned int DecHf3[]={0x800,0x2400,0xee00,0xfe80,0xffff,0xffff,
|
||||
0xffff};
|
||||
const
|
||||
static unsigned int PosHf3[]={0,0,0,0,0,0,0,2,16,218,251,0,0};
|
||||
|
||||
|
||||
#define STARTHF4 8
|
||||
const
|
||||
static unsigned int DecHf4[]={0xff00,0xffff,0xffff,0xffff,0xffff,0xffff};
|
||||
const
|
||||
static unsigned int PosHf4[]={0,0,0,0,0,0,0,0,0,255,0,0,0};
|
||||
|
||||
|
||||
void Unpack::Unpack15(bool Solid)
|
||||
{
|
||||
if (Suspended)
|
||||
UnpPtr=WrPtr;
|
||||
else
|
||||
{
|
||||
UnpInitData(Solid);
|
||||
OldUnpInitData(Solid);
|
||||
UnpReadBuf();
|
||||
if (!Solid)
|
||||
{
|
||||
InitHuff();
|
||||
UnpPtr=0;
|
||||
}
|
||||
else
|
||||
UnpPtr=WrPtr;
|
||||
--DestUnpSize;
|
||||
}
|
||||
if (DestUnpSize>=0)
|
||||
{
|
||||
GetFlagsBuf();
|
||||
FlagsCnt=8;
|
||||
}
|
||||
|
||||
while (DestUnpSize>=0)
|
||||
{
|
||||
UnpPtr&=MAXWINMASK;
|
||||
|
||||
if (InAddr>ReadTop-30 && !UnpReadBuf())
|
||||
break;
|
||||
if (((WrPtr-UnpPtr) & MAXWINMASK)<270 && WrPtr!=UnpPtr)
|
||||
{
|
||||
OldUnpWriteBuf();
|
||||
if (Suspended)
|
||||
return;
|
||||
}
|
||||
if (StMode)
|
||||
{
|
||||
HuffDecode();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (--FlagsCnt < 0)
|
||||
{
|
||||
GetFlagsBuf();
|
||||
FlagsCnt=7;
|
||||
}
|
||||
|
||||
if (FlagBuf & 0x80)
|
||||
{
|
||||
FlagBuf<<=1;
|
||||
if (Nlzb > Nhfb)
|
||||
LongLZ();
|
||||
else
|
||||
HuffDecode();
|
||||
}
|
||||
else
|
||||
{
|
||||
FlagBuf<<=1;
|
||||
if (--FlagsCnt < 0)
|
||||
{
|
||||
GetFlagsBuf();
|
||||
FlagsCnt=7;
|
||||
}
|
||||
if (FlagBuf & 0x80)
|
||||
{
|
||||
FlagBuf<<=1;
|
||||
if (Nlzb > Nhfb)
|
||||
HuffDecode();
|
||||
else
|
||||
LongLZ();
|
||||
}
|
||||
else
|
||||
{
|
||||
FlagBuf<<=1;
|
||||
ShortLZ();
|
||||
}
|
||||
}
|
||||
}
|
||||
OldUnpWriteBuf();
|
||||
}
|
||||
|
||||
|
||||
void Unpack::OldUnpWriteBuf()
|
||||
{
|
||||
if (UnpPtr!=WrPtr)
|
||||
UnpSomeRead=true;
|
||||
if (UnpPtr<WrPtr)
|
||||
{
|
||||
UnpIO->UnpWrite(&Window[WrPtr],-WrPtr & MAXWINMASK);
|
||||
UnpIO->UnpWrite(Window,UnpPtr);
|
||||
UnpAllBuf=true;
|
||||
}
|
||||
else
|
||||
UnpIO->UnpWrite(&Window[WrPtr],UnpPtr-WrPtr);
|
||||
WrPtr=UnpPtr;
|
||||
}
|
||||
|
||||
|
||||
#define GetShortLen1(pos) ((pos)==1 ? Buf60+3:ShortLen1[pos])
|
||||
#define GetShortLen2(pos) ((pos)==3 ? Buf60+3:ShortLen2[pos])
|
||||
|
||||
void Unpack::ShortLZ()
|
||||
{
|
||||
const
|
||||
static unsigned int ShortLen1[]={1,3,4,4,5,6,7,8,8,4,4,5,6,6,4,0};
|
||||
const
|
||||
static unsigned int ShortXor1[]={0,0xa0,0xd0,0xe0,0xf0,0xf8,0xfc,0xfe,
|
||||
0xff,0xc0,0x80,0x90,0x98,0x9c,0xb0};
|
||||
const
|
||||
static unsigned int ShortLen2[]={2,3,3,3,4,4,5,6,6,4,4,5,6,6,4,0};
|
||||
const
|
||||
static unsigned int ShortXor2[]={0,0x40,0x60,0xa0,0xd0,0xe0,0xf0,0xf8,
|
||||
0xfc,0xc0,0x80,0x90,0x98,0x9c,0xb0};
|
||||
|
||||
|
||||
unsigned int Length,SaveLength;
|
||||
unsigned int LastDistance;
|
||||
unsigned int Distance;
|
||||
int DistancePlace;
|
||||
NumHuf=0;
|
||||
|
||||
unsigned int BitField=fgetbits();
|
||||
if (LCount==2)
|
||||
{
|
||||
faddbits(1);
|
||||
if (BitField >= 0x8000)
|
||||
{
|
||||
OldCopyString((unsigned int)LastDist,LastLength);
|
||||
return;
|
||||
}
|
||||
BitField <<= 1;
|
||||
LCount=0;
|
||||
}
|
||||
|
||||
BitField>>=8;
|
||||
|
||||
// not thread safe, replaced by GetShortLen1 and GetShortLen2 macro
|
||||
// ShortLen1[1]=ShortLen2[3]=Buf60+3;
|
||||
|
||||
if (AvrLn1<37)
|
||||
{
|
||||
for (Length=0;;Length++)
|
||||
if (((BitField^ShortXor1[Length]) & (~(0xff>>GetShortLen1(Length))))==0)
|
||||
break;
|
||||
faddbits(GetShortLen1(Length));
|
||||
}
|
||||
else
|
||||
{
|
||||
for (Length=0;;Length++)
|
||||
if (((BitField^ShortXor2[Length]) & (~(0xff>>GetShortLen2(Length))))==0)
|
||||
break;
|
||||
faddbits(GetShortLen2(Length));
|
||||
}
|
||||
|
||||
if (Length >= 9)
|
||||
{
|
||||
if (Length == 9)
|
||||
{
|
||||
LCount++;
|
||||
OldCopyString((unsigned int)LastDist,LastLength);
|
||||
return;
|
||||
}
|
||||
if (Length == 14)
|
||||
{
|
||||
LCount=0;
|
||||
Length=DecodeNum(fgetbits(),STARTL2,DecL2,PosL2)+5;
|
||||
Distance=(fgetbits()>>1) | 0x8000;
|
||||
faddbits(15);
|
||||
LastLength=Length;
|
||||
LastDist=Distance;
|
||||
OldCopyString(Distance,Length);
|
||||
return;
|
||||
}
|
||||
|
||||
LCount=0;
|
||||
SaveLength=Length;
|
||||
Distance=OldDist[(OldDistPtr-(Length-9)) & 3];
|
||||
Length=DecodeNum(fgetbits(),STARTL1,DecL1,PosL1)+2;
|
||||
if (Length==0x101 && SaveLength==10)
|
||||
{
|
||||
Buf60 ^= 1;
|
||||
return;
|
||||
}
|
||||
if (Distance > 256)
|
||||
Length++;
|
||||
if (Distance >= MaxDist3)
|
||||
Length++;
|
||||
|
||||
OldDist[OldDistPtr++]=Distance;
|
||||
OldDistPtr = OldDistPtr & 3;
|
||||
LastLength=Length;
|
||||
LastDist=Distance;
|
||||
OldCopyString(Distance,Length);
|
||||
return;
|
||||
}
|
||||
|
||||
LCount=0;
|
||||
AvrLn1 += Length;
|
||||
AvrLn1 -= AvrLn1 >> 4;
|
||||
|
||||
DistancePlace=DecodeNum(fgetbits(),STARTHF2,DecHf2,PosHf2) & 0xff;
|
||||
Distance=ChSetA[DistancePlace];
|
||||
if (--DistancePlace != -1)
|
||||
{
|
||||
PlaceA[Distance]--;
|
||||
LastDistance=ChSetA[DistancePlace];
|
||||
PlaceA[LastDistance]++;
|
||||
ChSetA[DistancePlace+1]=LastDistance;
|
||||
ChSetA[DistancePlace]=Distance;
|
||||
}
|
||||
Length+=2;
|
||||
OldDist[OldDistPtr++] = ++Distance;
|
||||
OldDistPtr = OldDistPtr & 3;
|
||||
LastLength=Length;
|
||||
LastDist=Distance;
|
||||
OldCopyString(Distance,Length);
|
||||
}
|
||||
|
||||
|
||||
void Unpack::LongLZ()
|
||||
{
|
||||
unsigned int Length;
|
||||
unsigned int Distance;
|
||||
unsigned int DistancePlace,NewDistancePlace;
|
||||
unsigned int OldAvr2,OldAvr3;
|
||||
|
||||
NumHuf=0;
|
||||
Nlzb+=16;
|
||||
if (Nlzb > 0xff)
|
||||
{
|
||||
Nlzb=0x90;
|
||||
Nhfb >>= 1;
|
||||
}
|
||||
OldAvr2=AvrLn2;
|
||||
|
||||
unsigned int BitField=fgetbits();
|
||||
if (AvrLn2 >= 122)
|
||||
Length=DecodeNum(BitField,STARTL2,DecL2,PosL2);
|
||||
else
|
||||
if (AvrLn2 >= 64)
|
||||
Length=DecodeNum(BitField,STARTL1,DecL1,PosL1);
|
||||
else
|
||||
if (BitField < 0x100)
|
||||
{
|
||||
Length=BitField;
|
||||
faddbits(16);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (Length=0;((BitField<<Length)&0x8000)==0;Length++)
|
||||
;
|
||||
faddbits(Length+1);
|
||||
}
|
||||
|
||||
AvrLn2 += Length;
|
||||
AvrLn2 -= AvrLn2 >> 5;
|
||||
|
||||
BitField=fgetbits();
|
||||
if (AvrPlcB > 0x28ff)
|
||||
DistancePlace=DecodeNum(BitField,STARTHF2,DecHf2,PosHf2);
|
||||
else
|
||||
if (AvrPlcB > 0x6ff)
|
||||
DistancePlace=DecodeNum(BitField,STARTHF1,DecHf1,PosHf1);
|
||||
else
|
||||
DistancePlace=DecodeNum(BitField,STARTHF0,DecHf0,PosHf0);
|
||||
|
||||
AvrPlcB += DistancePlace;
|
||||
AvrPlcB -= AvrPlcB >> 8;
|
||||
while (1)
|
||||
{
|
||||
Distance = ChSetB[DistancePlace & 0xff];
|
||||
NewDistancePlace = NToPlB[Distance++ & 0xff]++;
|
||||
if (!(Distance & 0xff))
|
||||
CorrHuff(ChSetB,NToPlB);
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
ChSetB[DistancePlace]=ChSetB[NewDistancePlace];
|
||||
ChSetB[NewDistancePlace]=Distance;
|
||||
|
||||
Distance=((Distance & 0xff00) | (fgetbits() >> 8)) >> 1;
|
||||
faddbits(7);
|
||||
|
||||
OldAvr3=AvrLn3;
|
||||
if (Length!=1 && Length!=4)
|
||||
if (Length==0 && Distance <= MaxDist3)
|
||||
{
|
||||
AvrLn3++;
|
||||
AvrLn3 -= AvrLn3 >> 8;
|
||||
}
|
||||
else
|
||||
if (AvrLn3 > 0)
|
||||
AvrLn3--;
|
||||
Length+=3;
|
||||
if (Distance >= MaxDist3)
|
||||
Length++;
|
||||
if (Distance <= 256)
|
||||
Length+=8;
|
||||
if (OldAvr3 > 0xb0 || AvrPlc >= 0x2a00 && OldAvr2 < 0x40)
|
||||
MaxDist3=0x7f00;
|
||||
else
|
||||
MaxDist3=0x2001;
|
||||
OldDist[OldDistPtr++]=Distance;
|
||||
OldDistPtr = OldDistPtr & 3;
|
||||
LastLength=Length;
|
||||
LastDist=Distance;
|
||||
OldCopyString(Distance,Length);
|
||||
}
|
||||
|
||||
|
||||
void Unpack::HuffDecode()
|
||||
{
|
||||
unsigned int CurByte,NewBytePlace;
|
||||
unsigned int Length;
|
||||
unsigned int Distance;
|
||||
int BytePlace;
|
||||
|
||||
unsigned int BitField=fgetbits();
|
||||
|
||||
if (AvrPlc > 0x75ff)
|
||||
BytePlace=DecodeNum(BitField,STARTHF4,DecHf4,PosHf4);
|
||||
else
|
||||
if (AvrPlc > 0x5dff)
|
||||
BytePlace=DecodeNum(BitField,STARTHF3,DecHf3,PosHf3);
|
||||
else
|
||||
if (AvrPlc > 0x35ff)
|
||||
BytePlace=DecodeNum(BitField,STARTHF2,DecHf2,PosHf2);
|
||||
else
|
||||
if (AvrPlc > 0x0dff)
|
||||
BytePlace=DecodeNum(BitField,STARTHF1,DecHf1,PosHf1);
|
||||
else
|
||||
BytePlace=DecodeNum(BitField,STARTHF0,DecHf0,PosHf0);
|
||||
BytePlace&=0xff;
|
||||
if (StMode)
|
||||
{
|
||||
if (BytePlace==0 && BitField > 0xfff)
|
||||
BytePlace=0x100;
|
||||
if (--BytePlace==-1)
|
||||
{
|
||||
BitField=fgetbits();
|
||||
faddbits(1);
|
||||
if (BitField & 0x8000)
|
||||
{
|
||||
NumHuf=StMode=0;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
Length = (BitField & 0x4000) ? 4 : 3;
|
||||
faddbits(1);
|
||||
Distance=DecodeNum(fgetbits(),STARTHF2,DecHf2,PosHf2);
|
||||
Distance = (Distance << 5) | (fgetbits() >> 11);
|
||||
faddbits(5);
|
||||
OldCopyString(Distance,Length);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
if (NumHuf++ >= 16 && FlagsCnt==0)
|
||||
StMode=1;
|
||||
AvrPlc += BytePlace;
|
||||
AvrPlc -= AvrPlc >> 8;
|
||||
Nhfb+=16;
|
||||
if (Nhfb > 0xff)
|
||||
{
|
||||
Nhfb=0x90;
|
||||
Nlzb >>= 1;
|
||||
}
|
||||
|
||||
Window[UnpPtr++]=(byte)(ChSet[BytePlace]>>8);
|
||||
--DestUnpSize;
|
||||
|
||||
while (1)
|
||||
{
|
||||
CurByte=ChSet[BytePlace];
|
||||
NewBytePlace=NToPl[CurByte++ & 0xff]++;
|
||||
if ((CurByte & 0xff) > 0xa1)
|
||||
CorrHuff(ChSet,NToPl);
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
ChSet[BytePlace]=ChSet[NewBytePlace];
|
||||
ChSet[NewBytePlace]=CurByte;
|
||||
}
|
||||
|
||||
|
||||
void Unpack::GetFlagsBuf()
|
||||
{
|
||||
unsigned int Flags,NewFlagsPlace;
|
||||
unsigned int FlagsPlace=DecodeNum(fgetbits(),STARTHF2,DecHf2,PosHf2);
|
||||
|
||||
while (1)
|
||||
{
|
||||
Flags=ChSetC[FlagsPlace];
|
||||
FlagBuf=Flags>>8;
|
||||
NewFlagsPlace=NToPlC[Flags++ & 0xff]++;
|
||||
if ((Flags & 0xff) != 0)
|
||||
break;
|
||||
CorrHuff(ChSetC,NToPlC);
|
||||
}
|
||||
|
||||
ChSetC[FlagsPlace]=ChSetC[NewFlagsPlace];
|
||||
ChSetC[NewFlagsPlace]=Flags;
|
||||
}
|
||||
|
||||
|
||||
void Unpack::OldUnpInitData(int Solid)
|
||||
{
|
||||
if (!Solid)
|
||||
{
|
||||
AvrPlcB=AvrLn1=AvrLn2=AvrLn3=NumHuf=Buf60=0;
|
||||
AvrPlc=0x3500;
|
||||
MaxDist3=0x2001;
|
||||
Nhfb=Nlzb=0x80;
|
||||
}
|
||||
FlagsCnt=0;
|
||||
FlagBuf=0;
|
||||
StMode=0;
|
||||
LCount=0;
|
||||
ReadTop=0;
|
||||
}
|
||||
|
||||
|
||||
void Unpack::InitHuff()
|
||||
{
|
||||
for (unsigned int I=0;I<256;I++)
|
||||
{
|
||||
Place[I]=PlaceA[I]=PlaceB[I]=I;
|
||||
PlaceC[I]=(~I+1) & 0xff;
|
||||
ChSet[I]=ChSetB[I]=I<<8;
|
||||
ChSetA[I]=I;
|
||||
ChSetC[I]=((~I+1) & 0xff)<<8;
|
||||
}
|
||||
memset(NToPl,0,sizeof(NToPl));
|
||||
memset(NToPlB,0,sizeof(NToPlB));
|
||||
memset(NToPlC,0,sizeof(NToPlC));
|
||||
CorrHuff(ChSetB,NToPlB);
|
||||
}
|
||||
|
||||
|
||||
void Unpack::CorrHuff(unsigned int *CharSet,unsigned int *NumToPlace)
|
||||
{
|
||||
int I,J;
|
||||
for (I=7;I>=0;I--)
|
||||
for (J=0;J<32;J++,CharSet++)
|
||||
*CharSet=(*CharSet & ~0xff) | I;
|
||||
memset(NumToPlace,0,sizeof(NToPl));
|
||||
for (I=6;I>=0;I--)
|
||||
NumToPlace[I]=(7-I)*32;
|
||||
}
|
||||
|
||||
|
||||
void Unpack::OldCopyString(unsigned int Distance,unsigned int Length)
|
||||
{
|
||||
DestUnpSize-=Length;
|
||||
while (Length--)
|
||||
{
|
||||
Window[UnpPtr]=Window[(UnpPtr-Distance) & MAXWINMASK];
|
||||
UnpPtr=(UnpPtr+1) & MAXWINMASK;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
unsigned int Unpack::DecodeNum(int Num,unsigned int StartPos,
|
||||
const unsigned int *DecTab,const unsigned int *PosTab)
|
||||
{
|
||||
int I;
|
||||
for (Num&=0xfff0,I=0;DecTab[I]<=Num;I++)
|
||||
StartPos++;
|
||||
faddbits(StartPos);
|
||||
return(((Num-(I ? DecTab[I-1]:0))>>(16-StartPos))+PosTab[StartPos]);
|
||||
}
|
||||
#endif
|
@ -1,394 +0,0 @@
|
||||
// #included by unpack.cpp
|
||||
#ifdef RAR_COMMON_HPP
|
||||
#include "rar.hpp"
|
||||
|
||||
// Presumably these optimizations give similar speedup as those for CopyString in unpack.cpp
|
||||
void Unpack::CopyString20(unsigned int Length,unsigned int Distance)
|
||||
{
|
||||
LastDist=OldDist[OldDistPtr++ & 3]=Distance;
|
||||
LastLength=Length;
|
||||
DestUnpSize-=Length;
|
||||
|
||||
unsigned UnpPtr = this->UnpPtr; // cache in register
|
||||
byte* const Window = this->Window; // cache in register
|
||||
|
||||
unsigned int DestPtr=UnpPtr-Distance;
|
||||
if (UnpPtr<MAXWINSIZE-300 && DestPtr<MAXWINSIZE-300)
|
||||
{
|
||||
this->UnpPtr += Length;
|
||||
if ( Distance < Length ) // can't use memcpy when source and dest overlap
|
||||
{
|
||||
Window[UnpPtr++]=Window[DestPtr++];
|
||||
Window[UnpPtr++]=Window[DestPtr++];
|
||||
while (Length>2)
|
||||
{
|
||||
Length--;
|
||||
Window[UnpPtr++]=Window[DestPtr++];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy( &Window[UnpPtr], &Window[DestPtr], Length );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (Length--)
|
||||
{
|
||||
Window[UnpPtr]=Window[DestPtr++ & MAXWINMASK];
|
||||
UnpPtr=(UnpPtr+1) & MAXWINMASK;
|
||||
}
|
||||
this->UnpPtr = UnpPtr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Unpack::Unpack20(bool Solid)
|
||||
{
|
||||
const
|
||||
static unsigned char LDecode[]={0,1,2,3,4,5,6,7,8,10,12,14,16,20,24,28,32,40,48,56,64,80,96,112,128,160,192,224};
|
||||
const
|
||||
static unsigned char LBits[]= {0,0,0,0,0,0,0,0,1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5};
|
||||
const
|
||||
static int DDecode[]={0,1,2,3,4,6,8,12,16,24,32,48,64,96,128,192,256,384,512,768,1024,1536,2048,3072,4096,6144,8192,12288,16384,24576,32768U,49152U,65536,98304,131072,196608,262144,327680,393216,458752,524288,589824,655360,720896,786432,851968,917504,983040};
|
||||
const
|
||||
static unsigned char DBits[]= {0,0,0,0,1,1,2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16};
|
||||
const
|
||||
static unsigned char SDDecode[]={0,4,8,16,32,64,128,192};
|
||||
const
|
||||
static unsigned char SDBits[]= {2,2,3, 4, 5, 6, 6, 6};
|
||||
unsigned int Bits;
|
||||
|
||||
if (Suspended)
|
||||
UnpPtr=WrPtr;
|
||||
else
|
||||
{
|
||||
UnpInitData(Solid);
|
||||
if (!UnpReadBuf())
|
||||
return;
|
||||
if (!Solid)
|
||||
if (!ReadTables20())
|
||||
return;
|
||||
--DestUnpSize;
|
||||
}
|
||||
|
||||
while (is64plus(DestUnpSize))
|
||||
{
|
||||
UnpPtr&=MAXWINMASK;
|
||||
|
||||
if (InAddr>ReadTop-30)
|
||||
if (!UnpReadBuf())
|
||||
break;
|
||||
if (((WrPtr-UnpPtr) & MAXWINMASK)<270 && WrPtr!=UnpPtr)
|
||||
{
|
||||
OldUnpWriteBuf();
|
||||
if (Suspended)
|
||||
return;
|
||||
}
|
||||
if (UnpAudioBlock)
|
||||
{
|
||||
int AudioNumber=DecodeNumber((struct Decode *)&MD[UnpCurChannel]);
|
||||
|
||||
if (AudioNumber==256)
|
||||
{
|
||||
if (!ReadTables20())
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
Window[UnpPtr++]=DecodeAudio(AudioNumber);
|
||||
if (++UnpCurChannel==UnpChannels)
|
||||
UnpCurChannel=0;
|
||||
--DestUnpSize;
|
||||
continue;
|
||||
}
|
||||
|
||||
int Number=DecodeNumber((struct Decode *)&LD);
|
||||
if (Number<256)
|
||||
{
|
||||
Window[UnpPtr++]=(byte)Number;
|
||||
--DestUnpSize;
|
||||
continue;
|
||||
}
|
||||
if (Number>269)
|
||||
{
|
||||
int Length=LDecode[Number-=270]+3;
|
||||
if ((Bits=LBits[Number])>0)
|
||||
{
|
||||
Length+=getbits()>>(16-Bits);
|
||||
addbits(Bits);
|
||||
}
|
||||
|
||||
int DistNumber=DecodeNumber((struct Decode *)&DD);
|
||||
unsigned int Distance=DDecode[DistNumber]+1;
|
||||
if ((Bits=DBits[DistNumber])>0)
|
||||
{
|
||||
Distance+=getbits()>>(16-Bits);
|
||||
addbits(Bits);
|
||||
}
|
||||
|
||||
if (Distance>=0x2000)
|
||||
{
|
||||
Length++;
|
||||
if (Distance>=0x40000L)
|
||||
Length++;
|
||||
}
|
||||
|
||||
CopyString20(Length,Distance);
|
||||
continue;
|
||||
}
|
||||
if (Number==269)
|
||||
{
|
||||
if (!ReadTables20())
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
if (Number==256)
|
||||
{
|
||||
CopyString20(LastLength,LastDist);
|
||||
continue;
|
||||
}
|
||||
if (Number<261)
|
||||
{
|
||||
unsigned int Distance=OldDist[(OldDistPtr-(Number-256)) & 3];
|
||||
int LengthNumber=DecodeNumber((struct Decode *)&RD);
|
||||
int Length=LDecode[LengthNumber]+2;
|
||||
if ((Bits=LBits[LengthNumber])>0)
|
||||
{
|
||||
Length+=getbits()>>(16-Bits);
|
||||
addbits(Bits);
|
||||
}
|
||||
if (Distance>=0x101)
|
||||
{
|
||||
Length++;
|
||||
if (Distance>=0x2000)
|
||||
{
|
||||
Length++;
|
||||
if (Distance>=0x40000)
|
||||
Length++;
|
||||
}
|
||||
}
|
||||
CopyString20(Length,Distance);
|
||||
continue;
|
||||
}
|
||||
if (Number<270)
|
||||
{
|
||||
unsigned int Distance=SDDecode[Number-=261]+1;
|
||||
if ((Bits=SDBits[Number])>0)
|
||||
{
|
||||
Distance+=getbits()>>(16-Bits);
|
||||
addbits(Bits);
|
||||
}
|
||||
CopyString20(2,Distance);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
ReadLastTables();
|
||||
OldUnpWriteBuf();
|
||||
}
|
||||
|
||||
|
||||
bool Unpack::ReadTables20()
|
||||
{
|
||||
byte BitLength[BC20];
|
||||
unsigned char Table[MC20*4];
|
||||
int TableSize,N,I;
|
||||
if (InAddr>ReadTop-25)
|
||||
if (!UnpReadBuf())
|
||||
return(false);
|
||||
unsigned int BitField=getbits();
|
||||
UnpAudioBlock=(BitField & 0x8000);
|
||||
|
||||
if (!(BitField & 0x4000))
|
||||
memset(UnpOldTable20,0,sizeof(UnpOldTable20));
|
||||
addbits(2);
|
||||
|
||||
if (UnpAudioBlock)
|
||||
{
|
||||
UnpChannels=((BitField>>12) & 3)+1;
|
||||
if (UnpCurChannel>=UnpChannels)
|
||||
UnpCurChannel=0;
|
||||
addbits(2);
|
||||
TableSize=MC20*UnpChannels;
|
||||
}
|
||||
else
|
||||
TableSize=NC20+DC20+RC20;
|
||||
|
||||
for (I=0;I<BC20;I++)
|
||||
{
|
||||
BitLength[I]=(byte)(getbits() >> 12);
|
||||
addbits(4);
|
||||
}
|
||||
MakeDecodeTables(BitLength,(struct Decode *)&BD,BC20);
|
||||
I=0;
|
||||
while (I<TableSize)
|
||||
{
|
||||
if (InAddr>ReadTop-5)
|
||||
if (!UnpReadBuf())
|
||||
return(false);
|
||||
int Number=DecodeNumber((struct Decode *)&BD);
|
||||
if (Number<16)
|
||||
{
|
||||
Table[I]=(Number+UnpOldTable20[I]) & 0xf;
|
||||
I++;
|
||||
}
|
||||
else
|
||||
if (Number==16)
|
||||
{
|
||||
N=(getbits() >> 14)+3;
|
||||
addbits(2);
|
||||
while (N-- > 0 && I<TableSize)
|
||||
{
|
||||
Table[I]=Table[I-1];
|
||||
I++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Number==17)
|
||||
{
|
||||
N=(getbits() >> 13)+3;
|
||||
addbits(3);
|
||||
}
|
||||
else
|
||||
{
|
||||
N=(getbits() >> 9)+11;
|
||||
addbits(7);
|
||||
}
|
||||
while (N-- > 0 && I<TableSize)
|
||||
Table[I++]=0;
|
||||
}
|
||||
}
|
||||
if (InAddr>ReadTop)
|
||||
return(true);
|
||||
if (UnpAudioBlock)
|
||||
for (I=0;I<UnpChannels;I++)
|
||||
MakeDecodeTables(&Table[I*MC20],(struct Decode *)&MD[I],MC20);
|
||||
else
|
||||
{
|
||||
MakeDecodeTables(&Table[0],(struct Decode *)&LD,NC20);
|
||||
MakeDecodeTables(&Table[NC20],(struct Decode *)&DD,DC20);
|
||||
MakeDecodeTables(&Table[NC20+DC20],(struct Decode *)&RD,RC20);
|
||||
}
|
||||
memcpy(UnpOldTable20,Table,sizeof(UnpOldTable20));
|
||||
return(true);
|
||||
}
|
||||
|
||||
|
||||
void Unpack::ReadLastTables()
|
||||
{
|
||||
if (ReadTop>=InAddr+5)
|
||||
if (UnpAudioBlock)
|
||||
{
|
||||
if (DecodeNumber((struct Decode *)&MD[UnpCurChannel])==256)
|
||||
ReadTables20();
|
||||
}
|
||||
else
|
||||
if (DecodeNumber((struct Decode *)&LD)==269)
|
||||
ReadTables20();
|
||||
}
|
||||
|
||||
|
||||
void Unpack::UnpInitData20(int Solid)
|
||||
{
|
||||
if (!Solid)
|
||||
{
|
||||
UnpAudioBlock=UnpChannelDelta=UnpCurChannel=0;
|
||||
UnpChannels=1;
|
||||
|
||||
memset(AudV,0,sizeof(AudV));
|
||||
memset(UnpOldTable20,0,sizeof(UnpOldTable20));
|
||||
memset(MD,0,sizeof(MD));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
byte Unpack::DecodeAudio(int Delta)
|
||||
{
|
||||
struct AudioVariables *V=&AudV[UnpCurChannel];
|
||||
V->ByteCount++;
|
||||
V->D4=V->D3;
|
||||
V->D3=V->D2;
|
||||
V->D2=V->LastDelta-V->D1;
|
||||
V->D1=V->LastDelta;
|
||||
int PCh=8*V->LastChar+V->K1*V->D1+V->K2*V->D2+V->K3*V->D3+V->K4*V->D4+V->K5*UnpChannelDelta;
|
||||
PCh=(PCh>>3) & 0xFF;
|
||||
|
||||
unsigned int Ch=PCh-Delta;
|
||||
|
||||
int D=((signed char)Delta)<<3;
|
||||
|
||||
V->Dif[0]+=abs(D);
|
||||
V->Dif[1]+=abs(D-V->D1);
|
||||
V->Dif[2]+=abs(D+V->D1);
|
||||
V->Dif[3]+=abs(D-V->D2);
|
||||
V->Dif[4]+=abs(D+V->D2);
|
||||
V->Dif[5]+=abs(D-V->D3);
|
||||
V->Dif[6]+=abs(D+V->D3);
|
||||
V->Dif[7]+=abs(D-V->D4);
|
||||
V->Dif[8]+=abs(D+V->D4);
|
||||
V->Dif[9]+=abs(D-UnpChannelDelta);
|
||||
V->Dif[10]+=abs(D+UnpChannelDelta);
|
||||
|
||||
UnpChannelDelta=V->LastDelta=(signed char)(Ch-V->LastChar);
|
||||
V->LastChar=Ch;
|
||||
|
||||
if ((V->ByteCount & 0x1F)==0)
|
||||
{
|
||||
unsigned int MinDif=V->Dif[0],NumMinDif=0;
|
||||
V->Dif[0]=0;
|
||||
for (int I=1;I<sizeof(V->Dif)/sizeof(V->Dif[0]);I++)
|
||||
{
|
||||
if (V->Dif[I]<MinDif)
|
||||
{
|
||||
MinDif=V->Dif[I];
|
||||
NumMinDif=I;
|
||||
}
|
||||
V->Dif[I]=0;
|
||||
}
|
||||
switch(NumMinDif)
|
||||
{
|
||||
case 1:
|
||||
if (V->K1>=-16)
|
||||
V->K1--;
|
||||
break;
|
||||
case 2:
|
||||
if (V->K1<16)
|
||||
V->K1++;
|
||||
break;
|
||||
case 3:
|
||||
if (V->K2>=-16)
|
||||
V->K2--;
|
||||
break;
|
||||
case 4:
|
||||
if (V->K2<16)
|
||||
V->K2++;
|
||||
break;
|
||||
case 5:
|
||||
if (V->K3>=-16)
|
||||
V->K3--;
|
||||
break;
|
||||
case 6:
|
||||
if (V->K3<16)
|
||||
V->K3++;
|
||||
break;
|
||||
case 7:
|
||||
if (V->K4>=-16)
|
||||
V->K4--;
|
||||
break;
|
||||
case 8:
|
||||
if (V->K4<16)
|
||||
V->K4++;
|
||||
break;
|
||||
case 9:
|
||||
if (V->K5>=-16)
|
||||
V->K5--;
|
||||
break;
|
||||
case 10:
|
||||
if (V->K5<16)
|
||||
V->K5++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return((byte)Ch);
|
||||
}
|
||||
#endif
|
@ -1,350 +0,0 @@
|
||||
// unrar_core 3.8.5. http://www.slack.net/~ant/
|
||||
|
||||
#include "unrar.h"
|
||||
|
||||
#include "rar.hpp"
|
||||
#include <assert.h>
|
||||
|
||||
// This source code is a heavily modified version based on the unrar package.
|
||||
// It may not be used to develop a RAR (WinRAR) compatible archiver.
|
||||
// See unrar/license.txt for copyright and licensing.
|
||||
|
||||
// Same as printf when debugging, otherwise 0
|
||||
#ifndef debug_printf
|
||||
#define debug_printf 1 ? (void)0 : (void)
|
||||
#endif
|
||||
|
||||
// If expr != unrar_ok, returns its value
|
||||
#define RETURN_ERR( expr ) \
|
||||
do {\
|
||||
unrar_err_t err_;\
|
||||
if ( (err_ = (expr)) != unrar_ok )\
|
||||
return err_;\
|
||||
} while ( 0 )
|
||||
|
||||
|
||||
// Receives errors reported from deep within library.
|
||||
// MUST be macro.
|
||||
#define NONLOCAL_ERROR( p ) \
|
||||
setjmp( p->Arc.jmp_env )
|
||||
|
||||
void Rar_Error_Handler::ReportError( unrar_err_t err )
|
||||
{
|
||||
if ( err )
|
||||
longjmp( jmp_env, err );
|
||||
}
|
||||
|
||||
void Rar_Error_Handler::MemoryError()
|
||||
{
|
||||
ReportError( unrar_err_memory );
|
||||
}
|
||||
|
||||
|
||||
//// Internal
|
||||
|
||||
unrar_t::unrar_t() :
|
||||
Buffer( &Arc )
|
||||
{
|
||||
Arc.user_read = NULL;
|
||||
Arc.user_write = NULL;
|
||||
Arc.Tell_ = 0;
|
||||
Arc.write_error = unrar_ok;
|
||||
data_ = NULL;
|
||||
own_data_ = NULL;
|
||||
close_file = NULL;
|
||||
FileCount = 0;
|
||||
Unp = NULL;
|
||||
|
||||
unrar_init();
|
||||
}
|
||||
|
||||
unrar_t::~unrar_t()
|
||||
{
|
||||
if ( Arc.write_error ) { }
|
||||
|
||||
if ( close_file )
|
||||
close_file( Arc.user_read_data );
|
||||
|
||||
delete Unp;
|
||||
|
||||
free( own_data_ );
|
||||
}
|
||||
|
||||
// True if current file is compressed in way that affects solid extraction state
|
||||
static inline bool solid_file( const unrar_t* p )
|
||||
{
|
||||
return p->Arc.Solid &&
|
||||
p->Arc.NewLhd.Method != 0x30 &&
|
||||
p->Arc.NewLhd.FullPackSize != 0;
|
||||
}
|
||||
|
||||
static void update_solid_pos( unrar_t* p )
|
||||
{
|
||||
if ( p->solid_pos == p->Arc.CurBlockPos )
|
||||
p->solid_pos = p->Arc.NextBlockPos;
|
||||
}
|
||||
|
||||
static unrar_err_t extract_( unrar_t* p, unrar_write_func user_write, void* user_data )
|
||||
{
|
||||
assert( !p->done );
|
||||
assert( !solid_file( p ) || p->solid_pos == p->Arc.CurBlockPos );
|
||||
|
||||
if ( p->Arc.write_error ) { }
|
||||
p->Arc.write_error = unrar_ok;
|
||||
p->Arc.user_write = user_write;
|
||||
p->Arc.user_write_data = user_data;
|
||||
RETURN_ERR( p->ExtractCurrentFile( user_write == NULL ) );
|
||||
p->Arc.user_write = NULL;
|
||||
RETURN_ERR( p->Arc.write_error );
|
||||
|
||||
update_solid_pos( p );
|
||||
|
||||
return unrar_ok;
|
||||
}
|
||||
|
||||
static unrar_err_t skip_solid( unrar_t* p )
|
||||
{
|
||||
if ( !solid_file( p ) )
|
||||
{
|
||||
update_solid_pos( p );
|
||||
return unrar_ok;
|
||||
}
|
||||
|
||||
return extract_( p, NULL, NULL );
|
||||
}
|
||||
|
||||
static inline bool IsLink(uint Attr)
|
||||
{
|
||||
return((Attr & 0xF000)==0xA000);
|
||||
}
|
||||
|
||||
static unrar_err_t next_( unrar_t* p, bool skipping_solid )
|
||||
{
|
||||
if ( p->done )
|
||||
return unrar_err_arc_eof;
|
||||
|
||||
free( p->own_data_ );
|
||||
p->own_data_ = NULL;
|
||||
p->data_ = NULL;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
p->Arc.SeekToNext();
|
||||
unrar_err_t const err = p->Arc.ReadHeader();
|
||||
if ( err != unrar_err_arc_eof )
|
||||
RETURN_ERR( err );
|
||||
//else
|
||||
// debug_printf( "unrar: Didn't end with ENDARC_HEAD\n" ); // rar -en causes this
|
||||
|
||||
HEADER_TYPE const type = (HEADER_TYPE) p->Arc.GetHeaderType();
|
||||
|
||||
if ( err != unrar_ok || type == ENDARC_HEAD )
|
||||
{
|
||||
p->done = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( type != FILE_HEAD )
|
||||
{
|
||||
// Skip non-files
|
||||
if ( type != NEWSUB_HEAD && type != PROTECT_HEAD && type != SIGN_HEAD && type != SUB_HEAD )
|
||||
debug_printf( "unrar: Skipping unknown block type: %X\n", (unsigned) type );
|
||||
|
||||
update_solid_pos( p );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Update even for non-solid files, in case it's not extracted
|
||||
if ( !solid_file( p ) )
|
||||
update_solid_pos( p );
|
||||
|
||||
if ( p->Arc.IsArcLabel() )
|
||||
{
|
||||
// Ignore labels
|
||||
}
|
||||
else if ( IsLink( p->Arc.NewLhd.FileAttr ) )
|
||||
{
|
||||
// Ignore links
|
||||
|
||||
p->update_first_file_pos();
|
||||
p->FileCount++; // Links are treated as files
|
||||
}
|
||||
else if ( p->Arc.IsArcDir() )
|
||||
{
|
||||
// Ignore directories
|
||||
}
|
||||
else
|
||||
{
|
||||
p->info.size = p->Arc.NewLhd.UnpSize;
|
||||
p->info.name = p->Arc.NewLhd.FileName;
|
||||
p->info.name_w = p->Arc.NewLhd.FileNameW;
|
||||
p->info.is_unicode = (p->Arc.NewLhd.Flags & LHD_UNICODE) != 0;
|
||||
p->info.dos_date = p->Arc.NewLhd.mtime.time;
|
||||
p->info.crc = p->Arc.NewLhd.FileCRC;
|
||||
p->info.is_crc32 = !p->Arc.OldFormat;
|
||||
|
||||
// Stop for files
|
||||
break;
|
||||
}
|
||||
|
||||
// Original code assumed that non-file items were never solid compressed
|
||||
check( !solid_file( p ) );
|
||||
|
||||
// Skip non-file solid-compressed items (original code assumed there were none)
|
||||
if ( skipping_solid )
|
||||
RETURN_ERR( skip_solid( p ) );
|
||||
}
|
||||
}
|
||||
|
||||
return unrar_ok;
|
||||
}
|
||||
|
||||
static unrar_err_t open_( unrar_t* p, unrar_read_func read, void* user_data )
|
||||
{
|
||||
p->Arc.user_read = read;
|
||||
p->Arc.user_read_data = user_data;
|
||||
|
||||
RETURN_ERR( p->Arc.IsArchive() );
|
||||
|
||||
p->begin_pos = p->Arc.NextBlockPos;
|
||||
p->solid_pos = p->Arc.NextBlockPos;
|
||||
p->first_file_pos = INT_MAX;
|
||||
p->done = false;
|
||||
|
||||
return unrar_ok;
|
||||
}
|
||||
|
||||
|
||||
//// Interface
|
||||
|
||||
// Needed when user read throws exception
|
||||
struct unrar_ptr {
|
||||
unrar_t* p;
|
||||
unrar_ptr() { p = NULL; }
|
||||
~unrar_ptr() { delete p; }
|
||||
};
|
||||
|
||||
unrar_err_t unrar_open_custom( unrar_t** impl_out, unrar_read_func read, void* user_data )
|
||||
{
|
||||
*impl_out = NULL;
|
||||
|
||||
unrar_ptr ptr;
|
||||
ptr.p = new unrar_t;
|
||||
if ( !ptr.p )
|
||||
return unrar_err_memory;
|
||||
|
||||
RETURN_ERR( NONLOCAL_ERROR( ptr.p ) );
|
||||
RETURN_ERR( open_( ptr.p, read, user_data ) );
|
||||
RETURN_ERR( next_( ptr.p, false ) );
|
||||
|
||||
*impl_out = ptr.p;
|
||||
ptr.p = NULL;
|
||||
|
||||
//delete ptr.p; // done automatically at end of function
|
||||
|
||||
return unrar_ok;
|
||||
}
|
||||
|
||||
void unrar_close( unrar_t* ar )
|
||||
{
|
||||
delete ar;
|
||||
}
|
||||
|
||||
unrar_bool unrar_done( const unrar_t* p )
|
||||
{
|
||||
return p->done;
|
||||
}
|
||||
|
||||
unrar_err_t unrar_next( unrar_t* p )
|
||||
{
|
||||
assert( !unrar_done( p ) );
|
||||
|
||||
RETURN_ERR( NONLOCAL_ERROR( p ) );
|
||||
return next_( p, false );
|
||||
}
|
||||
|
||||
const unrar_info_t* unrar_info( unrar_t const* p )
|
||||
{
|
||||
assert( !unrar_done( p ) );
|
||||
|
||||
return &p->info;
|
||||
}
|
||||
|
||||
unrar_pos_t unrar_tell( const unrar_t* p )
|
||||
{
|
||||
return p->Arc.CurBlockPos;
|
||||
}
|
||||
|
||||
unrar_err_t unrar_seek( unrar_t* p, unrar_pos_t n )
|
||||
{
|
||||
p->Arc.NextBlockPos = n;
|
||||
p->done = false;
|
||||
p->FileCount = (n <= p->first_file_pos ? 0 : 1);
|
||||
|
||||
return unrar_next( p );
|
||||
}
|
||||
|
||||
unrar_err_t unrar_rewind( unrar_t* p )
|
||||
{
|
||||
return unrar_seek( p, p->begin_pos );
|
||||
}
|
||||
|
||||
unrar_err_t unrar_try_extract( const unrar_t* p )
|
||||
{
|
||||
assert( !unrar_done( p ) );
|
||||
|
||||
return ((unrar_t*) p)->ExtractCurrentFile( true, true );
|
||||
}
|
||||
|
||||
static unrar_err_t reopen( unrar_t* p )
|
||||
{
|
||||
// Save and restore archive reader
|
||||
unrar_read_func read = p->Arc.user_read;
|
||||
void* user_data = p->Arc.user_read_data;
|
||||
|
||||
void (*close_file)( void* ) = p->close_file;
|
||||
p->close_file = NULL;
|
||||
|
||||
p->~unrar_t();
|
||||
new (p) unrar_t;
|
||||
|
||||
p->close_file = close_file;
|
||||
|
||||
return open_( p, read, user_data );
|
||||
}
|
||||
|
||||
unrar_err_t unrar_extract_custom( unrar_t* p, unrar_write_func user_write, void* user_data )
|
||||
{
|
||||
assert( !unrar_done( p ) );
|
||||
|
||||
RETURN_ERR( NONLOCAL_ERROR( p ) );
|
||||
|
||||
if ( solid_file( p ) )
|
||||
{
|
||||
unrar_pos_t pos = p->Arc.CurBlockPos;
|
||||
if ( p->solid_pos != pos )
|
||||
{
|
||||
// Next file to solid extract isn't current one
|
||||
|
||||
if ( p->solid_pos > pos )
|
||||
RETURN_ERR( reopen( p ) );
|
||||
else
|
||||
p->Arc.NextBlockPos = p->solid_pos;
|
||||
|
||||
RETURN_ERR( next_( p, true ) );
|
||||
|
||||
// Keep extracting until solid position is at desired file
|
||||
while ( !p->done && p->solid_pos < pos )
|
||||
{
|
||||
RETURN_ERR( skip_solid( p ) );
|
||||
RETURN_ERR( next_( p, true ) );
|
||||
}
|
||||
|
||||
// Be sure we're at right file
|
||||
if ( p->solid_pos != pos || p->Arc.CurBlockPos != pos )
|
||||
return unrar_err_corrupt;
|
||||
}
|
||||
}
|
||||
|
||||
return extract_( p, user_write, user_data );
|
||||
}
|
@ -1,164 +0,0 @@
|
||||
/** RAR archive scanning and extraction \file */
|
||||
|
||||
/* unrar_core 3.8.5 */
|
||||
#ifndef UNRAR_H
|
||||
#define UNRAR_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <limits.h>
|
||||
|
||||
#if !defined (UNRAR_NO_LONG_LONG) && defined (LLONG_MAX)
|
||||
typedef long long unrar_long_long;
|
||||
#else
|
||||
typedef long unrar_long_long;
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/** Error code, or 0 if function was successful. See Errors for more. Except
|
||||
where noted, once an operation returns an error, that archive should not be
|
||||
used any further, other than with unrar_close(). */
|
||||
#ifndef unrar_err_t /* (#ifndef allows better testing of library) */
|
||||
typedef int unrar_err_t;
|
||||
#endif
|
||||
|
||||
/** First parameter of most functions is unrar_t*, or const unrar_t* if nothing
|
||||
is changed. */
|
||||
typedef struct unrar_t unrar_t;
|
||||
|
||||
/** File position */
|
||||
typedef unrar_long_long unrar_pos_t;
|
||||
|
||||
/** Boolean, where 0 is false and 1 is true */
|
||||
typedef int unrar_bool;
|
||||
|
||||
|
||||
/******** Open/close ********/
|
||||
|
||||
/** Initializes static tables used by library. Automatically called by
|
||||
unrar_open(). OK to call more than once. */
|
||||
void unrar_init( void );
|
||||
|
||||
/** Opens archive and points *out at it. If error, sets *out to NULL. */
|
||||
unrar_err_t unrar_open( unrar_t** out, const char path [] );
|
||||
|
||||
/** User archive read callback. When called, user_data is a copy of that passed
|
||||
to unrar_open_custom(). Callback must do the following: Read avail bytes from
|
||||
file at offset pos and set *count to avail, where avail is the lesser of *count
|
||||
and file_size-pos. Put read bytes into *out and return unrar_ok. If fewer than
|
||||
avail bytes could be read successfully, return a non-zero error code. */
|
||||
typedef unrar_err_t (*unrar_read_func)( void* user_data,
|
||||
void* out, int* count, unrar_pos_t pos );
|
||||
|
||||
/** Same as unrar_open(), except data is read using supplied function rather
|
||||
than from file. */
|
||||
unrar_err_t unrar_open_custom( unrar_t** unrar_out,
|
||||
unrar_read_func, void* user_data );
|
||||
|
||||
/** Closes archive and frees memory. OK to pass NULL. */
|
||||
void unrar_close( unrar_t* );
|
||||
|
||||
|
||||
/******** Scanning ********/
|
||||
|
||||
/** True if at end of archive. Must be called after unrar_open() or
|
||||
unrar_rewind(), as an archive might contain no files. */
|
||||
unrar_bool unrar_done( const unrar_t* );
|
||||
|
||||
/** Goes to next file in archive. If there are no more files, unrar_done() will
|
||||
now return true. */
|
||||
unrar_err_t unrar_next( unrar_t* );
|
||||
|
||||
/** Goes back to first file in archive, as if it were just opened with
|
||||
unrar_open(). */
|
||||
unrar_err_t unrar_rewind( unrar_t* );
|
||||
|
||||
/** Position of current file in archive. Will never return zero. */
|
||||
unrar_pos_t unrar_tell( const unrar_t* );
|
||||
|
||||
/** Returns to file at previously-saved position. */
|
||||
unrar_err_t unrar_seek( unrar_t*, unrar_pos_t );
|
||||
|
||||
|
||||
/**** Info ****/
|
||||
|
||||
/** Information about current file */
|
||||
typedef struct unrar_info_t
|
||||
{
|
||||
unrar_pos_t size; /**< Uncompressed size */
|
||||
const char* name; /**< Name, in Unicode if is_unicode is true */
|
||||
const wchar_t* name_w; /**< Name in Unicode, "" if unavailable */
|
||||
unrar_bool is_unicode; /**< True if name is Unicode (UTF-8) */
|
||||
unsigned int dos_date; /**< Date in DOS-style format, 0 if unavailable */
|
||||
unsigned int crc; /**< Checksum; algorithm depends on archive */
|
||||
unrar_bool is_crc32; /**< True if crc is CRC-32 */
|
||||
} unrar_info_t;
|
||||
|
||||
/** Information about current file. Pointer is valid until unrar_next(),
|
||||
unrar_rewind(), unrar_seek(), or unrar_close(). */
|
||||
const unrar_info_t* unrar_info( const unrar_t* );
|
||||
|
||||
|
||||
/**** Extraction ****/
|
||||
|
||||
/** Returns unrar_ok if current file can be extracted, otherwise error
|
||||
indicating why it can't be extracted (too new/old compression algorithm,
|
||||
encrypted, segmented). Archive is still usable if this returns error,
|
||||
just the current file can't be extracted. */
|
||||
unrar_err_t unrar_try_extract( const unrar_t* );
|
||||
|
||||
/** Extracts at most size bytes from current file into out. If file is larger,
|
||||
discards excess bytes. If file is smaller, only writes unrar_size() bytes. */
|
||||
unrar_err_t unrar_extract( unrar_t*, void* out, unrar_pos_t size );
|
||||
|
||||
/** Extracts data to memory and returns pointer to it in *out. Pointer is
|
||||
valid until unrar_next(), unrar_rewind(), unrar_seek(), or unrar_close(). OK to
|
||||
call more than once for same file. Optimized to avoid allocating memory when
|
||||
entire file will already be kept in internal window. */
|
||||
unrar_err_t unrar_extract_mem( unrar_t* p, void const** out );
|
||||
|
||||
/** User extracted data write callback. When called, user_data is a copy of
|
||||
that passed to unrar_extract_custom(). Callback must do the following: Write
|
||||
count bytes from *in to wherever extracted data goes and return unrar_ok. If
|
||||
data cannot be written successfully, return a non-zero error code. */
|
||||
typedef unrar_err_t (*unrar_write_func)( void* user_data,
|
||||
const void* in, int count );
|
||||
|
||||
/** Extracts current file and writes data using supplied function. Any error
|
||||
it returns will be returned by this function, and archive will still be
|
||||
usable. */
|
||||
unrar_err_t unrar_extract_custom( unrar_t*,
|
||||
unrar_write_func, void* user_data );
|
||||
|
||||
|
||||
/******** Errors ********/
|
||||
|
||||
/** Error string associated with unrar error code. Always returns valid
|
||||
pointer to a C string; never returns NULL. Returns "" for unrar_ok. */
|
||||
const char* unrar_err_str( unrar_err_t );
|
||||
|
||||
enum {
|
||||
unrar_ok = 0,/**< No error; success. Guaranteed to be zero. */
|
||||
unrar_err_memory = 1,/**< Out of memory */
|
||||
unrar_err_open = 2,/**< Couldn't open file (not found/permissions) */
|
||||
unrar_err_not_arc = 3,/**< Not a RAR archive */
|
||||
unrar_err_corrupt = 4,/**< Archive is corrupt */
|
||||
unrar_err_io = 5,/**< Read failed */
|
||||
unrar_err_arc_eof = 6,/**< At end of archive; no more files */
|
||||
unrar_err_encrypted = 7,/**< Encryption not supported */
|
||||
unrar_err_segmented = 8,/**< Segmentation not supported */
|
||||
unrar_err_huge = 9,/**< Huge (2GB+) archives not supported */
|
||||
unrar_err_old_algo = 10,/**< Compressed with unsupported old algorithm */
|
||||
unrar_err_new_algo = 11,/**< Compressed with unsupported new algorithm */
|
||||
unrar_next_err = 100/**< Errors range from 0 to unrar_next_err-1 */
|
||||
};
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,170 +0,0 @@
|
||||
// Misc functions outside the core interface
|
||||
|
||||
#include "unrar.h"
|
||||
|
||||
#include "rar.hpp"
|
||||
#include <assert.h>
|
||||
|
||||
// This source code is a heavily modified version based on the unrar package.
|
||||
// It may not be used to develop a RAR (WinRAR) compatible archiver.
|
||||
// See unrar/license.txt for copyright and licensing.
|
||||
|
||||
void unrar_init()
|
||||
{
|
||||
if (CRCTab[1]==0)
|
||||
InitCRC();
|
||||
|
||||
Unpack::init_tables();
|
||||
}
|
||||
|
||||
struct unrar_extract_mem_t
|
||||
{
|
||||
char* out;
|
||||
char* end;
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
static unrar_err_t extract_write( void* user_data, const void* in, int count )
|
||||
{
|
||||
unrar_extract_mem_t* p = (unrar_extract_mem_t*) user_data;
|
||||
|
||||
unrar_pos_t remain = p->end - p->out;
|
||||
if ( remain > 0 )
|
||||
{
|
||||
if ( count > remain )
|
||||
count = remain;
|
||||
|
||||
memcpy( p->out, in, count );
|
||||
p->out += count;
|
||||
}
|
||||
|
||||
return unrar_ok;
|
||||
}
|
||||
}
|
||||
|
||||
unrar_err_t unrar_extract( unrar_t* p, void* out, unrar_pos_t size )
|
||||
{
|
||||
assert( !unrar_done( p ) );
|
||||
|
||||
unrar_extract_mem_t m;
|
||||
m.out = (char*) out;
|
||||
m.end = m.out + size;
|
||||
return unrar_extract_custom( p, &extract_write, &m );
|
||||
}
|
||||
|
||||
inline
|
||||
static bool is_entire_file( const unrar_t* p, const void* in, int count )
|
||||
{
|
||||
return (count == p->Arc.NewLhd.UnpSize && p->Unp && in == p->Unp->window_wrptr());
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
static unrar_err_t extract_mem( void* data, void const* in, int count )
|
||||
{
|
||||
unrar_t* p = (unrar_t*) data;
|
||||
|
||||
// We might have pointer to entire file
|
||||
if ( !p->data_ && is_entire_file( p, in, count ) )
|
||||
{
|
||||
p->data_ = in;
|
||||
return unrar_ok;
|
||||
}
|
||||
|
||||
// We don't have it, so allocate memory to read entire file into
|
||||
if ( !p->own_data_ )
|
||||
{
|
||||
assert( !p->data_ );
|
||||
|
||||
unrar_pos_t size = unrar_info( p )->size;
|
||||
p->own_data_ = malloc( size ? size : 1 );
|
||||
if ( !p->own_data_ )
|
||||
return unrar_err_memory;
|
||||
|
||||
p->data_ = p->own_data_;
|
||||
}
|
||||
|
||||
memcpy( (void*) p->data_, in, count );
|
||||
p->data_ = (char*) p->data_ + count;
|
||||
|
||||
return unrar_ok;
|
||||
}
|
||||
}
|
||||
|
||||
unrar_err_t unrar_extract_mem( unrar_t* p, void const** out )
|
||||
{
|
||||
assert( !unrar_done( p ) );
|
||||
|
||||
*out = NULL;
|
||||
|
||||
if ( !p->data_ )
|
||||
{
|
||||
unrar_err_t err = unrar_extract_custom( p, &extract_mem, p );
|
||||
if ( err )
|
||||
return err;
|
||||
}
|
||||
|
||||
*out = (p->own_data_ ? p->own_data_ : p->data_);
|
||||
return unrar_ok;
|
||||
}
|
||||
|
||||
const char* unrar_err_str( unrar_err_t err )
|
||||
{
|
||||
switch ( err )
|
||||
{
|
||||
case unrar_ok: return "";
|
||||
case unrar_err_memory: return "out of memory";
|
||||
case unrar_err_open: return "couldn't open RAR archive";
|
||||
case unrar_err_not_arc: return "not a RAR archive";
|
||||
case unrar_err_corrupt: return "RAR archive is corrupt";
|
||||
case unrar_err_io: return "couldn't read/write";
|
||||
case unrar_err_arc_eof: return "unexpected end of archive";
|
||||
case unrar_err_encrypted: return "encryption not supported";
|
||||
case unrar_err_segmented: return "segmentation not supported";
|
||||
case unrar_err_huge: return "huge (2GB+) archives are not supported";
|
||||
case unrar_err_old_algo: return "compressed using older algorithm than supported";
|
||||
case unrar_err_new_algo: return "compressed using newer algorithm than supported";
|
||||
}
|
||||
|
||||
assert( false );
|
||||
return "problem with RAR";
|
||||
}
|
||||
|
||||
int ComprDataIO::Read( void* p, int n )
|
||||
{
|
||||
unrar_err_t err = user_read( user_read_data, p, &n, Tell_ );
|
||||
if ( err )
|
||||
ReportError( err );
|
||||
|
||||
Tell_ += n;
|
||||
if ( Tell_ < 0 )
|
||||
ReportError( unrar_err_huge );
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void ComprDataIO::UnpWrite( byte* out, uint count )
|
||||
{
|
||||
if ( !SkipUnpCRC )
|
||||
{
|
||||
if ( write_error == unrar_ok )
|
||||
write_error = user_write( user_write_data, out, count );
|
||||
|
||||
if ( OldFormat )
|
||||
UnpFileCRC = OldCRC( (ushort) UnpFileCRC, out, count );
|
||||
else
|
||||
UnpFileCRC = CRC( UnpFileCRC, out, count );
|
||||
}
|
||||
}
|
||||
|
||||
int ComprDataIO::UnpRead( byte* out, uint count )
|
||||
{
|
||||
if ( count <= 0 )
|
||||
return 0;
|
||||
|
||||
if ( count > (uint) UnpPackedSize )
|
||||
count = UnpPackedSize;
|
||||
|
||||
int result = Read( out, count );
|
||||
UnpPackedSize -= result;
|
||||
return result;
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
// Separate file to avoid linking to f* functions unless user calls unrar_open_file()
|
||||
|
||||
#include "unrar.h"
|
||||
#include "rar.hpp"
|
||||
#include <stdio.h>
|
||||
|
||||
extern "C" {
|
||||
static unrar_err_t unrar_read_file( void* user_data, void* out, int* count, unrar_pos_t pos )
|
||||
{
|
||||
FILE* file = (FILE*) user_data;
|
||||
|
||||
// most of the time, seeking won't be necessary
|
||||
if ( pos != ftell( file ) && fseek( file, pos, SEEK_SET ) != 0 )
|
||||
return unrar_err_corrupt;
|
||||
|
||||
*count = (int) fread( out, 1, *count, file );
|
||||
|
||||
if ( ferror( file ) != 0 )
|
||||
return unrar_err_io;
|
||||
|
||||
return unrar_ok;
|
||||
}
|
||||
}
|
||||
|
||||
static void unrar_close_file( void* user_data )
|
||||
{
|
||||
fclose( (FILE*) user_data );
|
||||
}
|
||||
|
||||
unrar_err_t unrar_open( unrar_t** arc_out, const char path [] )
|
||||
{
|
||||
*arc_out = NULL;
|
||||
|
||||
FILE* file = fopen( path, "rb" );
|
||||
if ( file == NULL )
|
||||
return unrar_err_open;
|
||||
|
||||
unrar_err_t err = unrar_open_custom( arc_out, &unrar_read_file, file );
|
||||
if ( err != unrar_ok )
|
||||
fclose( file );
|
||||
else
|
||||
(*arc_out)->close_file = &unrar_close_file;
|
||||
|
||||
return err;
|
||||
}
|
@ -1,267 +0,0 @@
|
||||
|
||||
|
||||
WinRAR - What's new in the latest version
|
||||
|
||||
|
||||
Version 3.80
|
||||
|
||||
1. Added support for ZIP archives containing Unicode file names
|
||||
in UTF-8 format. When creating ZIP archive, WinRAR stores
|
||||
names in Unicode only if they cannot be stored correctly using
|
||||
the current single byte character set.
|
||||
|
||||
2. Added decompression support for WinZip AES encrypted ZIP archives.
|
||||
|
||||
3. Improved Unicode support for RAR and ZIP archive names.
|
||||
|
||||
4. "Ask before overwrite" and "Skip existing files" update modes
|
||||
are now available in archiving dialog. They allow to specify
|
||||
WinRAR behavior when updating already existing files in archive.
|
||||
Unlike already available "Fresh existing files only" and
|
||||
"Add and update files", these new modes ignore file date
|
||||
and compare only file names.
|
||||
|
||||
Command line equivalents of these modes are:
|
||||
|
||||
a) switch -o enables "Ask before overwrite" archiving mode;
|
||||
|
||||
b) switch -o- enables "Skip existing files" archiving mode;
|
||||
|
||||
c) switch -o+ enables "Overwrite all" mode (default for archiving).
|
||||
|
||||
5. New "Add to context menu" option in "Profile parameters" dialog.
|
||||
If this option is on, the profile name will be displayed in Explorer
|
||||
context menus allowing to activate a profile from context menu.
|
||||
|
||||
6. New -cp<profile name> switch allows to select a compression profile
|
||||
in command line mode. It is supported only by GUI WinRAR.exe,
|
||||
not by rar.exe.
|
||||
|
||||
7. New "Options" page of archiving dialog contains the group of
|
||||
settings modifying the behavior of "Delete files after archiving"
|
||||
option from "General" page:
|
||||
|
||||
a) Delete files. Delete files normally like in previous WinRAR
|
||||
versions.
|
||||
|
||||
b) Move files to Recycle Bin. Deleted files are placed to
|
||||
Recycle Bin.
|
||||
|
||||
Command line equivalent of this option is -dr switch.
|
||||
|
||||
c) Wipe files. Before deleting file data are overwritten by
|
||||
zero bytes to prevent recovery of deleted files.
|
||||
|
||||
Command line equivalent of this option is -dw switch.
|
||||
|
||||
All these options have an effect only if "Delete files
|
||||
after archiving" is on. You can enable any of these options
|
||||
in the default compression profile to change the default
|
||||
behavior of "Delete files after archiving".
|
||||
|
||||
8. WinRAR "Extraction path and options" dialog is now resizable.
|
||||
You can use the mouse to drag its border to the desired size
|
||||
and provide more space for folder tree pane. WinRAR will store
|
||||
new dimensions of this dialog.
|
||||
|
||||
9. New "Update" SFX script command and "Update mode" group
|
||||
of options in "Update" page of "Advanced SFX options" dialog.
|
||||
These command and options allow to check time and implement
|
||||
file time based updating;
|
||||
|
||||
10. SFX script "Shortcut" command and "Add shortcut..." command
|
||||
in "Advanced SFX options" dialog now allow to specify
|
||||
an icon file containing an icon associated with shortcut.
|
||||
|
||||
11. New "Wipe temporary files" option in "Settings/Security" dialog
|
||||
provides more secure, though slower, way to delete temporary
|
||||
WinRAR files.
|
||||
|
||||
12. WinRAR and RAR display the total progress bar when unpacking
|
||||
a multivolume RAR archive if all volumes are present
|
||||
in the same folder.
|
||||
|
||||
13. WinRAR and RAR automatically expand names of environment
|
||||
variables in list files. For example, a list file can contain
|
||||
lines like:
|
||||
|
||||
%windir%\*.exe
|
||||
%USERPROFILE%\Desktop
|
||||
|
||||
This feature is available only in Windows RAR version.
|
||||
|
||||
14. Added support of TAR archives with non-zero "extra field" data.
|
||||
|
||||
15. Added support of TAR archives, which does not contain
|
||||
the end of archive entry consisting of 512 zero bytes.
|
||||
|
||||
16. Improved Unicode support when dragging files from WinRAR window.
|
||||
|
||||
17. Shift+Tab key combination can be used in main WinRAR window to
|
||||
switch the input focus between interface elements (files, comment,
|
||||
tree, address) in reverse order. In previous versions Shift+Tab
|
||||
used the same order as Tab.
|
||||
|
||||
18. Corrected a possible WinRAR crash when opening truncated
|
||||
UDF ISO files.
|
||||
|
||||
|
||||
Version 3.71
|
||||
|
||||
1. Archive names in rar.log error log file always include
|
||||
the full path.
|
||||
|
||||
2. WinRAR tray icon is compatible with high DPI display modes.
|
||||
|
||||
3. If you modified a file in archive with encrypted names using
|
||||
an external editor, WinRAR will not ask for archive password again
|
||||
when prompting to update a file. It will use a password which
|
||||
you entered when opening an archive,
|
||||
|
||||
4. Bugs fixed:
|
||||
|
||||
a) switch -tl and "Set archive time to latest file time" option
|
||||
could fail in previous version. Sometimes they set archive time
|
||||
to current system time instead of latest file time;
|
||||
|
||||
b) if -ag switch mask contained archive number, month and minute
|
||||
characters, WinRAR placed 'I' character instead of minute value
|
||||
into generated archive name for archive numbers exceeding 1;
|
||||
|
||||
c) high ASCII names in ISO files using ISO 9660 format without
|
||||
Joliet format extension were displayed incorrectly;
|
||||
|
||||
d) WinRAR could crash when decompressing some of corrupt RAR archives;
|
||||
|
||||
e) if "Turn PC off when done" option was set in "Convert archives"
|
||||
command, WinRAR turned PC off after converting the first archive
|
||||
in selected group instead of after converting the entire group;
|
||||
|
||||
f) if user specified a non-existent destination path in SFX archive
|
||||
in Vista, SFX could enter into infinite "create new SFX window"
|
||||
loop;
|
||||
|
||||
g) WinRAR could fail to unpack an individual file from subfolder
|
||||
of ACE archive using the drag and drop.
|
||||
|
||||
|
||||
Version 3.70
|
||||
|
||||
1. Numerous Windows Vista compatibility changes:
|
||||
|
||||
a) help format changed from old HLP to newer HTML based CHM;
|
||||
|
||||
b) GUI self-extracting modules attempt to request for
|
||||
administrator permissions if they cannot create destination
|
||||
folder under current user account;
|
||||
|
||||
c) Log file rar.log and WinRAR theme files are stored
|
||||
in %APPDATA%\WinRAR folder instead of WinRAR program files folder.
|
||||
|
||||
Exported settings file settings.reg is also stored
|
||||
in %APPDATA%\WinRAR folder by default, but it is possible to
|
||||
select another folder in "Save WinRAR settings" and "Load WinRAR
|
||||
settings" dialogs.
|
||||
|
||||
WinRAR searches for registration key and settings.reg
|
||||
both in its program files folder and in %APPDATA%\WinRAR;
|
||||
|
||||
It is possible to set the string value "AppData" in Registry key
|
||||
HKEY_CURRENT_USER\Software\WinRAR\Paths to override the default
|
||||
%appdata%\WinRAR path for WinRAR settings.
|
||||
|
||||
For example, if you wish to store theme files in WinRAR folder,
|
||||
set this value to "c:\Program Files\WinRAR".
|
||||
|
||||
d) Vista compatibility changes in WinRAR shell integration;
|
||||
|
||||
e) New "Request administrative access" option in "Advanced" page
|
||||
of "Advanced SFX options" allows to create SFX archive,
|
||||
which will request the administrative access when started
|
||||
in Windows Vista.
|
||||
|
||||
Command line equivalent of this option is -iadm switch.
|
||||
|
||||
2. Added support for ISO 13346 (UDF) file format. This format
|
||||
is frequently used in ISO images of DVD disks.
|
||||
|
||||
3. Added Unicode support for ISO 9660 files, so WinRAR should
|
||||
handle non-English file names in .iso files better.
|
||||
|
||||
4. Design changes in window displaying archiving and extraction
|
||||
progress:
|
||||
|
||||
a) it provides more space for file names, allowing lengthy names;
|
||||
|
||||
b) it displays the current archive name in separate line,
|
||||
allowing much longer archive names than before;
|
||||
|
||||
c) when archiving, it displays the current compression ratio
|
||||
in separate line;
|
||||
|
||||
d) it can use both standard Windows and classic WinRAR progress bars.
|
||||
Turn on "Windows progress bars" option in WinRAR "Settings/General"
|
||||
dialog to use standard progress bars. By default this option is
|
||||
on if some Windows visual style is active and off if Windows Classic
|
||||
theme is selected.
|
||||
|
||||
Windows progress bars are two color only, so they do not indicate
|
||||
the current compression ratio. But now the ratio is displayed
|
||||
in separate line;
|
||||
|
||||
e) "Mode..." button moved to bottom of window.
|
||||
|
||||
5. GUI self-extracting modules support following command line
|
||||
switches:
|
||||
|
||||
-d<path> set the destination path
|
||||
-p<pwd> specify a password
|
||||
-s silent mode, hide all
|
||||
-s1 same as -s
|
||||
-s2 silent mode, hide start dialog
|
||||
-sp<par> specify parameters for setup program
|
||||
|
||||
6. GUI self-extracting modules do not pass the entire command line
|
||||
to setup program like they did in previous versions.
|
||||
If you need to get access to entire command line of SFX archive,
|
||||
parse sfxcmd environment variable which contains this command line.
|
||||
|
||||
7. New switch -sc<charset>[objects] allowing to select character
|
||||
sets for archive comments and list files. It replaces -fcu switch
|
||||
introduced in RAR 3.60, which was removed from list of supported
|
||||
switches. Now you need to specify -scuc instead of -fcu to use
|
||||
Unicode comments. Unlike -fcu, -sc also supports OEM and ANSI charset.
|
||||
|
||||
8. New "Save archive copy as..." command in "File" menu.
|
||||
This command may be useful if you opened an archive from Internet
|
||||
directly in WinRAR and then decided to save it on local disk.
|
||||
|
||||
9. "Word wrap" command added to "View" menu of WinRAR internal viewer,
|
||||
so you can change the wrapping mode of already opened viewer window.
|
||||
|
||||
State of this option is not stored between viewing sessions.
|
||||
If you need to change the default word wrap mode, use WinRAR
|
||||
"Settings/Viewer" dialog.
|
||||
|
||||
10. Buttons "Up" and "Down" added to "Organize profiles" dialog.
|
||||
Using these buttons you can change position of selected profile
|
||||
in the list.
|
||||
|
||||
11. Operation progress is displayed when adding the recovery record.
|
||||
|
||||
12. If WinRAR is minimized to tray and mouse is over its icon,
|
||||
WinRAR diplays a message about the current operation progress.
|
||||
In previous versions it included only percent done, now it also
|
||||
contains the time left information.
|
||||
|
||||
13. Console RAR displays "Calculating the control sum" message
|
||||
when calculating CRC32 control sum for newly created RAR volume.
|
||||
Previous versions also calculated the volume control sum,
|
||||
but did it silently.
|
||||
|
||||
14. Archives history list in "File" menu allows Unicode names,
|
||||
providing more reliable support for non-English archive names.
|
||||
|
||||
15. Stack overflow vulnerability has been corrected in password
|
||||
processing module of console RAR and UnRAR. GUI WinRAR is not
|
||||
affected. We are thankful to the iDEFENSE LABS for reporting this bug.
|
27
file.c
27
file.c
@ -355,13 +355,11 @@ typedef struct {
|
||||
} ExtensionType;
|
||||
|
||||
static ExtensionType extension_types[] = {
|
||||
{ ".7Z", FILE_TYPE_7ZIP },
|
||||
{ ".BMP", FILE_TYPE_BMP },
|
||||
{ ".JPG", FILE_TYPE_JPEG },
|
||||
{ ".JPEG", FILE_TYPE_JPEG },
|
||||
{ ".PNG", FILE_TYPE_PNG },
|
||||
{ ".MP3", FILE_TYPE_MP3 },
|
||||
{ ".RAR", FILE_TYPE_RAR },
|
||||
{ ".VPK", FILE_TYPE_VPK },
|
||||
{ ".ZIP", FILE_TYPE_ZIP },
|
||||
};
|
||||
@ -391,8 +389,10 @@ char **getMountPoints() {
|
||||
FileListEntry *fileListFindEntry(FileList *list, char *name) {
|
||||
FileListEntry *entry = list->head;
|
||||
|
||||
int name_length = strlen(name);
|
||||
|
||||
while (entry) {
|
||||
if (strcmp(entry->name, name) == 0)
|
||||
if (entry->name_length == name_length && strcmp(entry->name, name) == 0)
|
||||
return entry;
|
||||
|
||||
entry = entry->next;
|
||||
@ -424,8 +424,6 @@ void fileListAddEntry(FileList *list, FileListEntry *entry, int sort) {
|
||||
list->tail = entry;
|
||||
} else {
|
||||
if (sort != SORT_NONE) {
|
||||
int entry_length = strlen(entry->name);
|
||||
|
||||
FileListEntry *p = list->head;
|
||||
FileListEntry *previous = NULL;
|
||||
|
||||
@ -440,15 +438,14 @@ void fileListAddEntry(FileList *list, FileListEntry *entry, int sort) {
|
||||
|
||||
if (strcmp(p->name, "..") != 0) {
|
||||
// Get the minimum length without /
|
||||
int name_length = strlen(p->name);
|
||||
int len = MIN(entry_length, name_length);
|
||||
int len = MIN(entry->name_length, p->name_length);
|
||||
if (entry->name[len - 1] == '/' || p->name[len - 1] == '/')
|
||||
len--;
|
||||
|
||||
// Sort by name
|
||||
if (entry->is_folder == p->is_folder) {
|
||||
int diff = strncasecmp(entry->name, p->name, len);
|
||||
if (diff < 0 || (diff == 0 && entry_length < name_length)) {
|
||||
if (diff < 0 || (diff == 0 && entry->name_length < p->name_length)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -476,6 +473,7 @@ void fileListAddEntry(FileList *list, FileListEntry *entry, int sort) {
|
||||
} else {
|
||||
FileListEntry *tail = list->tail;
|
||||
tail->next = entry;
|
||||
entry->previous = tail;
|
||||
list->tail = entry;
|
||||
}
|
||||
}
|
||||
@ -510,8 +508,10 @@ int fileListRemoveEntryByName(FileList *list, char *name) {
|
||||
FileListEntry *entry = list->head;
|
||||
FileListEntry *previous = NULL;
|
||||
|
||||
int name_length = strlen(name);
|
||||
|
||||
while (entry) {
|
||||
if (strcmp(entry->name, name) == 0) {
|
||||
if (entry->name_length == name_length && strcmp(entry->name, name) == 0) {
|
||||
if (previous) {
|
||||
previous->next = entry->next;
|
||||
} else {
|
||||
@ -561,10 +561,11 @@ int fileListGetMountPointEntries(FileList *list) {
|
||||
if (sceIoGetstat(mount_points[i], &stat) >= 0) {
|
||||
FileListEntry *entry = malloc(sizeof(FileListEntry));
|
||||
strcpy(entry->name, mount_points[i]);
|
||||
entry->name_length = strlen(entry->name);
|
||||
entry->is_folder = 1;
|
||||
entry->type = FILE_TYPE_UNKNOWN;
|
||||
|
||||
memcpy(&entry->time, (SceRtcTime *)&stat.st_ctime, sizeof(SceRtcTime));
|
||||
memcpy(&entry->time, (SceDateTime *)&stat.st_ctime, sizeof(SceDateTime));
|
||||
|
||||
fileListAddEntry(list, entry, SORT_BY_NAME_AND_FOLDER);
|
||||
|
||||
@ -583,6 +584,7 @@ int fileListGetDirectoryEntries(FileList *list, char *path) {
|
||||
|
||||
FileListEntry *entry = malloc(sizeof(FileListEntry));
|
||||
strcpy(entry->name, DIR_UP);
|
||||
entry->name_length = strlen(entry->name);
|
||||
entry->is_folder = 1;
|
||||
entry->type = FILE_TYPE_UNKNOWN;
|
||||
fileListAddEntry(list, entry, SORT_BY_NAME_AND_FOLDER);
|
||||
@ -612,10 +614,11 @@ int fileListGetDirectoryEntries(FileList *list, char *path) {
|
||||
list->files++;
|
||||
}
|
||||
|
||||
memcpy(&entry->time, (SceRtcTime *)&dir.d_stat.st_mtime, sizeof(SceRtcTime));
|
||||
|
||||
entry->name_length = strlen(entry->name);
|
||||
entry->size = dir.d_stat.st_size;
|
||||
|
||||
memcpy(&entry->time, (SceDateTime *)&dir.d_stat.st_mtime, sizeof(SceDateTime));
|
||||
|
||||
fileListAddEntry(list, entry, SORT_BY_NAME_AND_FOLDER);
|
||||
}
|
||||
} while (res > 0);
|
||||
|
6
file.h
6
file.h
@ -31,12 +31,10 @@
|
||||
|
||||
enum FileTypes {
|
||||
FILE_TYPE_UNKNOWN,
|
||||
FILE_TYPE_7ZIP,
|
||||
FILE_TYPE_BMP,
|
||||
FILE_TYPE_JPEG,
|
||||
FILE_TYPE_PNG,
|
||||
FILE_TYPE_MP3,
|
||||
FILE_TYPE_RAR,
|
||||
FILE_TYPE_VPK,
|
||||
FILE_TYPE_ZIP,
|
||||
};
|
||||
@ -50,10 +48,12 @@ typedef struct FileListEntry {
|
||||
struct FileListEntry *next;
|
||||
struct FileListEntry *previous;
|
||||
char name[MAX_NAME_LENGTH];
|
||||
int name_length;
|
||||
int is_folder;
|
||||
int type;
|
||||
SceOff size;
|
||||
SceRtcTime time;
|
||||
SceDateTime time;
|
||||
int reserved[16];
|
||||
} FileListEntry;
|
||||
|
||||
typedef struct {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user