Last active
April 23, 2022 09:49
-
-
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
This file contains hidden or 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
#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