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.  * - Where's Waldo? Exploring Geography
  5.  * - Eraser Turnabout by Imagination Pilots
  6.  * - Virtual K'Nex by Imagination Pilots
  7.  * Revision: 2018-02-15
  8.  **/
  9.  
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <stdbool.h>
  13. #include <string.h>
  14. #include <math.h>
  15.  
  16. #include "ipe_artfile_packer_ipe32.h"
  17. #include "ipe32_artfile.h"
  18. #include "ipe32_bmpimport.h"
  19. #include "ipe32_lzw_encoder.h"
  20.  
  21. #define MAX_FILE 256
  22.  
  23. bool ipe32_pack_art(const char* szSrcFolder, FILE* fobArt, const int verbosity) {
  24.         bool bEverythingOK = true;
  25.  
  26.         char szIndexFilename[MAX_FILE];
  27.         sprintf(szIndexFilename, "%s/index.txt", szSrcFolder);
  28.         FILE* fitIndex = fopen(szIndexFilename, "rt");
  29.         if (!fitIndex) {
  30.                 fprintf(stderr, "Cannot open %s\n", szIndexFilename);
  31.                 return false;
  32.         }
  33.  
  34.         #define MAX_LINE 1024
  35.         char line[MAX_LINE];
  36.         int cItems = 0;
  37.         while (fgets(line, sizeof(line), fitIndex)) {
  38.                 if (strlen(line) == 0) continue;
  39.                 ++cItems;
  40.         }
  41.         if (verbosity >= 1) printf("%s contains %d entries\n", szIndexFilename, cItems); // TODO: don't print double /
  42.  
  43.         Ipe32FileHeader efh;
  44.         memset(&efh, 0x00, sizeof(efh));
  45.         strcpy(efh.magic, IPE32_MAGIC_ART);
  46.         efh.reserved = 0;
  47.         efh.totalHeaderSize = (cItems+1)*sizeof(efh);
  48.  
  49.         Ipe32PictureEntryHeader peh[cItems];
  50.         memset(&peh, 0x00, sizeof(peh));
  51.  
  52.         // These headers are currently just dummies. They will be rewritten after all pictures are processed
  53.         fwrite(&efh, sizeof(efh), 1, fobArt);
  54.         fwrite(&peh, sizeof(peh), 1, fobArt);
  55.  
  56.         Ipe32LZWEncoder *encoder = new_ipe32lzw_encoder();
  57.         ipe32lzw_init_encoder(encoder);
  58.         fseek(fitIndex, 0, SEEK_SET);
  59.         int curItem = 0;
  60.         while (fgets(line, sizeof(line), fitIndex)) {
  61.                 // If something fails, we discard the item, but continue in building the file!
  62.                 #define FAIL_CONTINUE { memset(&peh[curItem], 0x00, sizeof(peh[curItem])); bEverythingOK=false; continue; }
  63.  
  64.                 const char* szDelimiters = " \t\r\n";
  65.                 char* szName                = strtok(&line[0], szDelimiters);
  66.                 /* char* szNumCompressedChunks = */ strtok(NULL, szDelimiters);
  67.                 /* char* szNumRawChunks        = */ strtok(NULL, szDelimiters);
  68.                 char* szFilename            = strtok(NULL, szDelimiters);
  69.  
  70.                 if (strlen(szName) > IPE32_NAME_SIZE) {
  71.                         fprintf(stderr, "ERROR: Name %s is too long (max %d chars allowed)\n", szName, IPE32_NAME_SIZE);
  72.                         FAIL_CONTINUE;
  73.                 }
  74.  
  75.                 char szBitmapFilename[MAX_FILE];
  76.                 sprintf(szBitmapFilename, "%s/%s", szSrcFolder, szFilename);
  77.                 FILE* fibBitmap = fopen(szBitmapFilename, "rb");
  78.                 if (!fibBitmap) {
  79.                         fprintf(stderr, "ERROR: cannot open '%s'\n", szFilename);
  80.                         FAIL_CONTINUE;
  81.                 }
  82.  
  83.                 Ipe32BmpImportData result={0};
  84.                 if (!ipe32_bmp_import(fibBitmap, &result)) { // This function moves the file pointer to the bitmap info header
  85.                         fprintf(stderr, "Error at %s: %s\n", szFilename, result.error);
  86.                         fclose(fibBitmap);
  87.                         ipe32_free_bmpimport_result(&result);
  88.                         FAIL_CONTINUE;
  89.                 }
  90.  
  91.                 strcpy(peh[curItem].name, szName);
  92.                 peh[curItem].offset = ftell(fobArt);
  93.                 peh[curItem].uncompressedSize = result.dataSize;
  94.                 if (verbosity >= 1) printf("Process %s at offset %x\n", szName, peh[curItem].offset);
  95.  
  96.                 // Now write the chunks
  97.  
  98.                 int chunkNo = 0;
  99.                 unsigned char uncompressedChunk[0x3FFE];
  100.                 unsigned char compressedChunk[0x3FFE];
  101.                 while (1) {
  102.                         if (verbosity >= 2) fprintf(stdout, "Bitmap %s: Write chunk %d.\n", szFilename, chunkNo);
  103.  
  104.                         int uncompressedSize = fread(uncompressedChunk, 1, sizeof(uncompressedChunk), fibBitmap);
  105.                         if (uncompressedSize == 0) break; // done
  106.  
  107.                         int compressedSize = ipe32lzw_encode(encoder, compressedChunk, sizeof(compressedChunk), uncompressedChunk, uncompressedSize);
  108.  
  109.                         uint16_t len;
  110.  
  111.                         if ((compressedSize == -1) || (compressedSize >= uncompressedSize)) {
  112.                                 // Choose uncompressed chunk
  113.                                 len = 0x8000 | uncompressedSize;
  114.                                 fwrite(&len, sizeof(len), 1, fobArt);
  115.                                 fwrite(uncompressedChunk, uncompressedSize, 1, fobArt);
  116.                         } else {
  117.                                 // Choose compressed chunk
  118.                                 len = compressedSize;
  119.                                 fwrite(&len, sizeof(len), 1, fobArt);
  120.                                 fwrite(compressedChunk, compressedSize, 1, fobArt);
  121.                         }
  122.  
  123.                         chunkNo++;
  124.                 }
  125.  
  126.                 // Free and continue
  127.  
  128.                 fclose(fibBitmap);
  129.                 ipe32_free_bmpimport_result(&result);
  130.  
  131.                 ++curItem;
  132.         }
  133.         fclose(fitIndex);
  134.         ipe32lzw_free_encoder(encoder);
  135.  
  136.         fseek(fobArt, 0, SEEK_SET);
  137.         fwrite(&efh, sizeof(efh), 1, fobArt);
  138.         fwrite(&peh, sizeof(peh), 1, fobArt);
  139.  
  140.         fclose(fobArt);
  141.  
  142.         return bEverythingOK;
  143. }
  144.