Subversion Repositories ipe_artfile_utils

Rev

Blame | Last modification | View Log | RSS feed

  1. /**
  2.  * ART file packer by Daniel Marschall, ViaThinkSoft (C) 2014-2018
  3.  * Supports:
  4.  * - Blown Away - The Interactive Game by Imagination Pilots
  5.  * Revision: 2018-02-15
  6.  **/
  7.  
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <stdbool.h>
  11. #include <string.h>
  12. #include <math.h>
  13.  
  14. #include "ipe_artfile_packer_ipe16_ba.h"
  15.  
  16. #include "ipe16_artfile.h"
  17. #include "ipe16_bmpimport.h"
  18. #include "ipe16_lzw_encoder.h"
  19.  
  20. #define MAX_FILE 256
  21.  
  22. bool ba_pack_art(const char* szSrcFolder, FILE* fobArt, const int verbosity) {
  23.         bool bEverythingOK = true;
  24.  
  25.         char szIndexFilename[MAX_FILE];
  26.         sprintf(szIndexFilename, "%s/index.txt", szSrcFolder);
  27.         FILE* fitIndex = fopen(szIndexFilename, "rt");
  28.         if (!fitIndex) {
  29.                 fprintf(stderr, "Cannot open %s\n", szIndexFilename);
  30.                 return false;
  31.         }
  32.  
  33.         #define MAX_LINE 1024
  34.         char line[MAX_LINE];
  35.         int cItems = 0;
  36.         while (fgets(line, sizeof(line), fitIndex)) {
  37.                 if (strlen(line) == 0) continue;
  38.                 ++cItems;
  39.         }
  40.         if (verbosity >= 1) printf("%s contains %d entries\n", szIndexFilename, cItems); // TODO: don't print double /
  41.  
  42.         Ipe16FileHeader bfh;
  43.         memset(&bfh, 0x00, sizeof(bfh));
  44.         strcpy(bfh.magic, IPE16_MAGIC_ART);
  45.         bfh.dummy = IPE16_MAGIC_DUMMY;
  46.         bfh.numHeaderEntries = cItems+1;
  47.  
  48.         Ipe16PictureEntryHeader peh[cItems];
  49.         memset(&peh, 0x00, sizeof(peh));
  50.  
  51.         BAPictureHeader ph[cItems];
  52.         memset(&ph,  0x00, sizeof(ph));
  53.  
  54.         // We need to write the (still empty) headers, so we can use ftell() to determine the offsets correctly
  55.         // These headers are currently just dummies. They will be rewritten after all pictures are processed
  56.         fwrite(&bfh, sizeof(bfh), 1, fobArt);
  57.         fwrite(&peh, sizeof(peh), 1, fobArt);
  58.  
  59.         fseek(fitIndex, 0, SEEK_SET);
  60.         int curItem = 0;
  61.         Ipe16LZWEncoder* lzwEncoder = NULL;
  62.         while (fgets(line, sizeof(line), fitIndex)) {
  63.                 // If something fails, we discard the item, but continue in building the file!
  64.                 #define FAIL_CONTINUE { memset(&peh[curItem], 0x00, sizeof(peh[curItem])); bEverythingOK=false; continue; }
  65.  
  66.                 const char* szDelimiters = " \t\r\n";
  67.                 char* szPaletteType     = strtok(&line[0], szDelimiters);
  68.                 char* szCompressionType = strtok(NULL, szDelimiters);
  69.                 char* szName            = strtok(NULL, szDelimiters);
  70.                 char* szFilename        = strtok(NULL, szDelimiters);
  71.  
  72.                 if (strlen(szPaletteType) != 1) {
  73.                         fprintf(stderr, "ERROR: Palette type (argument 1) at line %d is not valid (must be 1 char)\n", curItem+1);
  74.                         FAIL_CONTINUE;
  75.                 }
  76.                 const char chPaletteType = *szPaletteType;
  77.  
  78.                 if ((chPaletteType != IPE16_PALETTETYPE_ATTACHED) && (chPaletteType != IPE16_PALETTETYPE_PARENT)) {
  79.                         fprintf(stderr, "ERROR: Unknown palette type '%c' at line %d\n", chPaletteType, curItem+1);
  80.                         FAIL_CONTINUE;
  81.                 }
  82.  
  83.                 if (strlen(szCompressionType) != 1) {
  84.                         fprintf(stderr, "ERROR: Compression type (argument 2) at line %d is not valid (must be 1 char)\n", curItem+1);
  85.                         FAIL_CONTINUE;
  86.                 }
  87.                 const char chCompressionType = *szCompressionType;
  88.  
  89.                 if (strlen(szName) > IPE16_NAME_SIZE) {
  90.                         fprintf(stderr, "ERROR: Name %s is too long (max %d chars allowed)\n", szName, IPE16_NAME_SIZE);
  91.                         FAIL_CONTINUE;
  92.                 }
  93.  
  94.                 strcpy(peh[curItem].name, szName);
  95.                 peh[curItem].paletteType = chPaletteType;
  96.                 peh[curItem].offset = ftell(fobArt);
  97.                 peh[curItem].size = 0; // will be increased later
  98.  
  99.                 if (verbosity >= 1) printf("Process %s at offset %x\n", szName, peh[curItem].offset);
  100.  
  101.                 // Read bitmap
  102.  
  103.                 const bool colorTableExisting = (chPaletteType == IPE16_PALETTETYPE_ATTACHED);
  104.  
  105.                 char szBitmapFilename[MAX_FILE];
  106.                 sprintf(szBitmapFilename, "%s/%s", szSrcFolder, szFilename);
  107.                 FILE* fibBitmap = fopen(szBitmapFilename, "rb");
  108.                 if (!fibBitmap) {
  109.                         fprintf(stderr, "ERROR: cannot open '%s'\n", szFilename);
  110.                         FAIL_CONTINUE;
  111.                 }
  112.  
  113.                 Ipe16BmpImportData result={0};
  114.                 if (!ipe16_bmp_import(fibBitmap, &result)) {
  115.                         fprintf(stderr, "Error at %s: %s\n", szFilename, result.error);
  116.                         fclose(fibBitmap);
  117.                         ipe16_free_bmpimport_result(&result);
  118.                         FAIL_CONTINUE;
  119.                 }
  120.  
  121.                 ph[curItem].compressionType = chCompressionType;
  122.                 ph[curItem].width = result.width;
  123.                 ph[curItem].height = result.height;
  124.                 fwrite(&ph[curItem], sizeof(ph[curItem]), 1, fobArt);
  125.                 peh[curItem].size += sizeof(ph[curItem]);
  126.  
  127.                 // Write picture data
  128.  
  129.                 size_t tmpBefore = ftell(fobArt);
  130.                 if (chCompressionType == BA_COMPRESSIONTYPE_LZW) {
  131.                         if (!lzwEncoder) lzwEncoder = new_ipe16lzw_encoder();
  132.                         ipe16lzw_encode(fobArt, lzwEncoder, result.bmpData, result.bmpDataSize);
  133.                 } else if (chCompressionType == BA_COMPRESSIONTYPE_NONE) {
  134.                         fwrite(result.bmpData, result.bmpDataSize, 1, fobArt);
  135.                 } else {
  136.                         fprintf(stderr, "Unknown compression type '%c' at line %d\n", chCompressionType, curItem+1);
  137.                         fclose(fibBitmap);
  138.                         ipe16_free_bmpimport_result(&result);
  139.                         FAIL_CONTINUE;
  140.                 }
  141.                 peh[curItem].size += ftell(fobArt)-tmpBefore;
  142.  
  143.                 if (colorTableExisting) {
  144.                         fwrite(result.colorTable, sizeof(*result.colorTable), 1, fobArt);
  145.                         peh[curItem].size += sizeof(*result.colorTable);
  146.                 }
  147.  
  148.                 // Free and continue
  149.  
  150.                 fclose(fibBitmap);
  151.                 ipe16_free_bmpimport_result(&result);
  152.  
  153.                 ++curItem;
  154.         }
  155.         if (lzwEncoder) del_ipe16lzw_encoder(lzwEncoder);
  156.         fclose(fitIndex);
  157.  
  158.         bfh.totalFileSize = ftell(fobArt);
  159.  
  160.         fseek(fobArt, 0, SEEK_SET);
  161.         fwrite(&bfh, sizeof(bfh), 1, fobArt);
  162.         fwrite(&peh, sizeof(peh), 1, fobArt);
  163.  
  164.         fclose(fobArt);
  165.  
  166.         return bEverythingOK;
  167. }
  168.