/***************************************************************************
 *                                  _   _ ____  _
 *  Project                     ___| | | |  _ \| |
 *                             / __| | | | |_) | |
 *                            | (__| |_| |  _ <| |___
 *                             \___|\___/|_| \_\_____|
 *
 * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
 *
 * This software is licensed as described in the file COPYING, which
 * you should have received as part of this distribution. The terms
 * are also available at https://curl.haxx.se/docs/copyright.html.
 *
 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
 * copies of the Software, and permit persons to whom the Software is
 * furnished to do so, under the terms of the COPYING file.
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 ***************************************************************************/
#include "tool_setup.h"

#ifdef CURL_DOES_CONVERSIONS

#ifdef HAVE_ICONV
#  include <iconv.h>
#endif

#include "tool_convert.h"

#include "memdebug.h" /* keep this as LAST include */

#ifdef HAVE_ICONV

/* curl tool iconv conversion descriptors */
static iconv_t inbound_cd  = (iconv_t)-1;
static iconv_t outbound_cd = (iconv_t)-1;

/* set default codesets for iconv */
#ifndef CURL_ICONV_CODESET_OF_NETWORK
#  define CURL_ICONV_CODESET_OF_NETWORK "ISO8859-1"
#endif

/*
 * convert_to_network() is a curl tool function to convert
 * from the host encoding to ASCII on non-ASCII platforms.
 */
CURLcode convert_to_network(char *buffer, size_t length)
{
  /* translate from the host encoding to the network encoding */
  char *input_ptr, *output_ptr;
  size_t res, in_bytes, out_bytes;

  /* open an iconv conversion descriptor if necessary */
  if(outbound_cd == (iconv_t)-1) {
    outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK,
                             CURL_ICONV_CODESET_OF_HOST);
    if(outbound_cd == (iconv_t)-1) {
      return CURLE_CONV_FAILED;
    }
  }
  /* call iconv */
  input_ptr = output_ptr = buffer;
  in_bytes = out_bytes = length;
  res = iconv(outbound_cd, &input_ptr,  &in_bytes,
              &output_ptr, &out_bytes);
  if((res == (size_t)-1) || (in_bytes != 0)) {
    return CURLE_CONV_FAILED;
  }

  return CURLE_OK;
}

/*
 * convert_from_network() is a curl tool function
 * for performing ASCII conversions on non-ASCII platforms.
 */
CURLcode convert_from_network(char *buffer, size_t length)
{
  /* translate from the network encoding to the host encoding */
  char *input_ptr, *output_ptr;
  size_t res, in_bytes, out_bytes;

  /* open an iconv conversion descriptor if necessary */
  if(inbound_cd == (iconv_t)-1) {
    inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
                            CURL_ICONV_CODESET_OF_NETWORK);
    if(inbound_cd == (iconv_t)-1) {
      return CURLE_CONV_FAILED;
    }
  }
  /* call iconv */
  input_ptr = output_ptr = buffer;
  in_bytes = out_bytes = length;
  res = iconv(inbound_cd, &input_ptr,  &in_bytes,
              &output_ptr, &out_bytes);
  if((res == (size_t)-1) || (in_bytes != 0)) {
    return CURLE_CONV_FAILED;
  }

  return CURLE_OK;
}

void convert_cleanup(void)
{
  /* close iconv conversion descriptors */
  if(inbound_cd != (iconv_t)-1)
    (void)iconv_close(inbound_cd);
  if(outbound_cd != (iconv_t)-1)
    (void)iconv_close(outbound_cd);
}

#endif /* HAVE_ICONV */

char convert_char(curl_infotype infotype, char this_char)
{
/* determine how this specific character should be displayed */
  switch(infotype) {
  case CURLINFO_DATA_IN:
  case CURLINFO_DATA_OUT:
  case CURLINFO_SSL_DATA_IN:
  case CURLINFO_SSL_DATA_OUT:
    /* data, treat as ASCII */
    if(this_char < 0x20 || this_char >= 0x7f) {
      /* non-printable ASCII, use a replacement character */
      return UNPRINTABLE_CHAR;
    }
    /* printable ASCII hex value: convert to host encoding */
    (void)convert_from_network(&this_char, 1);
    /* FALLTHROUGH */
  default:
    /* treat as host encoding */
    if(ISPRINT(this_char)
       &&  (this_char != '\t')
       &&  (this_char != '\r')
       &&  (this_char != '\n')) {
      /* printable characters excluding tabs and line end characters */
      return this_char;
    }
    break;
  }
  /* non-printable, use a replacement character  */
  return UNPRINTABLE_CHAR;
}

#endif /* CURL_DOES_CONVERSIONS */
