Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/* jpeg parser by tom szymanski */
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <ctype.h>

/* subroutines done by macros */
#define min(A,B)        ((A)<(B) ? (A) : (B))
#define max(A,B)        ((A)>(B) ? (A) : (B))
#define maxeql(A,B)     if (A < (B)) A = (B);
#define mineql(A,B)     if (A > (B)) A = (B);
#define eatarg0         (argc--, argv++)
#define arrayLength(A) ((sizeof A)/ (sizeof A[0]))

FILE *infile;
char *fname;

/* Routines to print error messages of varying severity */

/* externally visible variables */
int   warncnt;
char *myname;

void getname (char *arg) {
        /* Save name of invoking program for use by error routines */
        register char *p;
        p = strrchr (arg, '/');
        if (p == NULL)
                myname = arg;
        else
                myname = ++p;
}

static void introduction (void) {
        warncnt++;
        fflush (stdout);
        if (myname != NULL)
                fprintf (stderr, "%s: ", myname);
}

void warn (char *fmt, ...) {
        va_list args;
        introduction ();
        va_start (args, fmt);
        vfprintf (stderr, fmt, args);
        va_end (args);
        fputc ('\n', stderr);
        fflush (stderr);
}

void quit (char *fmt, ...) {
        va_list args;
        introduction ();
        va_start (args, fmt);
        vfprintf (stderr, fmt, args);
        va_end (args);
        fputc ('\n', stderr);
        fflush (stderr);
        exit (1);
}

void fatal (char *fmt, ...) {
        va_list args;
        introduction ();
        va_start (args, fmt);
        vfprintf (stderr, fmt, args);
        va_end (args);
        fprintf (stderr, "\nbetter get help!\n");
        fflush (stderr);
        abort ();
}

int toption = 0;
int dqt[16][64];

int get1 (void) {
        unsigned char x;
        if (fread(&x, 1, 1, infile) == 0)
                quit ("unexpected EOF");
        return x;
}

int get2 (void) {
        int x;

        x = get1() << 8;
        return x | get1();
}

void eatmarker (int kind) {
        int l, c;
        l = get2();
        printf ("%02x len=%d\n", kind, l);
        for (l -= 2; l > 0; l--)
                get1();
}

char *sofName[16] = {
        "Baseline sequential DCT - Huffman coding",
        "Extended sequential DCT - Huffman coding",
        "Progressive DCT - Huffman coding",
        "Lossless - Huffman coding",
        "4 is otherwise used",
        "Sequential DCT - differential Huffman coding",
        "Progressive DCT - differential Huffman coding",
        "Lossless - differential Huffman coding",
        "8 is reserved",
        "Extended Sequential DCT - arithmetic coding",
        "Progressive DCT - arithmetic coding",
        "Lossless - arithmetic coding",
        "c is otherwise used",
        "Sequential DCT - differential arithmetic coding",
        "Progressive DCT - differential arithmetic coding",
        "Lossless - differential arithmetic coding",
};

void get_sof (int kind) {
        int i, length, height, width, precision, ncomponents;
        int id, sf, tab;
        length = get2();
        precision = get1();
        height = get2();
        width = get2();
        ncomponents = get1();
        printf ("SOF%d:\t%s\n", kind - 0xc0, sofName[kind - 0xc0]);
        printf ("\t%d wide, %d high, %d deep, %d components\n",
                width, height, precision, ncomponents);
        for (i = 0; i < ncomponents; i++) {
                id = get1();
                sf = get1();
                tab = get1();
                printf ("\tcomponent %d: %d hsample, %d vsample, quantization table %d\n",
                        id, sf >> 4, sf & 0xf, tab);
        }               
}

void get_com (int kind) {
        int l, c;
        l = get2();
        printf ("COM len=%d '", l);
        for (l -= 2; l > 0; l--)
                putchar (c = get1());
        printf ("'\n");
}

void get_app (int kind) {
        int l, c, first;
        char buf[6];
        int nbuf, nok;
        l = get2();
        printf ("APP%d len=%d\n", kind - 0xe0, l);
        nbuf = 0;
        nok = 0;
        first = 1;
        /* dump printable strings in comment */
        for (l -= 2; l > 0; l--){
                c = get1();
                if(isprint(c)){
                        if(nbuf >= sizeof buf){
                                if(!first && nbuf == nok)
                                        printf(" ");
                                printf("%.*s", nbuf, buf);
                                nbuf = 0;
                                first = 0;
                        }
                        buf[nbuf++] = c;
                        nok++;
                }else{
                        if(nok >= sizeof buf)
                                if(nbuf > 0)
                                        printf("%.*s", nbuf, buf);
                        nbuf = 0;
                        nok = 0;
                }
        }
        if(nok >= sizeof buf)
                if(nbuf > 0){
                        if(!first && nbuf == nok)
                                printf(" ");
                        printf("%.*s", nbuf, buf);
                }
}

void get_dac (int kind) {
        eatmarker (kind);
}

int get1dqt (void) {
        int t, p, i, *tab;
        t = get1();
        p = t >> 4;
        t = t & 0xf;
        printf ("DQT:\tp = %d, table = %d\n", p, t);
        tab = &dqt[t][0];
        for (i = 0; i < 64; i++)
                tab[i] = p ? get2() : get1();
        if (toption) {
                for (i = 0; i < 64; i++)
                        printf ("\t%q[%02d] = %d\n", i, tab[i]);
        }
        return p ? 65 : 129;
}

void get_dqt (int kind) {
        int length;
        length = get2() - 2;
        while (length > 0)
                length -= get1dqt();
}

int get1dht (void) {
        int l, tcth, p, i, j, v[16], vv[16][256];
        tcth = get1();
        printf ("DHT:\tclass = %d, table = %d\n", tcth >> 4, tcth & 0xf);
        for (i = 0; i < 16; i++)
                v[i] = get1();
        l = 17;
        for (i = 0; i < 16; i++)
                for (j = 0; j < v[i]; j++) {
                        vv[i][j] = get1();
                        l += 1;
                }
        if (toption) {
                for (i = 0; i < 16; i++)
                        printf ("\t%l[%02d] = %d\n", i+1, v[i]);
                for (i = 0; i < 16; i++)
                        for (j = 0; j < v[i]; j++)
                                printf ("\t%v[%02d,%02d] = %d\n", i+1, j+1, vv[i][j]);
        }
        return l;
}

void get_dht (int kind) {
        int length;
        length = get2() - 2;
        while (length > 0)
                length -= get1dht();
}

void get_sos (int kind) {
        int i, length, ncomponents, id, dcac, ahal;
        length = get2();
        ncomponents = get1();
        printf ("SOS:\t%d components\n", ncomponents);
        for (i = 0; i < ncomponents; i++) {
                id = get1();
                dcac = get1();
                printf ("\tcomponent %d: %d DC, %d AC\n", id, dcac >> 4, dcac & 0xf);
        }
        printf ("\tstart spectral %d\n", get1());
        printf ("\tend spectral %d\n", get1());
        ahal = get1();
        printf ("\tah = %d, al = %d\n", ahal >> 4, ahal &0xf);
}

main (int argc, char *argv[]) {
        int l, stuff, i, j, c;
        while (argc > 1 && argv[1][0] == '-') {
                switch (argv[1][1]) {
                case 't':
                        toption = 1;
                        break;
                default:
                        warn ("bad option '%c'", argv[1][1]);
                }
                eatarg0;
        }
        fname = argv[1];
        infile = fopen (fname, "r");
        if (infile == NULL)
                quit ("can't open %s\n", fname);
    Start:
//      if (get1() != 0xff || get1() != 0xd8)
//              quit ("not JFIF");
//      printf ("SOI\n");
//      get_app (0xe0);
        for (;;) {
                c = get1();
                if (c != 0xff)
                        quit ("expected marker, got %2x", c);
                do {
                        c = get1();
                } while (c == 0xff);
marker:
                switch (c) {
                case 0xc0: case 0xc1: case 0xc2: case 0xc3:
                case 0xc5: case 0xc6: case 0xc7:
                case 0xc8: case 0xc9: case 0xca: case 0xcb:
                case 0xcd: case 0xce: case 0xcf:
                        get_sof (c);
                        break;
                case 0xc4:
                        get_dht (c);
                        break;
                case 0xcc:
                        get_dac (c);
                        break;
                case 0xd8:
                        printf ("SOI\n");
                        break;
                case 0xe0: case 0xe1: case 0xe2: case 0xe3: 
                case 0xe4: case 0xe5: case 0xe6: case 0xe7: 
                case 0xe8: case 0xe9: case 0xea: case 0xeb: 
                case 0xec: case 0xed: case 0xee: case 0xef: 
                        get_app(c);
                        break;
                case 0xda:
                        get_sos (c);
                        goto newentropy;
                case 0xdb:
                        get_dqt (c);
                        break;
                case 0xfe:
                        get_com (c);
                        break;
                case 0xd9:
                        printf ("EOI\n");
                        if((c=getc(infile)) == EOF)
                                exit(0);
                        ungetc(c, infile);
                        goto Start;
                default:
                        eatmarker (c);
                }
                continue;
newentropy:
                l = stuff = 0;
entropy:
                while ((c = get1()) != 0xff)
                        l += 1;
                while (c == 0xff)
                        c = get1();
                if (c == 0) {
                        stuff += 1;
                        goto entropy;
                }
                printf ("sequence length %d with %d stuffs\n", l, stuff);
                if (0xd0 <= c && c <= 0xd7) {
                        printf ("restart %d\n", c - 0xd0);
                        goto newentropy;
                }
                goto marker;
        }
}