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.  * - Panic in the Park - The Interactive Game by Imagination Pilots
  5.  * - Where's Waldo? At the Circus (Waldo1)
  6.  * Revision: 2018-02-15
  7.  **/
  8.  
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <stdbool.h>
  12. #include <string.h>
  13. #include <math.h>
  14.  
  15. #include "ipe_artfile_packer_ipe16_pip.h"
  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 pip_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.         PipPictureHeader 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.                 char* szOffsetX         = strtok(NULL, szDelimiters);
  72.                 int iOffsetX            = (szOffsetX != NULL) ? atoi(szOffsetX) : 0;
  73.                 char* szOffsetY         = strtok(NULL, szDelimiters);
  74.                 int iOffsetY            = (szOffsetY != NULL) ? atoi(szOffsetY) : 0;
  75.  
  76.                 if (strlen(szPaletteType) != 1) {
  77.                         fprintf(stderr, "ERROR: Palette type (argument 1) at line %d is not valid (must be 1 char)\n", curItem+1);
  78.                         FAIL_CONTINUE;
  79.                 }
  80.                 const char chPaletteType = *szPaletteType;
  81.  
  82.                 if ((chPaletteType != IPE16_PALETTETYPE_ATTACHED) && (chPaletteType != IPE16_PALETTETYPE_PARENT)) {
  83.                         fprintf(stderr, "ERROR: Unknown palette type '%c' at line %d\n", chPaletteType, curItem+1);
  84.                         FAIL_CONTINUE;
  85.                 }
  86.  
  87.                 if (strlen(szCompressionType) != 1) {
  88.                         fprintf(stderr, "ERROR: Compression type (argument 2) at line %d is not valid (must be 1 char)\n", curItem+1);
  89.                         FAIL_CONTINUE;
  90.                 }
  91.                 const char chCompressionType = *szCompressionType;
  92.  
  93.                 if (strlen(szName) > IPE16_NAME_SIZE) {
  94.                         fprintf(stderr, "ERROR: Name %s is too long (max %d chars allowed)\n", szName, IPE16_NAME_SIZE);
  95.                         FAIL_CONTINUE;
  96.                 }
  97.  
  98.                 strcpy(peh[curItem].name, szName);
  99.                 peh[curItem].paletteType = chPaletteType;
  100.                 peh[curItem].offset = ftell(fobArt);
  101.                 peh[curItem].size = 0; // will be increased later
  102.  
  103.                 if (verbosity >= 1) printf("Process %s at offset %x\n", szName, peh[curItem].offset);
  104.  
  105.                 // Read bitmap
  106.  
  107.                 const bool colorTableExisting = (chPaletteType == IPE16_PALETTETYPE_ATTACHED);
  108.  
  109.                 char szBitmapFilename[MAX_FILE];
  110.                 sprintf(szBitmapFilename, "%s/%s", szSrcFolder, szFilename);
  111.                 FILE* fibBitmap = fopen(szBitmapFilename, "rb");
  112.                 if (!fibBitmap) {
  113.                         fprintf(stderr, "ERROR: cannot open '%s'\n", szFilename);
  114.                         FAIL_CONTINUE;
  115.                 }
  116.  
  117.                 Ipe16BmpImportData result={0};
  118.                 if (!ipe16_bmp_import(fibBitmap, &result)) {
  119.                         fprintf(stderr, "Error at %s: %s\n", szFilename, result.error);
  120.                         fclose(fibBitmap);
  121.                         ipe16_free_bmpimport_result(&result);
  122.                         FAIL_CONTINUE;
  123.                 }
  124.  
  125.                 ph[curItem].compressionType = chCompressionType;
  126.                 ph[curItem].offsetX = iOffsetX;
  127.                 ph[curItem].offsetY = iOffsetY;
  128.                 ph[curItem].width = result.width;
  129.                 ph[curItem].height = result.height;
  130.                 fwrite(&ph[curItem], sizeof(ph[curItem]), 1, fobArt);
  131.                 peh[curItem].size += sizeof(ph[curItem]);
  132.  
  133.                 // Write picture data
  134.  
  135.                 size_t tmpBefore = ftell(fobArt);
  136.                 if (chCompressionType == PIP_COMPRESSIONTYPE_LZW) {
  137.                         if (!lzwEncoder) lzwEncoder = new_ipe16lzw_encoder();
  138.                         ipe16lzw_encode(fobArt, lzwEncoder, result.bmpData, result.bmpDataSize);
  139.                 } else if (chCompressionType == PIP_COMPRESSIONTYPE_NONE) {
  140.                         fwrite(result.bmpData, result.bmpDataSize, 1, fobArt);
  141.                 } else {
  142.                         fprintf(stderr, "Unknown compression type '%c' at line %d\n", chCompressionType, curItem+1);
  143.                         fclose(fibBitmap);
  144.                         ipe16_free_bmpimport_result(&result);
  145.                         FAIL_CONTINUE;
  146.                 }
  147.                 peh[curItem].size += ftell(fobArt)-tmpBefore;
  148.  
  149.                 if (colorTableExisting) {
  150.                         fwrite(result.colorTable, sizeof(*result.colorTable), 1, fobArt);
  151.                         peh[curItem].size += sizeof(*result.colorTable);
  152.                 }
  153.  
  154.                 // Free and continue
  155.  
  156.                 fclose(fibBitmap);
  157.                 ipe16_free_bmpimport_result(&result);
  158.  
  159.                 ++curItem;
  160.         }
  161.         if (lzwEncoder) del_ipe16lzw_encoder(lzwEncoder);
  162.         fclose(fitIndex);
  163.  
  164.         bfh.totalFileSize = ftell(fobArt);
  165.  
  166.         fseek(fobArt, 0, SEEK_SET);
  167.         fwrite(&bfh, sizeof(bfh), 1, fobArt);
  168.         fwrite(&peh, sizeof(peh), 1, fobArt);
  169.  
  170.         fclose(fobArt);
  171.  
  172.         return bEverythingOK;
  173. }
  174.