]> Creatis software - gdcm.git/blob - src/jpeg/ljpg/read.c
FIX: put back everything since I broke tests, warnings should be discarded -apparently-
[gdcm.git] / src / jpeg / ljpg / read.c
1 /*
2  * read.c --
3  *
4  * Code for reading and processing JPEG markers.  Large parts are grabbed
5  * from the IJG software
6  */
7 /*
8  * $Id: read.c,v 1.2 2004/08/18 02:26:08 malaterre Exp $
9  */
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include "jpeg.h"
14 #include "mcu.h"
15 #include "io.h"
16 #include "proto.h"
17
18 /*
19  * To fix a memory leak (memory malloc'd then never freed) in the original
20  * version of lossless JPEG decompression, memory is allocated for 4 
21  * Huffman tables once here, then pointers set later as needed
22  */
23
24 static HuffmanTable HuffmanTableMemory[4];
25
26 /* 
27  * Enumerate all the JPEG marker codes
28  */
29 typedef enum {
30       M_SOF0 = 0xc0,
31       M_SOF1 = 0xc1,
32       M_SOF2 = 0xc2,
33       M_SOF3 = 0xc3,
34
35       M_SOF5 = 0xc5,
36       M_SOF6 = 0xc6,
37       M_SOF7 = 0xc7,
38
39       M_JPG = 0xc8,
40       M_SOF9 = 0xc9,
41       M_SOF10 = 0xca,
42       M_SOF11 = 0xcb,
43
44       M_SOF13 = 0xcd,
45       M_SOF14 = 0xce,
46       M_SOF15 = 0xcf,
47
48       M_DHT = 0xc4,
49
50       M_DAC = 0xcc,
51
52       M_RST0 = 0xd0,
53       M_RST1 = 0xd1,
54       M_RST2 = 0xd2,
55       M_RST3 = 0xd3,
56       M_RST4 = 0xd4,
57       M_RST5 = 0xd5,
58       M_RST6 = 0xd6,
59       M_RST7 = 0xd7,
60
61       M_SOI = 0xd8,
62       M_EOI = 0xd9,
63       M_SOS = 0xda,
64       M_DQT = 0xdb,
65       M_DNL = 0xdc,
66       M_DRI = 0xdd,
67       M_DHP = 0xde,
68       M_EXP = 0xdf,
69
70       M_APP0 = 0xe0,
71       M_APP15 = 0xef,
72
73       M_JPG0 = 0xf0,
74       M_JPG13 = 0xfd,
75       M_COM = 0xfe,
76
77       M_TEM = 0x01,
78
79       M_ERROR = 0x100
80 } JpegMarker;
81
82
83 /*
84  *--------------------------------------------------------------
85  *
86  * Get2bytes --
87  *
88  *        Get a 2-byte unsigned integer (e.g., a marker parameter length
89  *        field)
90  *
91  * Results:
92  *        Next two byte of input as an integer.
93  *
94  * Side effects:
95  *        Bitstream is parsed.
96  *
97  *--------------------------------------------------------------
98  */
99 static Uint Get2bytes (void)
100 {
101     int a;
102     a = GetJpegChar();
103     return (a << 8) + GetJpegChar();
104 }
105
106 /*
107  *--------------------------------------------------------------
108  *
109  * SkipVariable --
110  *
111  *        Skip over an unknown or uninteresting variable-length marker
112  *
113  * Results:
114  *        None.
115  *
116  * Side effects:
117  *        Bitstream is parsed over marker.
118  *
119  *
120  *--------------------------------------------------------------
121  */
122 static void SkipVariable (DecompressInfo *dcPtr)
123 {
124     int length;
125
126     length = Get2bytes () - 2;
127
128     while (length--) {
129         GetJpegChar();
130     }
131 }
132
133 /*
134  *--------------------------------------------------------------
135  *
136  * GetDht --
137  *
138  *        Process a DHT marker
139  *
140  * Results:
141  *        None
142  *
143  * Side effects:
144  *        A huffman table is read.
145  *        Exits on error.
146  *
147  *--------------------------------------------------------------
148  */
149 static void GetDht (DecompressInfo *dcPtr)
150 {
151     int length;
152     Uchar bits[17];
153     Uchar huffval[256];
154     int i, index, count;
155     HuffmanTable **htblptr=NULL;
156
157     length = Get2bytes () - 2;
158
159     while (length) {
160         index = GetJpegChar();
161
162         bits[0] = 0;
163         count = 0;
164         for (i = 1; i <= 16; i++) {
165             bits[i] = GetJpegChar();
166             count += bits[i];
167         }
168
169         if (count > 256) {
170             fprintf (stderr, "Bogus DHT counts\n");
171             /* exit (1); */
172             dcPtr->error = -1; return;
173         }
174
175         for (i = 0; i < count; i++)
176             huffval[i] = GetJpegChar();
177
178         length -= 1 + 16 + count;
179
180         if (index & 0x10) {        /* AC table definition */
181            fprintf(stderr,"Huffman table for lossless JPEG is not defined.\n");
182         } 
183         else {                /* DC table definition */
184             htblptr = &dcPtr->dcHuffTblPtrs[index];
185         }
186
187         if (index < 0 || index >= 4) 
188         {
189             fprintf (stderr, "Bogus DHT index %d\n", index);
190             /* exit (1); */
191             dcPtr->error = -1; return;
192         }
193
194         if (*htblptr == NULL) 
195         {
196             *htblptr = &HuffmanTableMemory[index];
197              if (*htblptr==NULL) 
198                          {
199                 fprintf(stderr,"Can't malloc HuffmanTable\n");
200                 /* exit(-1); */
201                 dcPtr->error = -1; return;
202              }
203         }
204
205         MEMCPY((*htblptr)->bits, bits, sizeof ((*htblptr)->bits));
206         MEMCPY((*htblptr)->huffval, huffval, sizeof ((*htblptr)->huffval));
207     }
208 }
209
210 /*
211  *--------------------------------------------------------------
212  *
213  * GetDri --
214  *
215  *        Process a DRI marker
216  *
217  * Results:
218  *        None
219  *
220  * Side effects:
221  *        Exits on error.
222  *        Bitstream is parsed.
223  *
224  *--------------------------------------------------------------
225  */
226 static void GetDri (DecompressInfo *dcPtr)
227 {
228     if (Get2bytes () != 4) 
229     {
230         fprintf (stderr, "Bogus length in DRI\n");
231         /* exit (1); */
232         dcPtr->error = -1; return;
233     }
234
235     dcPtr->restartInterval = (Ushort) Get2bytes ();
236 }
237
238 /*
239  *--------------------------------------------------------------
240  *
241  * GetApp0 --
242  *
243  *        Process an APP0 marker.
244  *
245  * Results:
246  *        None
247  *
248  * Side effects:
249  *        Bitstream is parsed
250  *
251  *--------------------------------------------------------------
252  */
253 static void GetApp0 (DecompressInfo *dcPtr)
254 {
255     int length;
256
257     length = Get2bytes () - 2;
258     while (length-- > 0)        /* skip any remaining data */
259         (void)GetJpegChar();
260 }
261
262 /*
263  *--------------------------------------------------------------
264  *
265  * GetSof --
266  *
267  *        Process a SOFn marker
268  *
269  * Results:
270  *        None.
271  *
272  * Side effects:
273  *        Bitstream is parsed
274  *        Exits on error
275  *        dcPtr structure is filled in
276  *
277  *--------------------------------------------------------------
278  */
279 static void GetSof (DecompressInfo *dcPtr, int code)
280 {
281     int length;
282     short ci;
283     int c;
284     JpegComponentInfo *compptr;
285     
286     code = code;
287
288     length = Get2bytes ();
289
290     dcPtr->dataPrecision = GetJpegChar();
291     dcPtr->imageHeight = Get2bytes ();
292     dcPtr->imageWidth = Get2bytes ();
293     dcPtr->numComponents = GetJpegChar();
294
295     /*
296      * We don't support files in which the image height is initially
297      * specified as 0 and is later redefined by DNL.  As long as we
298      * have to check that, might as well have a general sanity check.
299      */
300     if ((dcPtr->imageHeight <= 0 ) ||
301         (dcPtr->imageWidth <= 0) || 
302         (dcPtr->numComponents <= 0)) {
303         fprintf (stderr, "Empty JPEG image (DNL not supported)\n");
304         /* exit(1); */
305         dcPtr->error = -1; return;
306     }
307
308     if ((dcPtr->dataPrecision<MinPrecisionBits) ||
309         (dcPtr->dataPrecision>MaxPrecisionBits)) {
310         fprintf (stderr, "Unsupported JPEG data precision\n");
311         /* exit(1); */
312         dcPtr->error = -1; return;
313     }
314
315     if (length != (dcPtr->numComponents * 3 + 8)) {
316         fprintf (stderr, "Bogus SOF length\n");
317         /* exit (1); */
318         dcPtr->error = -1; return;
319     }
320
321     for (ci = 0; ci < dcPtr->numComponents; ci++) {
322         compptr = &dcPtr->compInfo[ci];
323         compptr->componentIndex = ci;
324         compptr->componentId = GetJpegChar();
325         c = GetJpegChar();
326         compptr->hSampFactor = (c >> 4) & 15;
327         compptr->vSampFactor = (c) & 15;
328         (void) GetJpegChar(); /* skip Tq */
329     }
330 }/*endof GetSof */
331
332
333 /*
334  *--------------------------------------------------------------
335  *
336  * GetSos --
337  *
338  *        Process a SOS marker
339  *
340  * Results:
341  *        None.
342  *
343  * Side effects:
344  *        Bitstream is parsed.
345  *        Exits on error.
346  *
347  *--------------------------------------------------------------
348  */
349 static void GetSos (DecompressInfo *dcPtr)
350 {
351     int length;
352     int i, ci, n, c, cc;
353     JpegComponentInfo *compptr;
354
355     length = Get2bytes ();
356
357     /* 
358      * Get the number of image components.
359      */
360     n = GetJpegChar();
361     dcPtr->compsInScan = n;
362     length -= 3;
363
364     if (length != (n * 2 + 3) || n < 1 || n > 4) {
365         fprintf (stderr, "Bogus SOS length\n");
366         /* exit (1); */
367         dcPtr->error = -1; return;
368     }
369
370
371     for (i = 0; i < n; i++) {
372         cc = GetJpegChar();
373         c = GetJpegChar();
374         length -= 2;
375
376         for (ci = 0; ci < dcPtr->numComponents; ci++)
377             if (cc == dcPtr->compInfo[ci].componentId) {
378                 break;
379             }
380
381         if (ci >= dcPtr->numComponents) {
382             fprintf (stderr, "Invalid component number in SOS\n");
383             /* exit (1); */
384             dcPtr->error = -1; return;
385         }
386
387         compptr = &dcPtr->compInfo[ci];
388         dcPtr->curCompInfo[i] = compptr;
389         compptr->dcTblNo = (c >> 4) & 15;
390     }
391
392     /*
393      * Get the PSV, skip Se, and get the point transform parameter.
394      */
395     dcPtr->Ss = GetJpegChar(); 
396     (void)GetJpegChar();
397     c = GetJpegChar(); 
398     dcPtr->Pt = c & 0x0F;
399 }/*endof GetSos */
400
401
402 /*
403  *--------------------------------------------------------------
404  *
405  * GetSoi --
406  *
407  *        Process an SOI marker
408  *
409  * Results:
410  *        None.
411  *
412  * Side effects:
413  *        Bitstream is parsed.
414  *        Exits on error.
415  *
416  *--------------------------------------------------------------
417  */
418 static void GetSoi (DecompressInfo *dcPtr)
419 {
420
421     /*
422      * Reset all parameters that are defined to be reset by SOI
423      */
424     dcPtr->restartInterval = 0;
425 }
426
427 /*
428  *--------------------------------------------------------------
429  *
430  * NextMarker --
431  *
432  *      Find the next JPEG marker Note that the output might not
433  *        be a valid marker code but it will never be 0 or FF
434  *
435  * Results:
436  *        The marker found.
437  *
438  * Side effects:
439  *        Bitstream is parsed.
440  *
441  *--------------------------------------------------------------
442  */
443 static int NextMarker (void)
444 {
445     int c, nbytes;
446
447     nbytes = 0;
448     do {
449         /*
450          * skip any non-FF bytes
451          */
452         do {
453             nbytes++;
454             c = GetJpegChar();
455         } while (c != 0xFF);
456         /*
457          * skip any duplicate FFs without incrementing nbytes, since
458          * extra FFs are legal
459          */
460         do {
461             c = GetJpegChar();
462         } while (c == 0xFF);
463     } while (c == 0);                /* repeat if it was a stuffed FF/00 */
464
465     return c;
466 }
467
468 /*
469  *--------------------------------------------------------------
470  *
471  * ProcessTables --
472  *
473  *        Scan and process JPEG markers that can appear in any order
474  *        Return when an SOI, EOI, SOFn, or SOS is found
475  *
476  * Results:
477  *        The marker found.
478  *
479  * Side effects:
480  *        Bitstream is parsed.
481  *
482  *--------------------------------------------------------------
483  */
484 static JpegMarker ProcessTables (dcPtr)
485   DecompressInfo *dcPtr;
486 {
487   int c;
488
489     while (1) {
490         c = NextMarker ();
491
492         switch (c) {
493         case M_SOF0:
494         case M_SOF1:
495         case M_SOF2:
496         case M_SOF3:
497         case M_SOF5:
498         case M_SOF6:
499         case M_SOF7:
500         case M_JPG:
501         case M_SOF9:
502         case M_SOF10:
503         case M_SOF11:
504         case M_SOF13:
505         case M_SOF14:
506         case M_SOF15:
507         case M_SOI:
508         case M_EOI:
509         case M_SOS:
510             return ((JpegMarker)c);
511
512         case M_DHT:
513             GetDht (dcPtr); if (dcPtr->error) return 0;
514             break;
515
516         case M_DQT:
517             fprintf(stderr,"Not a lossless JPEG file.\n");
518             break;
519
520         case M_DRI:
521             GetDri (dcPtr); if (dcPtr->error) return 0;
522             break;
523
524         case M_APP0:
525             GetApp0 (dcPtr);
526             break;
527
528         case M_RST0:                /* these are all parameterless */
529         case M_RST1:
530         case M_RST2:
531         case M_RST3:
532         case M_RST4:
533         case M_RST5:
534         case M_RST6:
535         case M_RST7:
536         case M_TEM:
537             fprintf (stderr, "Warning: unexpected marker 0x%02x\n", c);
538             break;
539
540         default:                /* must be DNL, DHP, EXP, APPn, JPGn, COM,
541                                  * or RESn */
542             SkipVariable (dcPtr);
543             break;
544         }
545     }
546 }/*endof ProcessTables */
547
548
549 /*
550  *--------------------------------------------------------------
551  *
552  * ReadFileHeader --
553  *
554  *        Initialize and read the file header (everything through
555  *        the SOF marker).
556  *
557  * Results:
558  *        None
559  *
560  * Side effects:
561  *        Exit on error.
562  *
563  *--------------------------------------------------------------
564  */
565 void ReadFileHeader (DecompressInfo *dcPtr)
566 {
567     int c, c2;
568
569     /*
570      * Demand an SOI marker at the start of the file --- otherwise it's
571      * probably not a JPEG file at all.
572      */
573     c = GetJpegChar();
574     c2 = GetJpegChar();
575     if ((c != 0xFF) || (c2 != M_SOI)) {
576         if( c == EOF ) {
577             fprintf(stderr, "Reached end of input file. All done!\n");
578             /* fclose(outFile); */
579             /* exit(1); */
580             dcPtr->error = -1; return;
581         } else {
582             fprintf (stderr, "Not a JPEG file. Found %02X %02X\n", c, c2);
583             /* exit (1); */
584             dcPtr->error = -1; return;
585         }
586     }/*endif*/
587
588     GetSoi (dcPtr); if (dcPtr->error) return;  /* OK, process SOI */
589
590     /*
591      * Process markers until SOF
592      */
593     c = ProcessTables (dcPtr); if (dcPtr->error) return;
594
595     switch (c) {
596     case M_SOF0:
597     case M_SOF1:
598     case M_SOF3:
599         GetSof (dcPtr, c);
600         break;
601
602     default:
603         fprintf (stderr, "Unsupported SOF marker type 0x%02x\n", c);
604         break;
605     }
606 }/*endof ReadFileHeader*/
607
608
609 /*
610  *--------------------------------------------------------------
611  *
612  * ReadScanHeader --
613  *
614  *        Read the start of a scan (everything through the SOS marker).
615  *
616  * Results:
617  *        1 if find SOS, 0 if find EOI
618  *
619  * Side effects:
620  *        Bitstream is parsed, may exit on errors.
621  *
622  *--------------------------------------------------------------
623  */
624 int ReadScanHeader (DecompressInfo *dcPtr)
625 {
626     int c;
627
628     /*
629      * Process markers until SOS or EOI
630      */
631     c = ProcessTables (dcPtr); if (dcPtr->error) return 0;
632
633     switch (c) {
634     case M_SOS:
635         GetSos (dcPtr);
636         return 1;
637
638     case M_EOI:
639         return 0;
640
641     default:
642         fprintf (stderr, "Unexpected marker 0x%02x\n", c);
643         break;
644     }
645     return 0;
646 }/*endof ReadScanHeader*/
647
648
649 /*
650  *--------------------------------------------------------------
651  *
652  * GetJpegChar, UnGetJpegChar --
653  *
654  *     
655  * Results:
656  *      GetJpegChar returns the next character in the stream, or EOF
657  *      UnGetJpegChar returns nothing.
658  *
659  * Side effects:
660  *      A byte is consumed or put back into the inputBuffer.
661  *
662  *--------------------------------------------------------------
663  */
664 int GetJpegChar(void) 
665 {
666         return (int)inputBuffer[inputBufferOffset++];
667
668                                           
669 void UnGetJpegChar(int ch) 
670 {      
671         inputBuffer[--inputBufferOffset] = ch;
672 }
673