/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */

#include "tomcrypt_private.h"

#ifdef LTC_PKCS_12

int pkcs12_utf8_to_utf16(const unsigned char *in,  unsigned long  inlen,
                               unsigned char *out, unsigned long *outlen) {
   unsigned long len = 0;
   const unsigned char* in_end = in + inlen;
   const ulong32 offset[6] = {
      0x00000000UL, 0x00003080UL, 0x000E2080UL,
      0x03C82080UL, 0xFA082080UL, 0x82082080UL
   };
   int err = CRYPT_ERROR;

   LTC_ARGCHK(in     != NULL);
   LTC_ARGCHK(out    != NULL);
   LTC_ARGCHK(outlen != NULL);

   while (in < in_end) {
      ulong32 ch = 0;
      unsigned short extra = 0; /* 0 */
      if (*in >= 192) extra++;  /* 1 */
      if (*in >= 224) extra++;  /* 2 */
      if (*in >= 240) extra++;  /* 3 */
      if (*in >= 248) extra++;  /* 4 */
      if (*in >= 252) extra++;  /* 5 */
      if (in + extra >= in_end) goto ERROR;
      switch (extra) {
         case 5: ch += *in++; ch <<= 6;
         /* FALLTHROUGH */
         case 4: ch += *in++; ch <<= 6;
         /* FALLTHROUGH */
         case 3: ch += *in++; ch <<= 6;
         /* FALLTHROUGH */
         case 2: ch += *in++; ch <<= 6;
         /* FALLTHROUGH */
         case 1: ch += *in++; ch <<= 6;
         /* FALLTHROUGH */
         case 0: ch += *in++;
      }
      ch -= offset[extra];
      if (ch > 0xFFFF) goto ERROR;
      if (*outlen >= len + 2) {
         out[len] = (unsigned short)((ch >> 8) & 0xFF);
         out[len + 1] = (unsigned char)(ch & 0xFF);
      }
      len += 2;
   }

   err = len > *outlen ? CRYPT_BUFFER_OVERFLOW : CRYPT_OK;
   *outlen = len;
ERROR:
   return err;
}

#endif
