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
 * - 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
}