/* -*- C++ -*-
 * Copyright 2019-2025 LibRaw LLC (info@libraw.org)
 *
 LibRaw uses code from dcraw.c -- Dave Coffin's raw photo decoder,
 dcraw.c is copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net.
 LibRaw do not use RESTRICTED code from dcraw.c

 LibRaw is free software; you can redistribute it and/or modify
 it under the terms of the one of two licenses as you choose:

1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1
   (See file LICENSE.LGPL provided in LibRaw distribution archive for details).

2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
   (See file LICENSE.CDDL provided in LibRaw distribution archive for details).

 */

#include "third_party/libraw/internal/dcraw_defs.h"

ushort LibRaw::sget2Rev(uchar *s) // specific to some Canon Makernotes fields,
                                  // where they have endian in reverse
{
  if (order == 0x4d4d) /* "II" means little-endian, and we reverse to "MM" - big
                          endian */
    return s[0] | s[1] << 8;
  else /* "MM" means big-endian... */
    return s[0] << 8 | s[1];
}

ushort libraw_sget2_static(short _order, uchar *s)
{
    if (_order == 0x4949) /* "II" means little-endian */
        return s[0] | s[1] << 8;
    else /* "MM" means big-endian */
        return s[0] << 8 | s[1];
}

ushort LibRaw::sget2(uchar *s)
{
    return libraw_sget2_static(order, s);
}


ushort LibRaw::get2()
{
  uchar str[2] = {0xff, 0xff};
  fread(str, 1, 2, ifp);
  return sget2(str);
}

unsigned LibRaw::sget4(uchar *s)
{
    return libraw_sget4_static(order, s);
}


unsigned libraw_sget4_static(short _order, uchar *s)
{
  if (_order == 0x4949)
    return s[0] | s[1] << 8 | s[2] << 16 | s[3] << 24;
  else
    return s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3];
}

unsigned LibRaw::get4()
{
  uchar str[4] = {0xff, 0xff, 0xff, 0xff};
  fread(str, 1, 4, ifp);
  return sget4(str);
}

unsigned LibRaw::getint(int type) { return tagtypeIs(LIBRAW_EXIFTAG_TYPE_SHORT) ? get2() : get4(); }

float libraw_int_to_float(int i)
{
  union {
    int i;
    float f;
  } u;
  u.i = i;
  return u.f;
}

float LibRaw::int_to_float(int i) { return libraw_int_to_float(i); }

double LibRaw::getreal(int type)
{
  union {
    char c[8];
    double d;
  } u, v;
  int i, rev;

  switch (type)
  {
  case LIBRAW_EXIFTAG_TYPE_SHORT:
    return (unsigned short)get2();
  case LIBRAW_EXIFTAG_TYPE_LONG:
    return (unsigned int)get4();
  case LIBRAW_EXIFTAG_TYPE_RATIONAL: // (unsigned, unsigned)
    u.d = (unsigned int)get4();
    v.d = (unsigned int)get4();
    return u.d / (v.d ? v.d : 1);
  case LIBRAW_EXIFTAG_TYPE_SSHORT:
    return (signed short)get2();
  case LIBRAW_EXIFTAG_TYPE_SLONG:
    return (signed int)get4();
  case LIBRAW_EXIFTAG_TYPE_SRATIONAL: // (int, int)
    u.d = (signed int)get4();
    v.d = (signed int)get4();
    return u.d / (v.d ? v.d : 1);
  case LIBRAW_EXIFTAG_TYPE_FLOAT:
    return int_to_float(get4());
  case LIBRAW_EXIFTAG_TYPE_DOUBLE:
    rev = 7 * ((order == 0x4949) == (ntohs(0x1234) == 0x1234));
    for (i = 0; i < 8; i++)
      u.c[i ^ rev] = fgetc(ifp);
    return u.d;
  default:
    return fgetc(ifp);
  }
}

double LibRaw::sgetreal(int type, uchar *s)
{
    return libraw_sgetreal_static(order, type, s);
}


double libraw_sgetreal_static(short _order, int type, uchar *s)
{
  union {
    char c[8];
    double d;
  } u, v;
  int i, rev;

  switch (type)
  {
  case LIBRAW_EXIFTAG_TYPE_SHORT:
    return (unsigned short) libraw_sget2_static(_order,s);
  case LIBRAW_EXIFTAG_TYPE_LONG:
      return (unsigned int)libraw_sget4_static(_order, s);
  case LIBRAW_EXIFTAG_TYPE_RATIONAL: // (unsigned, unsigned)
    u.d = (unsigned int)libraw_sget4_static(_order,s);
    v.d = (unsigned int)libraw_sget4_static(_order,s+4);
    return u.d / (v.d ? v.d : 1);
  case LIBRAW_EXIFTAG_TYPE_SSHORT:
    return (signed short)libraw_sget2_static(_order,s);
  case LIBRAW_EXIFTAG_TYPE_SLONG:
    return (signed int) libraw_sget4_static(_order,s);
  case LIBRAW_EXIFTAG_TYPE_SRATIONAL: // (int, int)
    u.d = (signed int)libraw_sget4_static(_order,s);
    v.d = (signed int)libraw_sget4_static(_order,s+4);
    return u.d / (v.d ? v.d : 1);
  case LIBRAW_EXIFTAG_TYPE_FLOAT:
    return libraw_int_to_float(libraw_sget4_static(_order,s));
  case LIBRAW_EXIFTAG_TYPE_DOUBLE:
    rev = 7 * ((_order == 0x4949) == (ntohs(0x1234) == 0x1234));
    for (i = 0; i < 8; i++)
      u.c[i ^ rev] = *(s+1);
    return u.d;
  default:
    return *(s+1);
  }
}


void LibRaw::read_shorts(ushort *pixel, unsigned count)
{
  if ((unsigned)fread(pixel, 2, count, ifp) < count)
    derror();
  if ((order == 0x4949) == (ntohs(0x1234) == 0x1234))
    libraw_swab(pixel, count * 2);
}
