#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <sys/stat.h>

#define BLKSIZE 0x100
#define HEADERSIZE 0x20
#define MAX_FN_LEN 25   // 26 - null char

bool ensuredir(char *path)
{
   char *s = path;
   while (*s != '\0') {
       if (*s == '/') {
           *s = '\0';
           struct stat path_stat;
           if (stat(path, &path_stat) != 0) {
               if (mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0) {
                   return false;
               }
           }
           *s = '/';
       }
       s++;
   }
   return true;
}

bool unpackblk(char *dstpath)
{
   char buf[MAX_FN_LEN+1];
   if (fgets(buf, 3+1, stdin) == NULL) {
       return false;
   }
   if (strcmp(buf, "CFS") != 0) {
       return false;
   }
   int c = getchar();
   uint8_t blkcnt = c;
   if (blkcnt == 0) {
       return false;
   }
   c = getchar();
   uint16_t fsize = c & 0xff;
   c = getchar();
   fsize |= (c & 0xff) << 8;

   if (fgets(buf, MAX_FN_LEN+1+1, stdin) == NULL) {
       return false;
   }
   char fullpath[0x1000];
   strcpy(fullpath, dstpath);
   strcat(fullpath, "/");
   strcat(fullpath, buf);
   if (!ensuredir(fullpath)) {
       return false;
   }
   int blksize = (BLKSIZE-HEADERSIZE)+(BLKSIZE*(blkcnt-1));
   int skipcount = blksize - fsize;
   FILE *fp = fopen(fullpath, "w");
   while (fsize) {
       c = getchar();
       if (c == EOF) {
           return false;
       }
       fputc(c, fp);
       fsize--;
   }
   fclose(fp);
   while (skipcount) {
       getchar();
       skipcount--;
   }
   return true;
}

int main(int argc, char *argv[])
{
   if (argc != 2) {
       fprintf(stderr, "Usage: cfspack /path/to/dest\n");
       return 1;
   }
   char *dstpath = argv[1];
   // we fail if there isn't at least one block
   if (!unpackblk(dstpath)) {
       return 1;
   }
   while (unpackblk(dstpath));
   return 0;
}