1 /* Modified by -------------->Allegro<--------------
2 * (the first line is for the seek test), the "Modified by" is to
3 * silence genexample.py.
4 *
5 * Example program for the Allegro library, by Peter Wang and
6 * Elias Pschernig.
7 *
8 * This program demonstrates the use of the packfile functions, with some
9 * simple tests.
10 *
11 * The first test uses the standard packfile functions to transfer a
12 * bitmap file into a block of memory, then reads the bitmap out of the
13 * block of memory, using a custom packfile vtable.
14 *
15 * The second test reads in a bitmap with another custom packfile
16 * vtable, which uses libc's file stream functions.
17 *
18 * The third test demonstrates seeking with a custom vtable.
19 *
20 * The fourth test reads two bitmaps, and dumps them back into a
21 * single file, using a custom vtable again.
22 */
23
24 #include <stdio.h>
25 #include <string.h>
26 #include "allegro.h"
27
28 /*----------------------------------------------------------------------*/
29 /* memory vtable */
30 /*----------------------------------------------------------------------*/
31
32 /* The packfile data for our memory reader. */
33 typedef struct MEMREAD_INFO
34 {
35 AL_CONST unsigned char *block;
36 long length;
37 long offset;
38 } MEMREAD_INFO;
39
memread_getc(void * userdata)40 static int memread_getc(void *userdata)
41 {
42 MEMREAD_INFO *info = userdata;
43 ASSERT(info);
44 ASSERT(info->offset <= info->length);
45
46 if (info->offset == info->length)
47 return EOF;
48 else
49 return info->block[info->offset++];
50 }
51
memread_ungetc(int c,void * userdata)52 static int memread_ungetc(int c, void *userdata)
53 {
54 MEMREAD_INFO *info = userdata;
55 unsigned char ch = c;
56
57 if ((info->offset > 0) && (info->block[info->offset-1] == ch))
58 return ch;
59 else
60 return EOF;
61 }
62
memread_putc(int c,void * userdata)63 static int memread_putc(int c, void *userdata)
64 {
65 return EOF;
66 }
67
memread_fread(void * p,long n,void * userdata)68 static long memread_fread(void *p, long n, void *userdata)
69 {
70 MEMREAD_INFO *info = userdata;
71 size_t actual;
72 ASSERT(info);
73 ASSERT(info->offset <= info->length);
74
75 actual = MIN(n, info->length - info->offset);
76
77 memcpy(p, info->block + info->offset, actual);
78 info->offset += actual;
79
80 ASSERT(info->offset <= info->length);
81
82 return actual;
83 }
84
memread_fwrite(AL_CONST void * p,long n,void * userdata)85 static long memread_fwrite(AL_CONST void *p, long n, void *userdata)
86 {
87 return 0;
88 }
89
memread_seek(void * userdata,int offset)90 static int memread_seek(void *userdata, int offset)
91 {
92 MEMREAD_INFO *info = userdata;
93 long actual;
94 ASSERT(info);
95 ASSERT(info->offset <= info->length);
96
97 actual = MIN(offset, info->length - info->offset);
98
99 info->offset += actual;
100
101 ASSERT(info->offset <= info->length);
102
103 if (offset == actual)
104 return 0;
105 else
106 return -1;
107 }
108
memread_fclose(void * userdata)109 static int memread_fclose(void *userdata)
110 {
111 return 0;
112 }
113
memread_feof(void * userdata)114 static int memread_feof(void *userdata)
115 {
116 MEMREAD_INFO *info = userdata;
117
118 return info->offset >= info->length;
119 }
120
memread_ferror(void * userdata)121 static int memread_ferror(void *userdata)
122 {
123 (void)userdata;
124
125 return FALSE;
126 }
127
128 /* The actual vtable. Note that writing is not supported, the functions for
129 * writing above are only placeholders.
130 */
131 static PACKFILE_VTABLE memread_vtable =
132 {
133 memread_fclose,
134 memread_getc,
135 memread_ungetc,
136 memread_fread,
137 memread_putc,
138 memread_fwrite,
139 memread_seek,
140 memread_feof,
141 memread_ferror
142 };
143
144 /*----------------------------------------------------------------------*/
145 /* stdio vtable */
146 /*----------------------------------------------------------------------*/
147
stdio_fclose(void * userdata)148 static int stdio_fclose(void *userdata)
149 {
150 FILE *fp = userdata;
151 return fclose(fp);
152 }
153
stdio_getc(void * userdata)154 static int stdio_getc(void *userdata)
155 {
156 FILE *fp = userdata;
157 return fgetc(fp);
158 }
159
stdio_ungetc(int c,void * userdata)160 static int stdio_ungetc(int c, void *userdata)
161 {
162 FILE *fp = userdata;
163 return ungetc(c, fp);
164 }
165
stdio_fread(void * p,long n,void * userdata)166 static long stdio_fread(void *p, long n, void *userdata)
167 {
168 FILE *fp = userdata;
169 return fread(p, 1, n, fp);
170 }
171
stdio_putc(int c,void * userdata)172 static int stdio_putc(int c, void *userdata)
173 {
174 FILE *fp = userdata;
175 return fputc(c, fp);
176 }
177
stdio_fwrite(AL_CONST void * p,long n,void * userdata)178 static long stdio_fwrite(AL_CONST void *p, long n, void *userdata)
179 {
180 FILE *fp = userdata;
181 return fwrite(p, 1, n, fp);
182 }
183
stdio_seek(void * userdata,int n)184 static int stdio_seek(void *userdata, int n)
185 {
186 FILE *fp = userdata;
187 return fseek(fp, n, SEEK_CUR);
188 }
189
stdio_feof(void * userdata)190 static int stdio_feof(void *userdata)
191 {
192 FILE *fp = userdata;
193 return feof(fp);
194 }
195
stdio_ferror(void * userdata)196 static int stdio_ferror(void *userdata)
197 {
198 FILE *fp = userdata;
199 return ferror(fp);
200 }
201
202 /* The actual vtable. */
203 static PACKFILE_VTABLE stdio_vtable =
204 {
205 stdio_fclose,
206 stdio_getc,
207 stdio_ungetc,
208 stdio_fread,
209 stdio_putc,
210 stdio_fwrite,
211 stdio_seek,
212 stdio_feof,
213 stdio_ferror
214 };
215
216 /*----------------------------------------------------------------------*/
217 /* tests */
218 /*----------------------------------------------------------------------*/
219
next(void)220 static void next(void)
221 {
222 textprintf_centre_ex(screen, font, SCREEN_W / 2,
223 SCREEN_H - text_height(font), -1, -1, "Press a key to continue");
224 readkey();
225 clear_bitmap(screen);
226 }
227
228 #define CHECK(x, err) \
229 do { \
230 if (!x) { \
231 alert("Error", err, NULL, "Ok", NULL, 0, 0); \
232 return; \
233 } \
234 } while (0)
235
236 /* This reads the files mysha.pcx and allegro.pcx into a memory block as
237 * binary data, and then uses the memory vtable to read the bitmaps out of
238 * the memory block.
239 */
memread_test(void)240 static void memread_test(void)
241 {
242 PACKFILE *f;
243 MEMREAD_INFO memread_info;
244 BITMAP *bmp, *bmp2;
245 unsigned char *block;
246 int64_t l1, l2;
247 PACKFILE *f1, *f2;
248
249 l1 = file_size_ex("allegro.pcx");
250 l2 = file_size_ex("mysha.pcx");
251
252 block = malloc(l1 + l2);
253
254 /* Read mysha.pcx into the memory block. */
255 f1 = pack_fopen("allegro.pcx", "rb");
256 CHECK(f1, "opening allegro.pcx");
257 pack_fread(block, l1, f1);
258 pack_fclose(f1);
259
260 /* Read allegro.pcx into the memory block. */
261 f2 = pack_fopen("mysha.pcx", "rb");
262 CHECK(f2, "opening mysha.pcx");
263 pack_fread(block + l1, l2, f2);
264 pack_fclose(f2);
265
266 /* Open the memory block as PACKFILE, using our memory vtable. */
267 memread_info.block = block;
268 memread_info.length = l1 + l2;
269 memread_info.offset = 0;
270 f = pack_fopen_vtable(&memread_vtable, &memread_info);
271 CHECK(f, "reading from memory block");
272
273 /* Read the bitmaps out of the memory block. */
274 bmp = load_pcx_pf(f, NULL);
275 CHECK(bmp, "load_pcx_pf");
276 bmp2 = load_pcx_pf(f, NULL);
277 CHECK(bmp2, "load_pcx_pf");
278
279 blit(bmp, screen, 0, 0, 0, 0, bmp->w, bmp->h);
280 textprintf_ex(screen, font, bmp->w + 8, 8, -1, -1,
281 "\"allegro.pcx\"");
282 textprintf_ex(screen, font, bmp->w + 8, 8 + 20, -1, -1,
283 "read out of a memory file");
284
285 blit(bmp2, screen, 0, 0, 0, bmp->h + 8, bmp2->w, bmp2->h);
286 textprintf_ex(screen, font, bmp2->w + 8, bmp->h + 8, -1, -1,
287 "\"mysha.pcx\"");
288 textprintf_ex(screen, font, bmp2->w + 8, bmp->h + 8 + 20, -1, -1,
289 "read out of a memory file");
290
291 destroy_bitmap(bmp);
292 destroy_bitmap(bmp2);
293 pack_fclose(f);
294
295 next();
296 }
297
298 /* This reads in allegro.pcx, but it does so by using the stdio vtable. */
stdio_read_test(void)299 static void stdio_read_test(void)
300 {
301 FILE *fp, *fp2;
302 PACKFILE *f;
303 BITMAP *bmp,*bmp2;
304
305 /* Simply open the file with the libc fopen. */
306 fp = fopen("allegro.pcx", "rb");
307 CHECK(fp, "opening allegro.pcx");
308
309 /* Create a PACKFILE, with our custom stdio vtable. */
310 f = pack_fopen_vtable(&stdio_vtable, fp);
311 CHECK(f, "reading with stdio");
312
313 /* Now read in the bitmap. */
314 bmp = load_pcx_pf(f, NULL);
315 CHECK(bmp, "load_pcx_pf");
316
317 /* A little bit hackish, we re-assign the file pointer in our PACKFILE
318 * to another file.
319 */
320 fp2 = freopen("mysha.pcx", "rb", fp);
321 CHECK(fp2, "opening mysha.pcx");
322
323 /* Read in the other bitmap. */
324 bmp2 = load_pcx_pf(f, NULL);
325 CHECK(bmp, "load_pcx_pf");
326
327 blit(bmp, screen, 0, 0, 0, 0, bmp->w, bmp->h);
328 textprintf_ex(screen, font, bmp2->w + 8, 8, -1, -1,
329 "\"allegro.pcx\"");
330 textprintf_ex(screen, font, bmp2->w + 8, 8 + 20, -1, -1,
331 "read with stdio functions");
332
333 blit(bmp2, screen, 0, 0, 0, bmp->h + 8, bmp2->w, bmp2->h);
334 textprintf_ex(screen, font, bmp2->w + 8, bmp->h + 8, -1, -1,
335 "\"mysha.pcx\"");
336 textprintf_ex(screen, font, bmp2->w + 8, bmp->h + 8 + 20, -1, -1,
337 "read with stdio functions");
338
339 destroy_bitmap(bmp);
340 destroy_bitmap(bmp2);
341 pack_fclose(f);
342
343 next();
344 }
345
346 /* This demonstrates seeking. It opens expackf.c, and reads some characters
347 * from it.
348 */
stdio_seek_test(void)349 static void stdio_seek_test(void)
350 {
351 FILE *fp;
352 PACKFILE *f;
353 char str[8];
354
355 fp = fopen("expackf.c", "rb");
356 if (!fp) {
357 /* Handle the case where the user is running from a build directory
358 * directly under the Allegro root directory.
359 */
360 fp = fopen("../../examples/expackf.c", "rb");
361 }
362 CHECK(fp, "opening expackf.c");
363 f = pack_fopen_vtable(&stdio_vtable, fp);
364 CHECK(f, "reading with stdio");
365
366 pack_fseek(f, 33);
367 pack_fread(str, 7, f);
368 str[7] = '\0';
369
370 textprintf_ex(screen, font, 0, 0, -1, -1, "Reading from \"expackf.c\" with stdio.");
371 textprintf_ex(screen, font, 0, 20, -1, -1, "Seeking to byte 33, reading 7 bytes:");
372 textprintf_ex(screen, font, 0, 40, -1, -1, "\"%s\"", str);
373 textprintf_ex(screen, font, 0, 60, -1, -1, "(Should be \"Allegro\")");
374
375 pack_fclose(f);
376
377 next();
378 }
379
380 /* This demonstrates writing. It simply saves the two bitmaps into a binary
381 * file.
382 */
stdio_write_test(void)383 static void stdio_write_test(void)
384 {
385 FILE *fp;
386 PACKFILE *f;
387 BITMAP *bmp, *bmp2;
388
389 /* Read the bitmaps. */
390 bmp = load_pcx("allegro.pcx", NULL);
391 CHECK(bmp, "load_pcx");
392 bmp2 = load_pcx("mysha.pcx", NULL);
393 CHECK(bmp2, "load_pcx");
394
395 /* Write them with out custom vtable. */
396 fp = fopen("expackf.out", "wb");
397 CHECK(fp, "writing expackf.out");
398 f = pack_fopen_vtable(&stdio_vtable, fp);
399 CHECK(f, "writing with stdio");
400
401 save_tga_pf(f, bmp, NULL);
402 save_bmp_pf(f, bmp2, NULL);
403
404 destroy_bitmap(bmp);
405 destroy_bitmap(bmp2);
406 pack_fclose(f);
407
408 /* Now read them in again with our custom vtable. */
409 fp = fopen("expackf.out", "rb");
410 CHECK(fp, "fopen");
411 f = pack_fopen_vtable(&stdio_vtable, fp);
412 CHECK(f, "reading from stdio");
413
414 /* Note: in general you would need to implement a "chunking" system
415 * that knows where the boundary of each file is. Many file format
416 * loaders will happily read everything to the end of the file,
417 * whereas others stop reading as soon as they have all the essential
418 * data (e.g. there may be some metadata at the end of the file).
419 * Concatenating bare files together only works in examples programs.
420 */
421 bmp = load_tga_pf(f, NULL);
422 CHECK(bmp, "load_tga_pf");
423 bmp2 = load_bmp_pf(f, NULL);
424 CHECK(bmp2, "load_bmp_pf");
425
426 blit(bmp, screen, 0, 0, 0, 0, bmp->w, bmp->h);
427 textprintf_ex(screen, font, bmp2->w + 8, 8, -1, -1,
428 "\"allegro.pcx\" (as tga)");
429 textprintf_ex(screen, font, bmp2->w + 8, 8 + 20, -1, -1,
430 "wrote with stdio functions");
431
432 blit(bmp2, screen, 0, 0, 0, bmp->h + 8, bmp2->w, bmp2->h);
433 textprintf_ex(screen, font, bmp2->w + 8, bmp->h + 8, -1, -1,
434 "\"mysha.pcx\" (as bmp)");
435 textprintf_ex(screen, font, bmp2->w + 8, bmp->h + 8 + 20, -1, -1,
436 "wrote with stdio functions");
437
438 destroy_bitmap(bmp);
439 destroy_bitmap(bmp2);
440 pack_fclose(f);
441
442 next();
443 }
444
445 /*----------------------------------------------------------------------*/
446
main(void)447 int main(void)
448 {
449 if (allegro_init() != 0)
450 return 1;
451 install_keyboard();
452 set_color_depth(32);
453 if (set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0) != 0) {
454 set_gfx_mode(GFX_TEXT, 0, 0, 0, 0);
455 allegro_message("Unable to set a 640x480x32 windowed mode\n%s\n", allegro_error);
456 return 1;
457 }
458
459 memread_test();
460
461 stdio_read_test();
462
463 stdio_seek_test();
464
465 stdio_write_test();
466
467 return 0;
468 }
469
470 END_OF_MAIN()
471