1 /*
2  * hat_grp.c
3  * decode GRP format images in the `Hatsune no Naisho!'.
4  * 1998/03/12 by TF
5  * 1999/05/08 updated
6  */
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include "hat_grp.h"
10 #include "leaf_util.h"
11 
12 #define RING_BUF_SIZ 0x1000
13 
14 static GRP *grp_new(void);
15 static int set_palette_from_data(GRP *, unsigned char *, int);
16 static void get_plain_palette(GRP *, unsigned char *, int, int);
17 static void get_compressed_palette(GRP *, unsigned char *, int, int);
18 static int extract_image(GRP *, unsigned char *, int);
19 static void optimize_palette(GRP *);
20 
read_grp(const char * filename)21 GRP *read_grp(const char *filename)
22 {
23   return NULL;
24 }
25 
grp_free(GRP * grp)26 void grp_free(GRP *grp)
27 {
28   if (grp == NULL) {
29     return;
30   }
31   if (grp->image != NULL) {
32     free(grp->image);
33   }
34   if (grp != NULL) {
35     free(grp);
36   }
37 }
38 
read_grp_from_data(unsigned char * palette,int psize,unsigned char * body,int bsize)39 GRP *read_grp_from_data(unsigned char *palette, int psize, unsigned char *body, int bsize)
40 {
41   GRP *grp;
42 
43   grp = grp_new();
44   if (set_palette_from_data(grp, palette, psize) < 0) {
45     fprintf(stderr, "read_grp_from_data: Can't read palette.\n");
46     grp_free(grp);
47     return NULL;
48   }
49   if (extract_image(grp, body, bsize) < 0) {
50     fprintf(stderr, "read_grp_from_data: Can't decode body.\n");
51     grp_free(grp);
52     return NULL;
53   }
54 
55   optimize_palette(grp);
56 
57   return grp;
58 }
59 
grp_new(void)60 static GRP *grp_new(void)
61 {
62   int i;
63   GRP *grp;
64 
65   grp = (GRP *)malloc(sizeof(GRP));
66   if (grp == NULL) {
67     fprintf(stderr, "grp_new: memory allocation error.\n");
68     exit(1);
69   }
70   grp->width = 0;
71   grp->height = 0;
72   grp->color_num = 0;
73   grp->transparent = -1;
74   for (i = 0; i < 256; i++) {
75     grp->palette[i][GRP_R] = -1;
76     grp->palette[i][GRP_G] = -1;
77     grp->palette[i][GRP_B] = -1;
78   }
79   grp->image = NULL;
80   return grp;
81 }
82 
set_palette_from_data(GRP * grp,unsigned char * palette,int psize)83 static int set_palette_from_data(GRP *grp, unsigned char *palette, int psize)
84 {
85   if (palette[1] == 0) {
86     /* plain palette */
87     grp->color_num = palette[0];
88     get_plain_palette(grp, palette, psize, 2);
89 #ifdef DEBUG
90     fprintf(stderr, "  plain palette(size=%d)\n", grp->color_num);
91 #endif
92   } else {
93     /* compressed palette */
94     get_compressed_palette(grp, palette, psize, 0);
95 #ifdef DEBUG
96     fprintf(stderr, "  compressed palette(size=%d)\n", grp->color_num);
97 #endif
98   }
99   return 0;
100 }
101 
get_plain_palette(GRP * grp,unsigned char * palette,int psize,int idx)102 static void get_plain_palette(GRP *grp, unsigned char *palette, int psize, int idx)
103 {
104   int i, id;
105 
106   for (i = 0; i < grp->color_num; i++) {
107     id = palette[idx++];    /* palette ID */
108     /*
109      * Does the palette order(B-G-R) differ with 'Saorin to issho(R-G-B)'?
110      */
111     grp->palette[id][GRP_B] = palette[idx++];
112     grp->palette[id][GRP_G] = palette[idx++];
113     grp->palette[id][GRP_R] = palette[idx++];
114 
115     if (grp->color_num < 16) {
116       /* should we change a palette on 16 colors? */
117       grp->palette[id][GRP_B] = (grp->palette[id][GRP_R] & 0xf0) + (grp->palette[id][GRP_R] >> 4);
118       grp->palette[id][GRP_G] = (grp->palette[id][GRP_G] & 0xf0) + (grp->palette[id][GRP_G] >> 4);
119       grp->palette[id][GRP_R] = (grp->palette[id][GRP_B] & 0xf0) + (grp->palette[id][GRP_B] >> 4);
120     }
121   }
122 }
123 
get_compressed_palette(GRP * grp,unsigned char * palette,int psize,int idx)124 static void get_compressed_palette(GRP *grp, unsigned char *palette, int psize, int idx)
125 {
126   int osize, esize;
127   unsigned char *dst;
128   int i;
129 
130   osize = LONGWORD(palette[idx], palette[idx + 1], palette[idx + 2], palette[idx + 3]);
131   esize = LONGWORD(palette[idx + 4], palette[idx + 5], palette[idx + 6], palette[idx + 7]);
132 
133   if (osize != psize) {
134     fprintf(stderr, "get_compressed_palette: Invalid header.\n");
135   }
136   dst = (unsigned char *)calloc(esize, sizeof(unsigned char));
137   if (dst == NULL) {
138     perror("calloc");
139     exit(1);
140   }
141 
142   extract_lz77(palette + 8, osize - 8, dst, esize, RING_BUF_SIZ);
143 
144   grp->color_num = dst[0];
145 
146   for (i = 2; i < esize; i += 4) {
147     grp->palette[dst[i]][GRP_B] = dst[i + 1];
148     grp->palette[dst[i]][GRP_G] = dst[i + 2];
149     grp->palette[dst[i]][GRP_R] = dst[i + 3];
150     /* printf("%02x: %02x, %02x, %02x\n",
151 	   dst[i], dst[i + 1], dst[i + 2], dst[i + 3]); */
152   }
153   free(dst);
154 }
155 
extract_image(GRP * grp,unsigned char * body,int bsize)156 static int extract_image(GRP *grp, unsigned char *body, int bsize)
157 {
158   int i, j;
159   int idx = 4;
160   unsigned char *dst;
161 
162   grp->orig_size = LONGWORD(body[0], body[1], body[2], body[3]);
163   grp->extracted_size = LONGWORD(body[4], body[5], body[6], body[7]);
164 
165   dst = (unsigned char *)calloc(grp->extracted_size, sizeof(unsigned char));
166   if (dst == NULL) {
167     perror("calloc");
168     exit(1);
169   }
170   extract_lz77(body + 8, bsize - 8, dst, grp->extracted_size, RING_BUF_SIZ);
171 
172   grp->width = WORD(dst[0], dst[1]);
173   grp->height = WORD(dst[2], dst[3]);
174   grp->image = (int *)calloc(grp->width * grp->height, sizeof(int));
175   if (grp->image == NULL) {
176     perror("calloc");
177     exit(1);
178   }
179 
180   for (i = 0; i < grp->height; i++) {
181     for (j = 0; j < grp->width; j++) {
182       grp->image[i * grp->width + j] = dst[idx++];
183     }
184   }
185   free(dst);
186 
187   /* transparent specification may be embedded in the game's executable. */
188   grp->transparent = grp->image[0];
189 
190   return 0;
191 }
192 
optimize_palette(GRP * grp)193 static void optimize_palette(GRP *grp)
194 {
195   int col[256];
196   int idx[256];
197   int i, j;
198 
199   for (i = 0; i < 256; i++) {
200     col[i] = -1;
201     idx[i] = 0;
202   }
203 
204   for (i = 0; i < grp->width * grp->height; i++) {
205     col[grp->image[i]] = 0;
206   }
207 
208   for (i = 0, j = 0; i < 256; i++) {
209     if (col[i] == 0) {
210       grp->palette[j][GRP_R] = grp->palette[i][GRP_R];
211       grp->palette[j][GRP_G] = grp->palette[i][GRP_G];
212       grp->palette[j][GRP_B] = grp->palette[i][GRP_B];
213       idx[i] = j;
214       j++;
215     }
216   }
217   if (grp->transparent >= j) {
218     if (j < 256) {
219       grp->transparent = j;
220       grp->color_num = j + 1;
221     }  else {
222       grp->transparent = 255;
223     }
224   } else {
225     grp->transparent = idx[grp->transparent];
226   }
227 
228   for (i = 0; i < grp->width * grp->height; i++) {
229     if (grp->image[i] < 0) {
230       grp->image[i] = idx[grp->image[0]];
231     } else {
232       grp->image[i] = idx[grp->image[i]];
233     }
234   }
235 }
236