-
-
Save hogsy/90ae893ded9c2b42796c5eff8788d1ba to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
FreshEngine Bin Packer | |
Copyright (C) 2023 Mark E. Sowden <hogsy@snortysoft.net> | |
This program is free software; you can redistribute it and/or modify | |
it under the terms of the GNU General Public License as published by | |
the Free Software Foundation; either version 2 of the License, or | |
(at your option) any later version. | |
This program is distributed in the hope that it will be useful, | |
but WITHOUT ANY WARRANTY; without even the implied warranty of | |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
GNU General Public License for more details. | |
You should have received a copy of the GNU General Public License along | |
with this program; if not, write to the Free Software Foundation, Inc., | |
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
*/ | |
#include "plcore/pl.h" | |
#include "plcore/pl_filesystem.h" | |
#include "plcore/pl_linkedlist.h" | |
#include "plcore/pl_package.h" | |
static PLLinkedList *filesList; | |
static const unsigned int BLOCK_SIZE = 2048U; | |
static size_t calculate_stream_length( size_t dataSize ) | |
{ | |
return ceil( ( double ) dataSize / BLOCK_SIZE ) * BLOCK_SIZE; | |
} | |
#define F3D_BIN_NAME "DATA.BIN" | |
#define F3D_BIN_IDENT "DATA " | |
#define F3D_BIN_IDENT_SIZE 8 | |
#define F3D_BIN_FILENAME_SIZE 12 | |
typedef struct F3dBinHeader | |
{ | |
char ident[ F3D_BIN_IDENT_SIZE ]; | |
uint32_t x; | |
uint32_t y; | |
uint32_t numFiles; | |
} F3dBinHeader; | |
static_assert( sizeof( F3dBinHeader ) == 20, "invalid struct size" ); | |
typedef struct F3dBinIndex | |
{ | |
char filename[ F3D_BIN_FILENAME_SIZE ]; | |
uint32_t block; | |
uint32_t size; | |
} F3dBinIndex; | |
static_assert( sizeof( F3dBinIndex ) == 20, "invalid struct size" ); | |
static void add_pack_file( const char *path, void * ) | |
{ | |
const char *filename = PlGetFileName( path ); | |
size_t bufSize = strlen( filename ) + 1; | |
char *buf = PL_NEW_( char, bufSize ); | |
snprintf( buf, bufSize, "%s", filename ); | |
PlInsertLinkedListNode( filesList, buf ); | |
} | |
static void *cache_file( const char *path, unsigned int *size ) | |
{ | |
PLFile *file = PlOpenLocalFile( path, true ); | |
if ( file == NULL ) | |
return NULL; | |
*size = PlGetFileSize( file ); | |
char *data = PL_NEW_( char, *size + 1 ); | |
memcpy( data, PlGetFileData( file ), *size ); | |
PlCloseFile( file ); | |
return data; | |
} | |
int main( int argc, char **argv ) | |
{ | |
PlInitialize( argc, argv ); | |
filesList = PlCreateLinkedList(); | |
const char *arg; | |
if ( ( arg = PlGetCommandLineArgumentValue( "/o" ) ) != NULL ) | |
{ | |
// This route ensures that the order of the files in the package match the original, | |
// by using the original toc as a reference | |
FILE *file = fopen( arg, "rb" ); | |
if ( file == NULL ) | |
{ | |
perror( "Failed to open origin package" ); | |
return EXIT_FAILURE; | |
} | |
F3dBinHeader header; | |
fread( &header, sizeof( F3dBinHeader ), 1, file ); | |
if ( strncmp( header.ident, "DATA ", 8 ) != 0 ) | |
{ | |
fprintf( stderr, "Package is not a FreshEngine package!\n" ); | |
return EXIT_FAILURE; | |
} | |
for ( unsigned int i = 0; i < header.numFiles; ++i ) | |
{ | |
F3dBinIndex index; | |
fread( &index, sizeof( F3dBinIndex ), 1, file ); | |
char *buf = PL_NEW_( char, sizeof( index.filename ) + 1 ); | |
for ( unsigned int j = 0; j < sizeof( index.filename ); ++j ) | |
buf[ j ] = ( index.filename[ j ] == ' ' ) ? '\0' : index.filename[ j ]; | |
PlInsertLinkedListNode( filesList, buf ); | |
} | |
fclose( file ); | |
} | |
else | |
PlScanDirectory( "./", NULL, add_pack_file, false, NULL ); | |
unsigned int numFiles = PlGetNumLinkedListNodes( filesList ); | |
if ( numFiles == 0 ) | |
{ | |
fprintf( stderr, "No files found in directory!\n" ); | |
return EXIT_FAILURE; | |
} | |
PlCreateDirectory( "out" ); | |
FILE *file = fopen( "out/" F3D_BIN_NAME, "wb" ); | |
if ( file == NULL ) | |
{ | |
perror( "Failed to open write destination" ); | |
return EXIT_FAILURE; | |
} | |
F3dBinHeader header = { .ident = F3D_BIN_IDENT, .numFiles = numFiles }; | |
fwrite( &header, sizeof( F3dBinHeader ), 1, file ); | |
size_t totalSize = sizeof( header ) + ( sizeof( F3dBinIndex ) * numFiles ); | |
PLLinkedListNode *node = PlGetFirstNode( filesList ); | |
while ( node != NULL ) | |
{ | |
char *filename = PlGetLinkedListNodeUserData( node ); | |
F3dBinIndex index; | |
strncpy( index.filename, filename, sizeof( index.filename ) ); | |
for ( unsigned int i = 0; i < sizeof( index.filename ); ++i ) | |
index.filename[ i ] = index.filename[ i ] == '\0' ? ' ' : toupper( index.filename[ i ] ); | |
index.block = calculate_stream_length( totalSize ) / BLOCK_SIZE; | |
index.size = PlGetLocalFileSize( filename ); | |
fwrite( &index, sizeof( F3dBinIndex ), 1, file ); | |
node = PlGetNextLinkedListNode( node ); | |
totalSize = index.block * BLOCK_SIZE + index.size; | |
} | |
node = PlGetFirstNode( filesList ); | |
while ( true ) | |
{ | |
size_t pos = calculate_stream_length( ftell( file ) ); | |
printf( "padding to %lu (block %zu)\n", pos, ( pos / BLOCK_SIZE ) ); | |
while ( ftell( file ) != pos ) | |
fputc( 0, file ); | |
if ( node == NULL ) | |
break; | |
unsigned int size; | |
char *filename = PlGetLinkedListNodeUserData( node ); | |
void *data = cache_file( filename, &size ); | |
if ( data == NULL ) | |
{ | |
fprintf( stderr, "Failed to cache a specific file (%s): %s\n", filename, PlGetError() ); | |
return EXIT_FAILURE; | |
} | |
fwrite( data, sizeof( char ), size, file ); | |
PL_DELETEN( data ); | |
node = PlGetNextLinkedListNode( node ); | |
} | |
fclose( file ); | |
return EXIT_SUCCESS; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment