/*
        Frank Lyonnet 1993
        Lecture header JPEG
*/

#include <stdio.h>
#include "Bool.h"
#include "Erreur.h"
#include "Modes.h"

typedef enum
{			/* JPEG marker codes */
   M_SOF0 = 0xc0,
   M_SOF1 = 0xc1,
   M_SOF2 = 0xc2,
   M_SOF3 = 0xc3,

   M_SOF5 = 0xc5,
   M_SOF6 = 0xc6,
   M_SOF7 = 0xc7,

   M_JPG = 0xc8,
   M_SOF9 = 0xc9,
   M_SOF10 = 0xca,
   M_SOF11 = 0xcb,

   M_SOF13 = 0xcd,
   M_SOF14 = 0xce,
   M_SOF15 = 0xcf,

   M_DHT = 0xc4,

   M_DAC = 0xcc,

   M_RST0 = 0xd0,
   M_RST1 = 0xd1,
   M_RST2 = 0xd2,
   M_RST3 = 0xd3,
   M_RST4 = 0xd4,
   M_RST5 = 0xd5,
   M_RST6 = 0xd6,
   M_RST7 = 0xd7,

   M_SOI = 0xd8,
   M_EOI = 0xd9,
   M_SOS = 0xda,
   M_DQT = 0xdb,
   M_DNL = 0xdc,
   M_DRI = 0xdd,
   M_DHP = 0xde,
   M_EXP = 0xdf,

   M_APP0 = 0xe0,
   M_APP15 = 0xef,

   M_JPG0 = 0xf0,
   M_JPG13 = 0xfd,
   M_COM = 0xfe,

   M_TEM = 0x01,

   M_ERROR = 0x100
}   JPEG_MARKER;

static int get_2bytes(FILE * File)
/* Get a 2-byte unsigned integer (e.g., a marker parameter length field) */
{
int a;

   a = getc(File);
   return (a << 8) + getc(File);
}

static void skip_variable(FILE * File, int code)
/* Skip over an unknown or uninteresting variable-length marker */
{
int length;

   length = get_2bytes(File);

   for (length -= 2; length > 0; length--)
      (void) getc(File);
}


static int next_marker(FILE * File)
/* Find the next JPEG marker */
/* Note that the output might not be a valid marker code, */
/* but it will never be 0 or FF */
{
int c, nbytes;

   nbytes = 0;
   do
   {
      do
      {				/* skip any non-FF bytes */
	 nbytes++;
	 c = getc(File);
      }
      while (c != 0xFF);
      do
      {
	 /* skip any duplicate FFs */
	 /* we don't increment nbytes here since extra FFs are legal */
	 c = getc(File);
      }
      while (c == 0xFF);
   }
   while (c == 0);		/* repeat if it was a stuffed FF/00 */
   return c;
}


static int process_tables(FILE * File)
/* Scan and process JPEG markers that can appear in any order */
/* Return when an SOI, EOI, SOFn, or SOS is found */
{
int c;

   while (TRUE)
   {
      c = next_marker(File);

      switch (c)
      {
      case M_SOF0:
      case M_SOF1:
      case M_SOF2:
      case M_SOF3:
      case M_SOF5:
      case M_SOF6:
      case M_SOF7:
      case M_JPG:
      case M_SOF9:
      case M_SOF10:
      case M_SOF11:
      case M_SOF13:
      case M_SOF14:
      case M_SOF15:
      case M_SOI:
      case M_EOI:
      case M_SOS:
	 return ((JPEG_MARKER) c);
      default:			/* must be DNL, DHP, EXP, APPn, JPGn, COM, or
				   RESn */
	 skip_variable(File, c);
	 break;
      }
   }
}



void get_jpeg_size(char *Filename, int *Width, int *Height)
{
FILE *File;
int c;

   File = fopen(Filename, "r");
   if (getc(File) != 0xFF || getc(File) != M_SOI)
   {
      erreur("Not a JPEG file \n");
      return;
   };

   /* Process markers until SOF */
   c = process_tables(File);

   (void) get_2bytes(File);
   (void) getc(File);
   *Height = get_2bytes(File);
   *Width = get_2bytes(File);
   fclose(File);
}

BOOL is_jpeg(char *Filename)
{
FILE *File;
BOOL Res;

   File = fopen(Filename, "r");
   Res = !(getc(File) != 0xFF || getc(File) != M_SOI);
   fclose(File);
   return (Res);
}

void get_jpeg_bpp_and_colorspace(char *Filename,int *Bpp,int *Colorspace)
{
FILE *File;
int c;
int NumComp;

   File = fopen(Filename, "r");
   if (getc(File) != 0xFF || getc(File) != M_SOI)
   {
      erreur("Not a JPEG file \n");
      return;
   };

   /* Process markers until SOF */
   c = process_tables(File);

   (void) get_2bytes(File);
   (void) getc(File);
   (void) get_2bytes(File);
   (void) get_2bytes(File);
   NumComp = getc(File);

   switch(NumComp)
   {
      case 1:
         *Bpp = 8;
         *Colorspace = FYEO_GRAY;
         break;
      case 3:
         *Bpp = 24;
         *Colorspace = FYEO_YUV;
         break;
      case 4:
         *Bpp = 32;
         *Colorspace = FYEO_CYMK;
         break;
      default:
         break;
   };

   fclose(File);
}

