source: libcaca/trunk/src/cacaview.c @ 734

Last change on this file since 734 was 734, checked in by Sam Hocevar, 14 years ago
  • Renamed *bitmap to *dither. Ben ouais connard, je fais ce que je veux.
  • Property svn:keywords set to Id
File size: 20.5 KB
Line 
1/*
2 *  cacaview      image viewer for libcaca
3 *  Copyright (c) 2003 Sam Hocevar <sam@zoy.org>
4 *                All Rights Reserved
5 *
6 *  $Id: cacaview.c 734 2006-04-10 20:02:38Z sam $
7 *
8 *  This program is free software; you can redistribute it and/or
9 *  modify it under the terms of the Do What The Fuck You Want To
10 *  Public License, Version 2, as published by Sam Hocevar. See
11 *  http://sam.zoy.org/wtfpl/COPYING for more details.
12 */
13
14#include "config.h"
15
16#include <stdio.h>
17#include <string.h>
18#include <stdlib.h>
19
20#if defined(HAVE_IMLIB2_H)
21#   include <Imlib2.h>
22#else
23#   include <stdio.h>
24#endif
25
26#if defined(HAVE_SLEEP)
27#   include <windows.h>
28#endif
29
30#include "cucul.h"
31#include "caca.h"
32
33/* Local macros */
34#define MODE_IMAGE 1
35#define MODE_FILES 2
36
37#define STATUS_DITHERING 1
38#define STATUS_ANTIALIASING 2
39#define STATUS_BACKGROUND 3
40
41#define ZOOM_FACTOR 1.08f
42#define ZOOM_MAX 50
43#define GAMMA_FACTOR 1.04f
44#define GAMMA_MAX 100
45#define GAMMA(g) (((g) < 0) ? 1.0 / gammatab[-(g)] : gammatab[(g)])
46#define PAD_STEP 0.15
47
48/* libcucul/libcaca contexts */
49cucul_t *qq; caca_t *kk;
50
51/* Local functions */
52static void print_status(void);
53static void print_help(int, int);
54static void set_zoom(int);
55static void set_gamma(int);
56static void load_image(char const *);
57static void unload_image(void);
58static void draw_checkers(int, int, int, int);
59#if !defined(HAVE_IMLIB2_H)
60static int freadint(FILE *);
61static int freadshort(FILE *);
62static int freadchar(FILE *);
63#endif
64
65/* Local variables */
66#if defined(HAVE_IMLIB2_H)
67Imlib_Image image = NULL;
68#endif
69char *pixels = NULL;
70struct cucul_dither *dither = NULL;
71unsigned int w, h, depth, bpp, rmask, gmask, bmask, amask;
72#if !defined(HAVE_IMLIB2_H)
73unsigned int red[256], green[256], blue[256], alpha[256];
74#endif
75
76float zoomtab[ZOOM_MAX + 1];
77float gammatab[GAMMA_MAX + 1];
78float xfactor = 1.0, yfactor = 1.0, dx = 0.5, dy = 0.5;
79int zoom = 0, g = 0, fullscreen = 0, mode, ww, wh;
80
81int main(int argc, char **argv)
82{
83    int quit = 0, update = 1, help = 0, status = 0;
84    int reload = 0;
85
86    char **list = NULL;
87    int current = 0, items = 0, opts = 1;
88    int i;
89
90    /* Initialise libcucul */
91    qq = cucul_create(0, 0);
92    if(!qq)
93    {
94        fprintf(stderr, "%s: unable to initialise libcucul\n", argv[0]);
95        return 1;
96    }
97
98    kk = caca_attach(qq);
99    if(!kk)
100    {
101        fprintf(stderr, "%s: unable to initialise libcaca\n", argv[0]);
102        return 1;
103    }
104
105    /* Set the window title */
106    caca_set_window_title(kk, "cacaview");
107
108    ww = cucul_get_width(qq);
109    wh = cucul_get_height(qq);
110
111    /* Fill the zoom table */
112    zoomtab[0] = 1.0;
113    for(i = 0; i < ZOOM_MAX; i++)
114        zoomtab[i + 1] = zoomtab[i] * ZOOM_FACTOR;
115
116    /* Fill the gamma table */
117    gammatab[0] = 1.0;
118    for(i = 0; i < GAMMA_MAX; i++)
119        gammatab[i + 1] = gammatab[i] * GAMMA_FACTOR;
120
121    /* Load items into playlist */
122    for(i = 1; i < argc; i++)
123    {
124        /* Skip options except after `--' */
125        if(opts && argv[i][0] == '-')
126        {
127            if(argv[i][1] == '-' && argv[i][2] == '\0')
128                opts = 0;
129            continue;
130        }
131
132        /* Add argv[i] to the list */
133        if(items)
134            list = realloc(list, (items + 1) * sizeof(char *));
135        else
136            list = malloc(sizeof(char *));
137        list[items] = argv[i];
138        items++;
139
140        reload = 1;
141    }
142
143    /* Go ! */
144    while(!quit)
145    {
146        struct caca_event ev;
147        unsigned int const event_mask = CACA_EVENT_KEY_PRESS
148                                      | CACA_EVENT_RESIZE
149                                      | CACA_EVENT_MOUSE_PRESS;
150        unsigned int new_status = 0, new_help = 0;
151        int event;
152
153        if(update)
154            event = caca_get_event(kk, event_mask, &ev, 0);
155        else
156            event = caca_get_event(kk, event_mask, &ev, -1);
157
158        while(event)
159        {
160            if(ev.type & CACA_EVENT_MOUSE_PRESS)
161            {
162                if(ev.data.mouse.button == 1)
163                {
164                    if(items) current = (current + 1) % items;
165                    reload = 1;
166                }
167                else if(ev.data.mouse.button == 2)
168                {
169                    if(items) current = (items + current - 1) % items;
170                    reload = 1;
171                }
172            }
173            else if(ev.type & CACA_EVENT_KEY_PRESS) switch(ev.data.key.c)
174            {
175            case 'n':
176            case 'N':
177                if(items) current = (current + 1) % items;
178                reload = 1;
179                break;
180            case 'p':
181            case 'P':
182                if(items) current = (items + current - 1) % items;
183                reload = 1;
184                break;
185            case 'f':
186            case 'F':
187                fullscreen = ~fullscreen;
188                update = 1;
189                set_zoom(zoom);
190                break;
191            case 'b':
192                i = 1 + cucul_get_feature(qq, CUCUL_BACKGROUND);
193                if(i > CUCUL_BACKGROUND_MAX) i = CUCUL_BACKGROUND_MIN;
194                cucul_set_feature(qq, i);
195                new_status = STATUS_BACKGROUND;
196                update = 1;
197                break;
198            case 'B':
199                i = -1 + cucul_get_feature(qq, CUCUL_BACKGROUND);
200                if(i < CUCUL_BACKGROUND_MIN) i = CUCUL_BACKGROUND_MAX;
201                cucul_set_feature(qq, i);
202                new_status = STATUS_BACKGROUND;
203                update = 1;
204                break;
205            case 'a':
206                i = 1 + cucul_get_feature(qq, CUCUL_ANTIALIASING);
207                if(i > CUCUL_ANTIALIASING_MAX) i = CUCUL_ANTIALIASING_MIN;
208                cucul_set_feature(qq, i);
209                new_status = STATUS_ANTIALIASING;
210                update = 1;
211                break;
212            case 'A':
213                i = -1 + cucul_get_feature(qq, CUCUL_ANTIALIASING);
214                if(i < CUCUL_ANTIALIASING_MIN) i = CUCUL_ANTIALIASING_MAX;
215                cucul_set_feature(qq, i);
216                new_status = STATUS_ANTIALIASING;
217                update = 1;
218                break;
219            case 'd':
220                i = 1 + cucul_get_feature(qq, CUCUL_DITHERING);
221                if(i > CUCUL_DITHERING_MAX) i = CUCUL_DITHERING_MIN;
222                cucul_set_feature(qq, i);
223                new_status = STATUS_DITHERING;
224                update = 1;
225                break;
226            case 'D':
227                i = -1 + cucul_get_feature(qq, CUCUL_DITHERING);
228                if(i < CUCUL_DITHERING_MIN) i = CUCUL_DITHERING_MAX;
229                cucul_set_feature(qq, i);
230                new_status = STATUS_DITHERING;
231                update = 1;
232                break;
233            case '+':
234                update = 1;
235                set_zoom(zoom + 1);
236                break;
237            case '-':
238                update = 1;
239                set_zoom(zoom - 1);
240                break;
241            case 'G':
242                update = 1;
243                set_gamma(g + 1);
244                break;
245            case 'g':
246                update = 1;
247                set_gamma(g - 1);
248                break;
249            case 'x':
250            case 'X':
251                update = 1;
252                set_zoom(0);
253                set_gamma(0);
254                break;
255            case 'k':
256            case 'K':
257            case CACA_KEY_UP:
258                if(yfactor > 1.0) dy -= PAD_STEP / yfactor;
259                if(dy < 0.0) dy = 0.0;
260                update = 1;
261                break;
262            case 'j':
263            case 'J':
264            case CACA_KEY_DOWN:
265                if(yfactor > 1.0) dy += PAD_STEP / yfactor;
266                if(dy > 1.0) dy = 1.0;
267                update = 1;
268                break;
269            case 'h':
270            case 'H':
271            case CACA_KEY_LEFT:
272                if(xfactor > 1.0) dx -= PAD_STEP / xfactor;
273                if(dx < 0.0) dx = 0.0;
274                update = 1;
275                break;
276            case 'l':
277            case 'L':
278            case CACA_KEY_RIGHT:
279                if(xfactor > 1.0) dx += PAD_STEP / xfactor;
280                if(dx > 1.0) dx = 1.0;
281                update = 1;
282                break;
283            case '?':
284                new_help = !help;
285                update = 1;
286                break;
287            case 'q':
288            case 'Q':
289                quit = 1;
290                break;
291            }
292            else if(ev.type == CACA_EVENT_RESIZE)
293            {
294                caca_display(kk);
295                ww = ev.data.resize.w;
296                wh = ev.data.resize.h;
297                update = 1;
298                set_zoom(zoom);
299            }
300
301            if(status || new_status)
302                status = new_status;
303
304            if(help || new_help)
305                help = new_help;
306
307            event = caca_get_event(kk, CACA_EVENT_KEY_PRESS, &ev, 0);
308        }
309
310        if(items && reload)
311        {
312            char *buffer;
313            int len = strlen(" Loading `%s'... ") + strlen(list[current]);
314
315            if(len < ww + 1)
316                len = ww + 1;
317
318            buffer = malloc(len);
319
320            sprintf(buffer, " Loading `%s'... ", list[current]);
321            buffer[ww] = '\0';
322            cucul_set_color(qq, CUCUL_COLOR_WHITE, CUCUL_COLOR_BLUE);
323            cucul_putstr(qq, (ww - strlen(buffer)) / 2, wh / 2, buffer);
324            caca_display(kk);
325            ww = cucul_get_width(qq);
326            wh = cucul_get_height(qq);
327
328            unload_image();
329            load_image(list[current]);
330            reload = 0;
331
332            /* Reset image-specific runtime variables */
333            dx = dy = 0.5;
334            update = 1;
335            set_zoom(0);
336            set_gamma(0);
337
338            free(buffer);
339        }
340
341        cucul_clear(qq);
342
343        if(!items)
344        {
345            cucul_set_color(qq, CUCUL_COLOR_WHITE, CUCUL_COLOR_BLUE);
346            cucul_printf(qq, ww / 2 - 5, wh / 2, " No image. ");
347        }
348        else if(!pixels)
349        {
350#if defined(HAVE_IMLIB2_H)
351#   define ERROR_STRING " Error loading `%s'. "
352#else
353#   define ERROR_STRING " Error loading `%s'. Only BMP is supported. "
354#endif
355            char *buffer;
356            int len = strlen(ERROR_STRING) + strlen(list[current]);
357
358            if(len < ww + 1)
359                len = ww + 1;
360
361            buffer = malloc(len);
362
363            sprintf(buffer, ERROR_STRING, list[current]);
364            buffer[ww] = '\0';
365            cucul_set_color(qq, CUCUL_COLOR_WHITE, CUCUL_COLOR_BLUE);
366            cucul_putstr(qq, (ww - strlen(buffer)) / 2, wh / 2, buffer);
367            free(buffer);
368        }
369        else
370        {
371            float xdelta, ydelta;
372            int y, height;
373
374            y = fullscreen ? 0 : 1;
375            height = fullscreen ? wh : wh - 3;
376
377            xdelta = (xfactor > 1.0) ? dx : 0.5;
378            ydelta = (yfactor > 1.0) ? dy : 0.5;
379
380            draw_checkers(ww * (1.0 - xfactor) / 2,
381                          y + height * (1.0 - yfactor) / 2,
382                          ww * (1.0 + xfactor) / 2,
383                          y + height * (1.0 + yfactor) / 2);
384
385            cucul_dither_bitmap(qq, ww * (1.0 - xfactor) * xdelta,
386                              y + height * (1.0 - yfactor) * ydelta,
387                              ww * (xdelta + (1.0 - xdelta) * xfactor),
388                              y + height * (ydelta + (1.0 - ydelta) * yfactor),
389                              dither, pixels);
390        }
391
392        if(!fullscreen)
393        {
394            print_status();
395
396            cucul_set_color(qq, CUCUL_COLOR_LIGHTGRAY, CUCUL_COLOR_BLACK);
397            switch(status)
398            {
399                case STATUS_ANTIALIASING:
400                    cucul_printf(qq, 0, wh - 1, "Antialiasing: %s",
401                  cucul_get_feature_name(cucul_get_feature(qq, CUCUL_ANTIALIASING)));
402                    break;
403                case STATUS_DITHERING:
404                    cucul_printf(qq, 0, wh - 1, "Dithering: %s",
405                  cucul_get_feature_name(cucul_get_feature(qq, CUCUL_DITHERING)));
406                    break;
407                case STATUS_BACKGROUND:
408                    cucul_printf(qq, 0, wh - 1, "Background: %s",
409                  cucul_get_feature_name(cucul_get_feature(qq, CUCUL_BACKGROUND)));
410                    break;
411            }
412        }
413
414        if(help)
415        {
416            print_help(ww - 26, 2);
417        }
418
419        caca_display(kk);
420        update = 0;
421    }
422
423    /* Clean up */
424    unload_image();
425    caca_detach(kk);
426    cucul_free(qq);
427
428    return 0;
429}
430
431static void print_status(void)
432{
433    cucul_set_color(qq, CUCUL_COLOR_WHITE, CUCUL_COLOR_BLUE);
434    cucul_draw_line(qq, 0, 0, ww - 1, 0, " ");
435    cucul_draw_line(qq, 0, wh - 2, ww - 1, wh - 2, "-");
436    cucul_putstr(qq, 0, 0, "q:Quit  np:Next/Prev  +-x:Zoom  gG:Gamma  "
437                           "hjkl:Move  d:Dither  a:Antialias");
438    cucul_putstr(qq, ww - strlen("?:Help"), 0, "?:Help");
439    cucul_printf(qq, 3, wh - 2, "cacaview %s", VERSION);
440    cucul_printf(qq, ww - 30, wh - 2, "(gamma: %#.3g)", GAMMA(g));
441    cucul_printf(qq, ww - 14, wh - 2, "(zoom: %s%i)", zoom > 0 ? "+" : "", zoom);
442
443    cucul_set_color(qq, CUCUL_COLOR_LIGHTGRAY, CUCUL_COLOR_BLACK);
444    cucul_draw_line(qq, 0, wh - 1, ww - 1, wh - 1, " ");
445}
446
447static void print_help(int x, int y)
448{
449    static char const *help[] =
450    {
451        " +: zoom in              ",
452        " -: zoom out             ",
453        " g: decrease gamma       ",
454        " G: increase gamma       ",
455        " x: reset zoom and gamma ",
456        " ----------------------- ",
457        " hjkl: move view         ",
458        " arrows: move view       ",
459        " ----------------------- ",
460        " a: antialiasing method  ",
461        " d: dithering method     ",
462        " b: background mode      ",
463        " ----------------------- ",
464        " ?: help                 ",
465        " q: quit                 ",
466        NULL
467    };
468
469    int i;
470
471    cucul_set_color(qq, CUCUL_COLOR_WHITE, CUCUL_COLOR_BLUE);
472
473    for(i = 0; help[i]; i++)
474        cucul_putstr(qq, x, y + i, help[i]);
475}
476
477static void set_zoom(int new_zoom)
478{
479    int height;
480
481    zoom = new_zoom;
482
483    if(zoom > ZOOM_MAX) zoom = ZOOM_MAX;
484    if(zoom < -ZOOM_MAX) zoom = -ZOOM_MAX;
485
486    ww = cucul_get_width(qq);
487    height = fullscreen ? wh : wh - 3;
488
489    xfactor = (zoom < 0) ? 1.0 / zoomtab[-zoom] : zoomtab[zoom];
490    yfactor = xfactor * ww / height * h / w
491               * cucul_get_height(qq) / cucul_get_width(qq)
492               * caca_get_window_width(kk) / caca_get_window_height(kk);
493
494    if(yfactor > xfactor)
495    {
496        float tmp = xfactor;
497        xfactor = tmp * tmp / yfactor;
498        yfactor = tmp;
499    }
500}
501
502static void set_gamma(int new_gamma)
503{
504    g = new_gamma;
505
506    if(g > GAMMA_MAX) g = GAMMA_MAX;
507    if(g < -GAMMA_MAX) g = -GAMMA_MAX;
508
509    cucul_set_dither_gamma(dither, (g < 0) ? 1.0 / gammatab[-g] : gammatab[g]);
510}
511
512static void unload_image(void)
513{
514#if defined(HAVE_IMLIB2_H)
515    if(image)
516        imlib_free_image();
517    image = NULL;
518    pixels = NULL;
519#else
520    if(pixels)
521        free(pixels);
522    pixels = NULL;
523#endif
524    if(dither)
525        cucul_free_dither(dither);
526    dither = NULL;
527}
528
529static void load_image(char const *name)
530{
531#if defined(HAVE_IMLIB2_H)
532    /* Load the new image */
533    image = imlib_load_image(name);
534
535    if(!image)
536        return;
537
538    imlib_context_set_image(image);
539    pixels = (char *)imlib_image_get_data_for_reading_only();
540    w = imlib_image_get_width();
541    h = imlib_image_get_height();
542    rmask = 0x00ff0000;
543    gmask = 0x0000ff00;
544    bmask = 0x000000ff;
545    amask = 0xff000000;
546    bpp = 32;
547    depth = 4;
548
549    /* Create the libcucul dither */
550    dither = cucul_create_dither(bpp, w, h, depth * w,
551                                 rmask, gmask, bmask, amask);
552    if(!dither)
553    {
554        imlib_free_image();
555        image = NULL;
556    }
557
558#else
559    /* Try to load a BMP file */
560    FILE *fp;
561    unsigned int i, colors, offset, tmp, planes;
562
563    fp = fopen(name, "rb");
564    if(!fp)
565        return;
566
567    if(freadshort(fp) != 0x4d42)
568    {
569        fclose(fp);
570        return;
571    }
572
573    freadint(fp); /* size */
574    freadshort(fp); /* reserved 1 */
575    freadshort(fp); /* reserved 2 */
576
577    offset = freadint(fp);
578
579    tmp = freadint(fp); /* header size */
580    if(tmp == 40)
581    {
582        w = freadint(fp);
583        h = freadint(fp);
584        planes = freadshort(fp);
585        bpp = freadshort(fp);
586
587        tmp = freadint(fp); /* compression */
588        if(tmp != 0)
589        {
590            fclose(fp);
591            return;
592        }
593
594        freadint(fp); /* sizeimage */
595        freadint(fp); /* xpelspermeter */
596        freadint(fp); /* ypelspermeter */
597        freadint(fp); /* biclrused */
598        freadint(fp); /* biclrimportantn */
599
600        colors = (offset - 54) / 4;
601        for(i = 0; i < colors && i < 256; i++)
602        {
603            blue[i] = freadchar(fp) * 16;
604            green[i] = freadchar(fp) * 16;
605            red[i] = freadchar(fp) * 16;
606            alpha[i] = 0;
607            freadchar(fp);
608        }
609    }
610    else if(tmp == 12)
611    {
612        w = freadint(fp);
613        h = freadint(fp);
614        planes = freadshort(fp);
615        bpp = freadshort(fp);
616
617        colors = (offset - 26) / 3;
618        for(i = 0; i < colors && i < 256; i++)
619        {
620            blue[i] = freadchar(fp);
621            green[i] = freadchar(fp);
622            red[i] = freadchar(fp);
623            alpha[i] = 0;
624        }
625    }
626    else
627    {
628        fclose(fp);
629        return;
630    }
631
632    /* Fill the rest of the palette */
633    for(i = colors; i < 256; i++)
634        blue[i] = green[i] = red[i] = alpha[i] = 0;
635
636    depth = (bpp + 7) / 8;
637
638    /* Sanity check */
639    if(!w || w > 0x10000 || !h || h > 0x10000 || planes != 1 /*|| bpp != 24*/)
640    {
641        fclose(fp);
642        return;
643    }
644
645    /* Allocate the pixel buffer */
646    pixels = malloc(w * h * depth);
647    if(!pixels)
648    {
649        fclose(fp);
650        return;
651    }
652
653    memset(pixels, 0, w * h * depth);
654
655    /* Read the dither data */
656    for(i = h; i--; )
657    {
658        unsigned int j, k, bits = 0;
659
660        switch(bpp)
661        {
662            case 1:
663                for(j = 0; j < w; j++)
664                {
665                    k = j % 32;
666                    if(k == 0)
667                        bits = freadint(fp);
668                    pixels[w * i * depth + j] =
669                        (bits >> ((k & ~0xf) + 0xf - (k & 0xf))) & 0x1;
670                }
671                break;
672            case 4:
673                for(j = 0; j < w; j++)
674                {
675                    k = j % 8;
676                    if(k == 0)
677                        bits = freadint(fp);
678                    pixels[w * i * depth + j] =
679                        (bits >> (4 * ((k & ~0x1) + 0x1 - (k & 0x1)))) & 0xf;
680                }
681                break;
682            default:
683                /* Works for 8bpp, but also for 16, 24 etc. */
684                fread(pixels + w * i * depth, w * depth, 1, fp);
685                /* Pad reads to 4 bytes */
686                tmp = (w * depth) % 4;
687                tmp = (4 - tmp) % 4;
688                while(tmp--)
689                    freadchar(fp);
690                break;
691        }
692    }
693
694    switch(depth)
695    {
696    case 3:
697        rmask = 0xff0000;
698        gmask = 0x00ff00;
699        bmask = 0x0000ff;
700        amask = 0x000000;
701        break;
702    case 2: /* XXX: those are the 16 bits values */
703        rmask = 0x7c00;
704        gmask = 0x03e0;
705        bmask = 0x001f;
706        amask = 0x0000;
707        break;
708    case 1:
709    default:
710        bpp = 8;
711        rmask = gmask = bmask = amask = 0;
712        break;
713    }
714
715    fclose(fp);
716
717    /* Create the libcucul dither */
718    dither = cucul_create_dither(bpp, w, h, depth * w,
719                                 rmask, gmask, bmask, amask);
720    if(!dither)
721    {
722        free(pixels);
723        pixels = NULL;
724        return;
725    }
726
727    if(bpp == 8)
728        cucul_set_dither_palette(dither, red, green, blue, alpha);
729#endif
730}
731
732static void draw_checkers(int x1, int y1, int x2, int y2)
733{
734    int xn, yn;
735
736    if(x2 + 1 > (int)cucul_get_width(qq)) x2 = cucul_get_width(qq) - 1;
737    if(y2 + 1 > (int)cucul_get_height(qq)) y2 = cucul_get_height(qq) - 1;
738
739    for(yn = y1 > 0 ? y1 : 0; yn <= y2; yn++)
740        for(xn = x1 > 0 ? x1 : 0; xn <= x2; xn++)
741    {
742        if((((xn - x1) / 5) ^ ((yn - y1) / 3)) & 1)
743            cucul_set_color(qq, CUCUL_COLOR_LIGHTGRAY, CUCUL_COLOR_DARKGRAY);
744        else
745            cucul_set_color(qq, CUCUL_COLOR_DARKGRAY, CUCUL_COLOR_LIGHTGRAY);
746        cucul_putchar(qq, xn, yn, ' ');
747    }
748}
749
750#if !defined(HAVE_IMLIB2_H)
751static int freadint(FILE *fp)
752{
753    unsigned char buffer[4];
754    fread(buffer, 4, 1, fp);
755    return ((int)buffer[3] << 24) | ((int)buffer[2] << 16)
756             | ((int)buffer[1] << 8) | ((int)buffer[0]);
757}
758
759static int freadshort(FILE *fp)
760{
761    unsigned char buffer[2];
762    fread(buffer, 2, 1, fp);
763    return ((int)buffer[1] << 8) | ((int)buffer[0]);
764}
765
766static int freadchar(FILE *fp)
767{
768    unsigned char buffer;
769    fread(&buffer, 1, 1, fp);
770    return (int)buffer;
771}
772#endif
773
Note: See TracBrowser for help on using the repository browser.