text: /*
   * Copyright 2003-2019 The OpenSSL Project Authors. All Rights Reserved.
   *
   * Licensed under the OpenSSL license (the "License").  You may not use
   * this file except in compliance with the License.  You can obtain a copy
   * in the file LICENSE in the source distribution or at
   * https://www.openssl.org/source/license.html
   */
  
  #include "internal/o_str.h"
  
  #include <limits.h>
  #include <openssl/crypto.h>
  
  #include "e_os.h"
  #include "internal/cryptlib.h"
  
  int OPENSSL_memcmp(const void* v1, const void* v2, size_t n)
  {
      const unsigned char *c1 = v1, *c2 = v2;
      int ret = 0;
  
      while (n && (ret = *c1 - *c2) == 0)
          n--, c1++, c2++;
  
      return ret;
  }
  
  char* CRYPTO_strdup(const char* str, const char* file, int line)
  {
      char* ret;
  
      if (str == NULL)
          return NULL;
      ret = CRYPTO_malloc(strlen(str) + 1, file, line);
      if (ret != NULL)
          strcpy(ret, str);
      return ret;
  }
  
  char* CRYPTO_strndup(const char* str, size_t s, const char* file, int line)
  {
      size_t maxlen;
      char* ret;
  
      if (str == NULL)
          return NULL;
  
      maxlen = OPENSSL_strnlen(str, s);
  
      ret = CRYPTO_malloc(maxlen + 1, file, line);
      if (ret)
      {
          memcpy(ret, str, maxlen);
          ret[maxlen] = '\0';
      }
      return ret;
  }
  
  void* CRYPTO_memdup(const void* data, size_t siz, const char* file, int line)
  {
      void* ret;
  
      if (data == NULL || siz >= INT_MAX)
          return NULL;
  
      ret = CRYPTO_malloc(siz, file, line);
      if (ret == NULL)
      {
          CRYPTOerr(CRYPTO_F_CRYPTO_MEMDUP, ERR_R_MALLOC_FAILURE);
          return NULL;
      }
      return memcpy(ret, data, siz);
  }
  
  size_t OPENSSL_strnlen(const char* str, size_t maxlen)
  {
      const char* p;
  
      for (p = str; maxlen-- != 0 && *p != '\0'; ++p)
          ;
  
      return p - str;
  }
  
  size_t OPENSSL_strlcpy(char* dst, const char* src, size_t size)
  {
      size_t l = 0;
      for (; size > 1 && *src; size--)
      {
          *dst++ = *src++;
          l++;
      }
      if (size)
          *dst = '\0';
      return l + strlen(src);
  }
  
  size_t OPENSSL_strlcat(char* dst, const char* src, size_t size)
  {
      size_t l = 0;
      for (; size > 0 && *dst; size--, dst++)
          l++;
      return l + OPENSSL_strlcpy(dst, src, size);
  }
  
  int OPENSSL_hexchar2int(unsigned char c)
  {
  #ifdef CHARSET_EBCDIC
      c = os_toebcdic[c];
  #endif
  
      switch (c)
      {
          case '0':
              return 0;
          case '1':
              return 1;
          case '2':
              return 2;
          case '3':
              return 3;
          case '4':
              return 4;
          case '5':
              return 5;
          case '6':
              return 6;
          case '7':
              return 7;
          case '8':
              return 8;
          case '9':
              return 9;
          case 'a':
          case 'A':
              return 0x0A;
          case 'b':
          case 'B':
              return 0x0B;
          case 'c':
          case 'C':
              return 0x0C;
          case 'd':
          case 'D':
              return 0x0D;
          case 'e':
          case 'E':
              return 0x0E;
          case 'f':
          case 'F':
              return 0x0F;
      }
      return -1;
  }
  
  /*
   * Give a string of hex digits convert to a buffer
   */
  unsigned char* OPENSSL_hexstr2buf(const char* str, long* len)
  {
      unsigned char *hexbuf, *q;
      unsigned char ch, cl;
      int chi, cli;
      const unsigned char* p;
      size_t s;
  
      s = strlen(str);
      if ((hexbuf = OPENSSL_malloc(s >> 1)) == NULL)
      {
          CRYPTOerr(CRYPTO_F_OPENSSL_HEXSTR2BUF, ERR_R_MALLOC_FAILURE);
          return NULL;
      }
      for (p = (const unsigned char*)str, q = hexbuf; *p;)
      {
          ch = *p++;
          if (ch == ':')
              continue;
          cl = *p++;
          if (!cl)
          {
              CRYPTOerr(CRYPTO_F_OPENSSL_HEXSTR2BUF,
                        CRYPTO_R_ODD_NUMBER_OF_DIGITS);
              OPENSSL_free(hexbuf);
              return NULL;
          }
          cli = OPENSSL_hexchar2int(cl);
          chi = OPENSSL_hexchar2int(ch);
          if (cli < 0 || chi < 0)
          {
              OPENSSL_free(hexbuf);
              CRYPTOerr(CRYPTO_F_OPENSSL_HEXSTR2BUF, CRYPTO_R_ILLEGAL_HEX_DIGIT);
              return NULL;
          }
          *q++ = (unsigned char)((chi << 4) | cli);
      }
  
      if (len)
          *len = q - hexbuf;
      return hexbuf;
  }
  
  /*
   * Given a buffer of length 'len' return a OPENSSL_malloc'ed string with its
   * hex representation @@@ (Contents of buffer are always kept in ASCII, also
   * on EBCDIC machines)
   */
  char* OPENSSL_buf2hexstr(const unsigned char* buffer, long len)
  {
      static const char hexdig[] = "0123456789ABCDEF";
      char *tmp, *q;
      const unsigned char* p;
      int i;
  
      if (len == 0)
      {
          return OPENSSL_zalloc(1);
      }
  
      if ((tmp = OPENSSL_malloc(len * 3)) == NULL)
      {
          CRYPTOerr(CRYPTO_F_OPENSSL_BUF2HEXSTR, ERR_R_MALLOC_FAILURE);
          return NULL;
      }
      q = tmp;
      for (i = 0, p = buffer; i < len; i++, p++)
      {
          *q++ = hexdig[(*p >> 4) & 0xf];
          *q++ = hexdig[*p & 0xf];
          *q++ = ':';
      }
      q[-1] = 0;
  #ifdef CHARSET_EBCDIC
      ebcdic2ascii(tmp, tmp, q - tmp - 1);
  #endif
  
      return tmp;
  }
  
  int openssl_strerror_r(int errnum, char* buf, size_t buflen)
  {
  #if defined(_MSC_VER) && _MSC_VER >= 1400
      return !strerror_s(buf, buflen, errnum);
  #elif defined(_GNU_SOURCE)
      char* err;
  
      /*
       * GNU strerror_r may not actually set buf.
       * It can return a pointer to some (immutable) static string in which case
       * buf is left unused.
       */
      err = strerror_r(errnum, buf, buflen);
      if (err == NULL)
          return 0;
      /*
       * If err is statically allocated, err != buf and we need to copy the data.
       * If err points somewhere inside buf, OPENSSL_strlcpy can handle this,
       * since src and dest are not annotated with __restrict and the function
       * reads src byte for byte and writes to dest.
       * If err == buf we do not have to copy anything.
       */
      if (err != buf)
          OPENSSL_strlcpy(buf, err, buflen);
      return 1;
  #elif (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) ||              \
      (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 600)
      /*
       * We can use "real" strerror_r. The OpenSSL version differs in that it
       * gives 1 on success and 0 on failure for consistency with other OpenSSL
       * functions. Real strerror_r does it the other way around
       */
      return !strerror_r(errnum, buf, buflen);
  #else
      char* err;
  
      /* Fall back to non-thread safe strerror()...its all we can do */
      if (buflen < 2)
          return 0;
      err = strerror(errnum);
      /* Can this ever happen? */
      if (err == NULL)
          return 0;
      OPENSSL_strlcpy(buf, err, buflen);
      return 1;
  #endif
  }
  