Skip to content

Commit

Permalink
POSIX GNU tar read support
Browse files Browse the repository at this point in the history
- supporting tared csm.bin of Chasm: The Rift Remastered at https://store.steampowered.com/app/2061230/Chasm_The_Rift/
- Thanks to @sezero for OS/2 and Windows fixes
  • Loading branch information
Jon Daniel committed Jul 28, 2023
1 parent 5f4b8be commit 496a5a4
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 34 deletions.
3 changes: 2 additions & 1 deletion src/physfs_archiver_tar.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ static bool TAR_loadEntries(PHYSFS_Io *io, void *arc)
union block zero_block;
union block current_block;
PHYSFS_uint64 count = 0;
bool long_name = false;

memset(zero_block.buffer, 0, sizeof(BLOCKSIZE));
memset(current_block.buffer, 0, sizeof(BLOCKSIZE));
Expand All @@ -31,7 +32,7 @@ static bool TAR_loadEntries(PHYSFS_Io *io, void *arc)
switch(TAR_magic(&current_block))
{
case POSIX_FORMAT:
TAR_posix_block(io, arc, &current_block, &count);
TAR_posix_block(io, arc, &current_block, &count, &long_name);
break;
case OLDGNU_FORMAT:
break;
Expand Down
52 changes: 19 additions & 33 deletions src/physfs_tar.h
Original file line number Diff line number Diff line change
@@ -1,15 +1,7 @@
#ifndef _INCLUDE_PHYSFS_TAR_H_
#define _INCLUDE_PHYSFS_TAR_H_

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <ctype.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>

#ifndef PATH_MAX
#define PATH_MAX 1024
Expand Down Expand Up @@ -114,43 +106,37 @@ union block
struct posix_header header;
};

static PHYSFS_uint64 TAR_decodeOctal(char* data, size_t size) {
unsigned char* currentPtr = (unsigned char*) data + size;
static PHYSFS_uint64 TAR_decodeOctal(char *data, size_t size) {
unsigned char *currentPtr = (unsigned char*) data + size;
PHYSFS_uint64 sum = 0;
PHYSFS_uint64 currentMultiplier = 1;
unsigned char* checkPtr = currentPtr;
unsigned char *checkPtr = currentPtr;

for (; checkPtr >= (unsigned char*) data; checkPtr--) {
for (; checkPtr >= (unsigned char *) data; checkPtr--) {
if ((*checkPtr) == 0 || (*checkPtr) == ' ') {
currentPtr = checkPtr - 1;
}
}
for (; currentPtr >= (unsigned char*) data; currentPtr--) {
for (; currentPtr >= (unsigned char *) data; currentPtr--) {
sum += (*currentPtr - 48) * currentMultiplier;
currentMultiplier *= 8;
}
return sum;
}

static bool TAR_encodeOctal(char* data, size_t size, PHYSFS_uint64 i) {
if( snprintf(data, size, "%llo", i) < 0 )
return false;
return true;
}

static int TAR_magic(union block* block) {
static enum archive_format TAR_magic(union block *block) {
if(strcmp(block->header.magic, OLDGNU_MAGIC) == 0 && strncmp(block->header.version, TVERSION, 2) == 0)
return (int)OLDGNU_FORMAT;
return OLDGNU_FORMAT;
if(strncmp(block->header.magic, TMAGIC, TMAGLEN - 1) == 0)
return (int)POSIX_FORMAT;
return (int)DEFAULT_FORMAT;
return POSIX_FORMAT;
return DEFAULT_FORMAT;
}

static size_t TAR_fileSize(union block* block) {
static PHYSFS_uint64 TAR_fileSize(union block *block) {
return TAR_decodeOctal(block->header.size, sizeof(block->header.size));
}

static bool TAR_checksum(union block* block) {
static bool TAR_checksum(union block *block) {
PHYSFS_sint64 unsigned_sum = 0;
PHYSFS_sint64 signed_sum = 0;
PHYSFS_uint64 reference_chksum = 0;
Expand All @@ -161,23 +147,23 @@ static bool TAR_checksum(union block* block) {
memset(block->header.chksum, ' ', 8);

for(; i < BLOCKSIZE; i++) {
unsigned_sum += ((unsigned char*) block->buffer)[i];
signed_sum += ((signed char*) block->buffer)[i];
unsigned_sum += ((unsigned char *) block->buffer)[i];
signed_sum += ((signed char *) block->buffer)[i];
}
memcpy(block->header.chksum, orig_chksum, 8);
reference_chksum = TAR_decodeOctal(orig_chksum, 12);
return (reference_chksum == unsigned_sum || reference_chksum == signed_sum);
}

time_t TAR_time(union block* block)
static PHYSFS_uint64 TAR_time(union block *block)
{
return TAR_decodeOctal(block->header.mtime, 12);
}

bool TAR_posix_block(PHYSFS_Io* io, void* arc, union block* block, PHYSFS_uint64* count)
static bool TAR_posix_block(PHYSFS_Io *io, void *arc, union block *block, PHYSFS_uint64 *count, bool *long_name)
{
static bool long_name = false;
const PHYSFS_Allocator* allocator = PHYSFS_getAllocator();
const PHYSFS_Allocator *allocator = PHYSFS_getAllocator();
char name[PATH_MAX] = { 0 };
PHYSFS_sint64 time = 0;
PHYSFS_uint64 size = 0;
Expand All @@ -204,10 +190,10 @@ bool TAR_posix_block(PHYSFS_Io* io, void* arc, union block* block, PHYSFS_uint64
/* add file type entry */
if (block->header.typeflag == REGTYPE || block->header.typeflag == 0) {
/* support long file names */
if(long_name) {
if(*long_name) {
strcpy(&name[0], block->header.name);
BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, block->buffer, BLOCKSIZE), 0);
long_name = false;
*long_name = false;
(*count)++;
}
size = TAR_fileSize(block);
Expand All @@ -228,7 +214,7 @@ bool TAR_posix_block(PHYSFS_Io* io, void* arc, union block* block, PHYSFS_uint64
/* long name mode */
else if(block->header.typeflag == GNUTYPE_LONGNAME)
{
long_name = true;
*long_name = true;
}
else
{
Expand Down

0 comments on commit 496a5a4

Please sign in to comment.