Subversion Repositories ipe_artfile_utils

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 daniel-mar 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
}