Skip to content

Instantly share code, notes, and snippets.

@lifning
Last active April 23, 2022 09:49
Show Gist options
  • Save lifning/1a7d3e86ce5c88716b06f1a967d0abf3 to your computer and use it in GitHub Desktop.
Save lifning/1a7d3e86ce5c88716b06f1a967d0abf3 to your computer and use it in GitHub Desktop.
an ancient (ca. 2005) sega dreamcast AFS archive unpacker written by a high schooler who still commented every line of their programs
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
struct afsHeader // Header of the file
{
char magic[4]; // Magic word "AFS"
uint32_t count; // Number of .ADX files in the archive
};
struct afsEntry // Each entry in the .AFS filesystem
{
uint32_t offset; // Offset to the .ADX file
uint32_t size; // Size of the .ADX file
};
// Precondition: Parameter filename is a string representing a valid .AFS archive's filename
// Postcondition: .ADX files aer extracted from the .AFS archive
int unpackAFS(char *filename)
{
int i, j; // Used in for loops
char *dir; // Base filename for generating output filenames
FILE *inputAFS, *outputADX; // Streams for input and output
struct afsHeader fileHeader; // Header of the archive
struct afsEntry *fileEntries; // Filesystem of the archive
dir = malloc(strlen(filename)); // Initialize the base filename
strcpy(dir, filename); // Copy the .AFS filename into it
*(strrchr(dir, '.')) = '\0'; // Take off the extension
inputAFS = fopen(filename, "rb"); // Open the .AFS archive for binary reading
if(!inputAFS) // If it didn't open
return(1); // Complain
fread(&fileHeader, sizeof(fileHeader), 1, inputAFS); // Read in the header
if(strcmp(fileHeader.magic, "AFS")) // Make sure it's got the magic word
{
fclose(inputAFS); // If it doesn't, we don't want it
printf("\nError: Not a valid .AFS file\n"); // Tell the people
return(2); // Complain
}
printf("\n%u Sounds:\n", fileHeader.count); // Display some header info
fileEntries = malloc(sizeof(fileEntries[0]) * fileHeader.count); // Initialize the array of entries
fread(fileEntries, sizeof(fileEntries[0]), fileHeader.count, inputAFS); // Read the table of contents
for(i = 0; i < fileHeader.count; i++) // For each file entry
{
char *name; // Output file's name
name = malloc(strlen(dir) + 10); // Make a string that's big enough for the filename
fseek(inputAFS, fileEntries[i].offset, SEEK_SET); // Go to the file offset
printf("\tEntry: 0x%04X\tOffset: 0x%08X\tSize: 0x%08X\n",
i, fileEntries[i].offset, fileEntries[i].size); // Output some info about the file
sprintf(name, "%s_%04d.adx", dir, i); // Make the filename string
outputADX = fopen(name, "wb"); // Try to open the .ADX file for writing
if(!outputADX) // If it didn't open properly
return(3); // Complain
for(j = 0; j < fileEntries[i].size; j++) // For each of the bytes
fputc(fgetc(inputAFS), outputADX); // Copy the bytes from one stream to the other
fclose(outputADX); // Close the file, as we're done with it
}
fclose(inputAFS); // Close the file, as we're done with it
return 0; // We're all done
}
int main(int argc, char *argv[]) // Main part of the program
{
printf("Lightning's .AFS Utility\n"); // =P
if(argc <= 1) // If there aren't the right arguments
printf("\n\tUsage: AFS_Unpk <filename>.afs\n"); // Tell the people
else // If it's run correctly
return unpackAFS(argv[1]); // Do it
return(0); // Finished
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment