1 //=============================================================================
2 //
3 // Adventure Game Studio (AGS)
4 //
5 // Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
6 // The full list of copyright holders can be found in the Copyright.txt
7 // file, which is part of this source code distribution.
8 //
9 // The AGS source code is provided under the Artistic License 2.0.
10 // A copy of this license can be found in the file License.txt and at
11 // http://www.opensource.org/licenses/artistic-license-2.0.php
12 //
13 //=============================================================================
14
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include "ac/common.h" // quit()
18 #include "ac/roomstruct.h"
19 #include "util/compress.h"
20 #include "util/lzw.h"
21 #include "util/misc.h"
22 #include "util/bbop.h"
23
24 #ifdef _MANAGED
25 // ensure this doesn't get compiled to .NET IL
26 #pragma unmanaged
27 #endif
28
29 #include "util/misc.h"
30 #include "util/stream.h"
31 #include "util/filestream.h"
32 #include "gfx/bitmap.h"
33
34 using namespace AGS::Common;
35
36 #ifndef __WGT4_H
37 struct color
38 {
39 unsigned char r, g, b;
40 };
41 #endif
42
43 #ifndef __CJONES_H
44 long csavecompressed(char *, __block, color[256], long = 0);
45 long cloadcompressed(char *, __block, color *, long = 0);
46 #endif
47
cpackbitl(unsigned char * line,int size,Stream * out)48 void cpackbitl(unsigned char *line, int size, Stream *out)
49 {
50 int cnt = 0; // bytes encoded
51
52 while (cnt < size) {
53 int i = cnt;
54 int j = i + 1;
55 int jmax = i + 126;
56 if (jmax >= size)
57 jmax = size - 1;
58
59 if (i == size - 1) { //................last byte alone
60 out->WriteInt8(0);
61 out->WriteInt8(line[i]);
62 cnt++;
63
64 } else if (line[i] == line[j]) { //....run
65 while ((j < jmax) && (line[j] == line[j + 1]))
66 j++;
67
68 out->WriteInt8(i - j);
69 out->WriteInt8(line[i]);
70 cnt += j - i + 1;
71
72 } else { //.............................sequence
73 while ((j < jmax) && (line[j] != line[j + 1]))
74 j++;
75
76 out->WriteInt8(j - i);
77 out->WriteArray(line + i, j - i + 1, 1);
78 cnt += j - i + 1;
79
80 }
81 } // end while
82 }
83
cpackbitl16(unsigned short * line,int size,Stream * out)84 void cpackbitl16(unsigned short *line, int size, Stream *out)
85 {
86 int cnt = 0; // bytes encoded
87
88 while (cnt < size) {
89 int i = cnt;
90 int j = i + 1;
91 int jmax = i + 126;
92 if (jmax >= size)
93 jmax = size - 1;
94
95 if (i == size - 1) { //................last byte alone
96 out->WriteInt8(0);
97 out->WriteInt16(line[i]);
98 cnt++;
99
100 } else if (line[i] == line[j]) { //....run
101 while ((j < jmax) && (line[j] == line[j + 1]))
102 j++;
103
104 out->WriteInt8(i - j);
105 out->WriteInt16(line[i]);
106 cnt += j - i + 1;
107
108 } else { //.............................sequence
109 while ((j < jmax) && (line[j] != line[j + 1]))
110 j++;
111
112 out->WriteInt8(j - i);
113 out->WriteArray(line + i, j - i + 1, 2);
114 cnt += j - i + 1;
115
116 }
117 } // end while
118 }
119
cpackbitl32(unsigned int * line,int size,Stream * out)120 void cpackbitl32(unsigned int *line, int size, Stream *out)
121 {
122 int cnt = 0; // bytes encoded
123
124 while (cnt < size) {
125 int i = cnt;
126 int j = i + 1;
127 int jmax = i + 126;
128 if (jmax >= size)
129 jmax = size - 1;
130
131 if (i == size - 1) { //................last byte alone
132 out->WriteInt8(0);
133 out->WriteInt32(line[i]);
134 cnt++;
135
136 } else if (line[i] == line[j]) { //....run
137 while ((j < jmax) && (line[j] == line[j + 1]))
138 j++;
139
140 out->WriteInt8(i - j);
141 out->WriteInt32(line[i]);
142 cnt += j - i + 1;
143
144 } else { //.............................sequence
145 while ((j < jmax) && (line[j] != line[j + 1]))
146 j++;
147
148 out->WriteInt8(j - i);
149 out->WriteArray(line + i, j - i + 1, 4);
150 cnt += j - i + 1;
151
152 }
153 } // end while
154 }
155
156
csavecompressed(char * finam,__block tobesaved,color pala[256],long exto)157 long csavecompressed(char *finam, __block tobesaved, color pala[256], long exto)
158 {
159 Stream *outpt;
160
161 if (exto > 0) {
162 outpt = ci_fopen(finam, Common::kFile_Create, Common::kFile_ReadWrite);
163 outpt->Seek(exto, kSeekBegin);
164 }
165 else
166 outpt = ci_fopen(finam, Common::kFile_CreateAlways, Common::kFile_Write);
167
168 int widt, hit;
169 long ofes;
170 widt = *tobesaved++;
171 widt += (*tobesaved++) * 256;
172 hit = *tobesaved++;
173 hit += (*tobesaved++) * 256;
174 // Those were originally written as shorts, although they are ints
175 outpt->WriteInt16(widt);
176 outpt->WriteInt16(hit);
177
178 unsigned char *ress = (unsigned char *)malloc(widt + 1);
179 int ww;
180
181 for (ww = 0; ww < hit; ww++) {
182 for (int ss = 0; ss < widt; ss++)
183 (*ress++) = (*tobesaved++);
184
185 ress -= widt;
186 cpackbitl(ress, widt, outpt);
187 }
188
189 for (ww = 0; ww < 256; ww++) {
190 outpt->WriteInt8(pala[ww].r);
191 outpt->WriteInt8(pala[ww].g);
192 outpt->WriteInt8(pala[ww].b);
193 }
194
195 ofes = outpt->GetPosition();
196 delete outpt;
197 free(ress);
198 return ofes;
199 }
200
cunpackbitl(unsigned char * line,int size,Stream * in)201 int cunpackbitl(unsigned char *line, int size, Stream *in)
202 {
203 int n = 0; // number of bytes decoded
204
205 while (n < size) {
206 int ix = in->ReadByte(); // get index byte
207 if (in->HasErrors())
208 break;
209
210 char cx = ix;
211 if (cx == -128)
212 cx = 0;
213
214 if (cx < 0) { //.............run
215 int i = 1 - cx;
216 char ch = in->ReadInt8();
217 while (i--) {
218 // test for buffer overflow
219 if (n >= size)
220 return -1;
221
222 line[n++] = ch;
223 }
224 } else { //.....................seq
225 int i = cx + 1;
226 while (i--) {
227 // test for buffer overflow
228 if (n >= size)
229 return -1;
230
231 line[n++] = in->ReadByte();
232 }
233 }
234 }
235
236 return in->HasErrors() ? -1 : 0;
237 }
238
cunpackbitl16(unsigned short * line,int size,Stream * in)239 int cunpackbitl16(unsigned short *line, int size, Stream *in)
240 {
241 int n = 0; // number of bytes decoded
242
243 while (n < size) {
244 int ix = in->ReadByte(); // get index byte
245 if (in->HasErrors())
246 break;
247
248 char cx = ix;
249 if (cx == -128)
250 cx = 0;
251
252 if (cx < 0) { //.............run
253 int i = 1 - cx;
254 unsigned short ch = in->ReadInt16();
255 while (i--) {
256 // test for buffer overflow
257 if (n >= size)
258 return -1;
259
260 line[n++] = ch;
261 }
262 } else { //.....................seq
263 int i = cx + 1;
264 while (i--) {
265 // test for buffer overflow
266 if (n >= size)
267 return -1;
268
269 line[n++] = in->ReadInt16();
270 }
271 }
272 }
273
274 return in->HasErrors() ? -1 : 0;
275 }
276
cunpackbitl32(unsigned int * line,int size,Stream * in)277 int cunpackbitl32(unsigned int *line, int size, Stream *in)
278 {
279 int n = 0; // number of bytes decoded
280
281 while (n < size) {
282 int ix = in->ReadByte(); // get index byte
283 if (in->HasErrors())
284 break;
285
286 char cx = ix;
287 if (cx == -128)
288 cx = 0;
289
290 if (cx < 0) { //.............run
291 int i = 1 - cx;
292 unsigned int ch = in->ReadInt32();
293 while (i--) {
294 // test for buffer overflow
295 if (n >= size)
296 return -1;
297
298 line[n++] = ch;
299 }
300 } else { //.....................seq
301 int i = cx + 1;
302 while (i--) {
303 // test for buffer overflow
304 if (n >= size)
305 return -1;
306
307 line[n++] = (unsigned int)in->ReadInt32();
308 }
309 }
310 }
311
312 return in->HasErrors() ? -1 : 0;
313 }
314
315 //=============================================================================
316
317 char *lztempfnm = "~aclzw.tmp";
318 Bitmap *recalced = NULL;
319
320 // returns bytes per pixel for bitmap's color depth
bmp_bpp(Bitmap * bmpt)321 int bmp_bpp(Bitmap*bmpt) {
322 if (bmpt->GetColorDepth() == 15)
323 return 2;
324
325 return bmpt->GetColorDepth() / 8;
326 }
327
save_lzw(char * fnn,Bitmap * bmpp,color * pall,long offe)328 long save_lzw(char *fnn, Bitmap *bmpp, color *pall, long offe) {
329 Stream *lz_temp_s, *out;
330 long fll, toret, gobacto;
331
332 lz_temp_s = ci_fopen(lztempfnm, Common::kFile_CreateAlways, Common::kFile_Write);
333 lz_temp_s->WriteInt32(bmpp->GetWidth() * bmpp->GetBPP());
334 lz_temp_s->WriteInt32(bmpp->GetHeight());
335 lz_temp_s->WriteArray(bmpp->GetDataForWriting(), bmpp->GetLineLength(), bmpp->GetHeight());
336 delete lz_temp_s;
337
338 out = ci_fopen(fnn, Common::kFile_Open, Common::kFile_ReadWrite);
339 out->Seek(offe, kSeekBegin);
340
341 lz_temp_s = ci_fopen(lztempfnm);
342 fll = lz_temp_s->GetLength();
343 out->WriteArray(&pall[0], sizeof(color), 256);
344 out->WriteInt32(fll);
345 gobacto = out->GetPosition();
346
347 // reserve space for compressed size
348 out->WriteInt32(fll);
349 lzwcompress(lz_temp_s, out);
350 toret = out->GetPosition();
351 out->Seek(gobacto, kSeekBegin);
352 fll = (toret - gobacto) - 4;
353 out->WriteInt32(fll); // write compressed size
354 delete lz_temp_s;
355 delete out;
356 unlink(lztempfnm);
357
358 return toret;
359 }
360
361 /*long load_lzw(char*fnn,Bitmap*bmm,color*pall,long ooff) {
362 recalced=bmm;
363 FILE*iii=clibfopen(fnn,"rb");
364 Seek(iii,ooff,SEEK_SET);*/
365
load_lzw(Stream * in,Common::Bitmap * bmm,color * pall)366 long load_lzw(Stream *in, Common::Bitmap *bmm, color *pall) {
367 int uncompsiz, *loptr;
368 unsigned char *membuffer;
369 int arin;
370
371 recalced = bmm;
372 // MACPORT FIX (HACK REALLY)
373 in->Read(&pall[0], sizeof(color)*256);
374 maxsize = in->ReadInt32();
375 uncompsiz = in->ReadInt32();
376
377 uncompsiz += in->GetPosition();
378 outbytes = 0; putbytes = 0;
379
380 update_polled_stuff_if_runtime();
381 membuffer = lzwexpand_to_mem(in);
382 update_polled_stuff_if_runtime();
383
384 loptr = (int *)&membuffer[0];
385 membuffer += 8;
386 #if defined(AGS_BIG_ENDIAN)
387 loptr[0] = AGS::Common::BBOp::SwapBytesInt32(loptr[0]);
388 loptr[1] = AGS::Common::BBOp::SwapBytesInt32(loptr[1]);
389 int bitmapNumPixels = loptr[0]*loptr[1]/_acroom_bpp;
390 switch (_acroom_bpp) // bytes per pixel!
391 {
392 case 1:
393 {
394 // all done
395 break;
396 }
397 case 2:
398 {
399 short *sp = (short *)membuffer;
400 for (int i = 0; i < bitmapNumPixels; ++i)
401 {
402 sp[i] = AGS::Common::BBOp::SwapBytesInt16(sp[i]);
403 }
404 // all done
405 break;
406 }
407 case 4:
408 {
409 int *ip = (int *)membuffer;
410 for (int i = 0; i < bitmapNumPixels; ++i)
411 {
412 ip[i] = AGS::Common::BBOp::SwapBytesInt32(ip[i]);
413 }
414 // all done
415 break;
416 }
417 }
418 #endif // defined(AGS_BIG_ENDIAN)
419
420 delete bmm;
421
422 update_polled_stuff_if_runtime();
423
424 bmm = BitmapHelper::CreateBitmap((loptr[0] / _acroom_bpp), loptr[1], _acroom_bpp * 8);
425 if (bmm == NULL)
426 quit("!load_room: not enough memory to load room background");
427
428 update_polled_stuff_if_runtime();
429
430 bmm->Acquire ();
431 recalced = bmm;
432
433 for (arin = 0; arin < loptr[1]; arin++)
434 memcpy(&bmm->GetScanLineForWriting(arin)[0], &membuffer[arin * loptr[0]], loptr[0]);
435
436 bmm->Release ();
437
438 update_polled_stuff_if_runtime();
439
440 free(membuffer-8);
441
442 if (in->GetPosition() != uncompsiz)
443 in->Seek(uncompsiz, kSeekBegin);
444
445 update_polled_stuff_if_runtime();
446
447 return uncompsiz;
448 }
449
savecompressed_allegro(char * fnn,Common::Bitmap * bmpp,color * pall,long write_at)450 long savecompressed_allegro(char *fnn, Common::Bitmap *bmpp, color *pall, long write_at) {
451 unsigned char *wgtbl = (unsigned char *)malloc(bmpp->GetWidth() * bmpp->GetHeight() + 4);
452 short *sss = (short *)wgtbl;
453 long toret;
454
455 sss[0] = bmpp->GetWidth();
456 sss[1] = bmpp->GetHeight();
457
458 memcpy(&wgtbl[4], bmpp->GetDataForWriting(), bmpp->GetWidth() * bmpp->GetHeight());
459
460 toret = csavecompressed(fnn, wgtbl, pall, write_at);
461 free(wgtbl);
462 return toret;
463 }
464
loadcompressed_allegro(Stream * in,Common::Bitmap ** bimpp,color * pall,long read_at)465 long loadcompressed_allegro(Stream *in, Common::Bitmap **bimpp, color *pall, long read_at) {
466 short widd,hitt;
467 int ii;
468
469 Bitmap *bim = *bimpp;
470 delete bim;
471
472 widd = in->ReadInt16();
473 hitt = in->ReadInt16();
474 bim = BitmapHelper::CreateBitmap(widd, hitt, 8);
475 if (bim == NULL)
476 quit("!load_room: not enough memory to decompress masks");
477 *bimpp = bim;
478
479 for (ii = 0; ii < hitt; ii++) {
480 cunpackbitl(&bim->GetScanLineForWriting(ii)[0], widd, in);
481 if (ii % 20 == 0)
482 update_polled_stuff_if_runtime();
483 }
484
485 in->Seek(768); // skip palette
486
487 return in->GetPosition();
488 }
489
490
491