/*
** our include(s)
*/

#include "jsupport.h"
#include "jversion.h"

/*
** definitions
*/

#define INPUT_BUF_SIZE 8192

/*
** jpeg error message table
*/

#define JMESSAGE(code,string) string ,

static const char * const jpeg_std_message_table[] = {
  #include "jerror.h"
  NULL
};

/*
** jpeg error message interface
*/

METHODDEF(void)
error_exit(j_common_ptr cinfo)
{
  /* cinfo->err really points to a dt_error_mgr struct, so coerce pointer */
  dt_error_mgr *jerr = (dt_error_mgr *) cinfo->err;

  /* ignore JMSG_NOMESSAGE */
  if (jerr->pub.msg_code != JMSG_NOMESSAGE) {

    /* convert error number */
    if (jerr->pub.msg_code != JERR_OUT_OF_MEMORY)
      jerr->error = !jerr->ignore ? DTERROR_INVALID_DATA : 0;

    /* Always display the message. */
    /* We could postpone this until after returning, if we chose. */
    (*jerr->pub.output_message) (cinfo);
  }

  /* Return control to the setjmp point */
  longjmp(jerr->jmpbuf,1);
}

METHODDEF(void)
emit_message(j_common_ptr cinfo,int msg_level)
{ struct jpeg_error_mgr * err = cinfo->err;

  if (msg_level < 0) {
    /* It's a warning message.  Since corrupt files may generate many warnings,
     * the policy implemented here is to show only the first warning,
     * unless trace_level >= 3.
     */
    if (err->num_warnings == 0 || err->trace_level >= 3)
      (*err->output_message) (cinfo);
    /* Always count warnings in num_warnings. */
    err->num_warnings++;
  }
#ifndef JFIF_DT
  else {
    /* It's a trace message.  Show it if trace_level >= msg_level. */
    if (err->trace_level >= msg_level)
      (*err->output_message) (cinfo);
  }
#endif
}

METHODDEF(void)
output_message(j_common_ptr cinfo)
{ struct jpeg_error_mgr *err;
  struct ClassBase *cb;
  dt_client_mgr *mgr;
  const char *msg;
  void *args,*win;
  char ch;
  int code;

  if ((mgr=(dt_client_mgr *)cinfo->client_data)->verbose) {

    if (cb=mgr->cb,(win=((struct Process *)FindTask(NULL))->pr_WindowPtr) != (APTR)-1) {

      struct EasyStruct *es = &mgr->es;

      es->es_StructSize   = 5 * sizeof(ULONG);
      es->es_Flags        = 0;
      es->es_Title        = "JFIF Information";
      if ((code=(err=cinfo->err)->msg_code) < 0 || code > err->last_jpeg_message)
        { err->msg_parm.i[0] = code; code = JMSG_NOMESSAGE; }
      es->es_TextFormat   = (UBYTE *)(msg = err->jpeg_message_table[code]);
      es->es_GadgetFormat = (UBYTE *)"OK";

      do;while((ch=*msg++) && (ch != '%'));
      if (args=&err->msg_parm.i[0],ch && *msg == 's')
        { mgr->args = &err->msg_parm.s; args = &mgr->args; }

      EasyRequestArgs(win,es,NULL,args);
    }
  }
}

METHODDEF(void)
format_message(j_common_ptr cinfo,char *buffer)
{
  /* no work */
}

METHODDEF(void)
reset_error_mgr(j_common_ptr cinfo)
{
  cinfo->err->num_warnings = 0;
  cinfo->err->msg_code = 0;
}

GLOBAL(struct jpeg_error_mgr *)
jpeg_std_error (struct jpeg_error_mgr *err)
{
  err->error_exit = error_exit;
  err->emit_message = emit_message;
  err->output_message = output_message;
  err->format_message = format_message;
  err->reset_error_mgr = reset_error_mgr;

  err->msg_code = 0;		/* may be useful as a flag for "no error" */
  err->trace_level = 0;		/* default = no tracing */
  err->num_warnings = 0;	/* no warnings emitted yet */

  /* Initialize message table pointers */
  err->jpeg_message_table = jpeg_std_message_table;
  err->last_jpeg_message = (int) JMSG_LASTMSGCODE - 1;

#ifndef JFIF_DT

  err->addon_message_table = NULL;
  err->first_addon_message = 0;	/* for safety */
  err->last_addon_message = 0;

#endif

  return err;
}

/*
** jpeg memory managment interface
*/

GLOBAL(void *)
jpeg_get_large(j_common_ptr cinfo,size_t sizeofobject)
{ dt_client_mgr * mgr = (dt_client_mgr *) cinfo->client_data;
  struct ClassBase *cb = mgr->cb;

  return AllocPooled(mgr->pool,sizeofobject);
}

GLOBAL(void)
jpeg_free_large(j_common_ptr cinfo,void *object,size_t sizeofobject)
{ dt_client_mgr * mgr = (dt_client_mgr *) cinfo->client_data;
  struct ClassBase *cb = mgr->cb;

  if (object) FreePooled(mgr->pool,object,sizeofobject);
}

GLOBAL(long)
jpeg_mem_available(j_common_ptr cinfo,long min_bytes_needed,long max_bytes_needed,long already_allocated)
{
  return max_bytes_needed;
}

GLOBAL(void)
jpeg_open_backing_store(j_common_ptr cinfo,backing_store_ptr info,long total_bytes_needed)
{
  ERREXIT(cinfo,JERR_NO_BACKING_STORE);
}

GLOBAL(long)
jpeg_mem_init(j_common_ptr cinfo)
{
  return 0; /* just set max_memory_to_use to 0 */
}

GLOBAL(void)
jpeg_mem_term(j_common_ptr cinfo)
{
  /* no work */
}

/*
** jpeg decompression input interface
*/

METHODDEF(void)
init_source(j_decompress_ptr cinfo)
{ //dt_src_mgr *src = (dt_src_mgr *) cinfo->src;

  //src->start_of_file = TRUE;
}

METHODDEF(boolean)
fill_input_buffer(j_decompress_ptr cinfo)
{ dt_src_mgr *src = (dt_src_mgr *) cinfo->src;
  JOCTET *buffer = src->buffer;
  size_t nbytes;
#if 0
  struct ClassBase *cb = ((dt_client_mgr *)cinfo->client_data)->cb;
  if (SetSignal(0,SIGBREAKF_CTRL_E)&SIGBREAKF_CTRL_E) {
    ((dt_error_mgr *)cinfo->err)->error = ERROR_BREAK; ERREXIT(cinfo,JMSG_NOMESSAGE);
  }
#endif
  if ((long)(nbytes=FFRRead(src->infile,buffer,INPUT_BUF_SIZE)) <= 0) {
  //if (src->start_of_file)
  //  ERREXIT(cinfo, JERR_INPUT_EMPTY);
    WARNMS(cinfo, JWRN_JPEG_EOF);
    /* Insert a fake EOI marker */
    buffer[0] = (JOCTET) 0xFF; buffer[1] = (JOCTET) JPEG_EOI; nbytes = 2;
  }

  src->pub.next_input_byte = buffer;
  src->pub.bytes_in_buffer = nbytes;
//src->start_of_file = FALSE;

  return TRUE;
}

METHODDEF(void)
skip_input_data(j_decompress_ptr cinfo,long num_bytes)
{ dt_src_mgr *src = (dt_src_mgr *) cinfo->src;

  if (num_bytes > 0) {
    while (num_bytes > (long) src->pub.bytes_in_buffer) {
      num_bytes -= (long) src->pub.bytes_in_buffer; fill_input_buffer(cinfo);
    }
    src->pub.next_input_byte += (size_t) num_bytes;
    src->pub.bytes_in_buffer -= (size_t) num_bytes;
  }
}

METHODDEF(void)
term_source(j_decompress_ptr cinfo)
{
  /* no work */
}

GLOBAL(void)
jpeg_load_src(j_decompress_ptr cinfo,void *infile)
{ dt_src_mgr *src = (dt_src_mgr *) cinfo->src;

  if (!src) {
    src = (dt_src_mgr *)
      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof(*src));
    src->buffer = (JOCTET *)
      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, INPUT_BUF_SIZE*sizeof(JOCTET));
    cinfo->src = &src->pub;
  }

  src->pub.next_input_byte = NULL;
  src->pub.bytes_in_buffer = 0;
  src->pub.init_source = init_source;
  src->pub.fill_input_buffer = fill_input_buffer;
  src->pub.skip_input_data = skip_input_data;
  src->pub.resync_to_restart = jpeg_resync_to_restart;
  src->pub.term_source = term_source;
  src->infile = infile;
}

#ifdef NEED_BSD_STRINGS

/*
** utility functions ...
*/

GLOBAL(void)
bcopy(const void *s1,void *s2,size_t n)
{ if (n)
  { size_t m;
    if((size_t)s1&1)
    { *((char *)s2)++=*((char *)s1)++;
      n--; }
    if(!((size_t)s2&1))
    { for(m=n/(4*sizeof(n));m;m--)
      { *((size_t *)s2)++=*((size_t *)s1)++; *((size_t *)s2)++=*((size_t *)s1)++;
        *((size_t *)s2)++=*((size_t *)s1)++; *((size_t *)s2)++=*((size_t *)s1)++; }
      n&=4*sizeof(n)-1; }
    if((m=n))
    do;while(*((char *)s2)++=*((char *)s1)++,--m); }
}

GLOBAL(void)
bzero(void *b,size_t n)
{ if (n)
  { size_t m;
    if((size_t)b&1)
    { *((char *)b)++=0;
      n--; }
    if(m=(4*sizeof(n)-1)&n,n/=4*sizeof(n))
      do{
        *((size_t *)b)++=0; *((size_t *)b)++=0;
        *((size_t *)b)++=0; *((size_t *)b)++=0;
      }while(--n);
    if((n=m))
      do;while(*((char *)b)++=0,--n); }
}

#endif
