#include <stdio.h>
#include <setjmp.h>
#include <jpeglib.h>

#define GLOBALDECL(decl) decl; decl

static jmp_buf j;

static void err (j_common_ptr jpeg_info)
{
  (void) jpeg_info;
  longjmp (j, 1);
}

GLOBALDECL (int JPEGSize (const char *FileName, int *Width, int *Height))
{
  struct jpeg_decompress_struct cinfo;
  struct jpeg_error_mgr jerr;
  FILE *input_file = fopen(FileName, "r");
  if (!input_file)
    return 0;
  if (setjmp (j))
    {
      jpeg_destroy_decompress (&cinfo);
      fclose (input_file);
      return 0;
    }
  cinfo.err = jpeg_std_error (&jerr);
  cinfo.err->error_exit = err;
  jpeg_create_decompress (&cinfo);
  jpeg_stdio_src (&cinfo, input_file);
  jpeg_read_header (&cinfo, TRUE);
  jpeg_destroy_decompress (&cinfo);
  fclose (input_file);
  *Width = cinfo.image_width;
  *Height = cinfo.image_height;
  return 1;
}

typedef struct
{
  struct jpeg_source_mgr pub;
  JOCTET buffer[2];
  int count;
  int (*get_byte) ();
} my_source_mgr;

static boolean fill_input_buffer (j_decompress_ptr cinfo)
{
  my_source_mgr *src = (my_source_mgr *) cinfo->src;
  int i = src->get_byte ();
  if (i < 0)
    {
      src->buffer[0] = (JOCTET) 0xff;
      src->buffer[1] = (JOCTET) JPEG_EOI;
      src->pub.bytes_in_buffer = 2;
    }
  else
    {
      src->count++;
      src->buffer[0] = i;
      src->pub.bytes_in_buffer = 1;
    }
  src->pub.next_input_byte = src->buffer;
  return TRUE;
}

static void skip_input_data (j_decompress_ptr cinfo, long num_bytes)
{
  my_source_mgr *src = (my_source_mgr *) cinfo->src;
  if (num_bytes <= 0)
    return;
  num_bytes -= (long) src->pub.bytes_in_buffer;
  src->pub.bytes_in_buffer = 0;
  while (num_bytes-- && src->get_byte () >= 0)
    src->count++;
}

static void dummy (j_decompress_ptr cinfo __attribute__ ((__unused__)))
{
}

GLOBALDECL (int JPEGFindEndOfFile (int (*get_byte) ()))
{
  struct jpeg_decompress_struct srcinfo;
  struct jpeg_error_mgr jsrcerr;
  my_source_mgr m;
  srcinfo.err = jpeg_std_error (&jsrcerr);
  jpeg_create_decompress (&srcinfo);
  srcinfo.src = (struct jpeg_source_mgr *) &m;
  m.pub.init_source = m.pub.term_source = dummy;
  m.pub.fill_input_buffer = fill_input_buffer;
  m.pub.skip_input_data = skip_input_data;
  m.pub.resync_to_restart = jpeg_resync_to_restart;
  m.get_byte = get_byte;
  m.count = m.pub.bytes_in_buffer = 0;
  m.pub.next_input_byte = NULL;
  jpeg_read_header (&srcinfo, TRUE);
  jpeg_read_coefficients (&srcinfo);
  jpeg_finish_decompress (&srcinfo);
  jpeg_destroy_decompress (&srcinfo);
  return m.count;
}
