11cb0ef41Sopenharmony_ci/* MIT License
21cb0ef41Sopenharmony_ci *
31cb0ef41Sopenharmony_ci * Copyright (c) 2023 Brad House
41cb0ef41Sopenharmony_ci *
51cb0ef41Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy
61cb0ef41Sopenharmony_ci * of this software and associated documentation files (the "Software"), to deal
71cb0ef41Sopenharmony_ci * in the Software without restriction, including without limitation the rights
81cb0ef41Sopenharmony_ci * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
91cb0ef41Sopenharmony_ci * copies of the Software, and to permit persons to whom the Software is
101cb0ef41Sopenharmony_ci * furnished to do so, subject to the following conditions:
111cb0ef41Sopenharmony_ci *
121cb0ef41Sopenharmony_ci * The above copyright notice and this permission notice (including the next
131cb0ef41Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
141cb0ef41Sopenharmony_ci * Software.
151cb0ef41Sopenharmony_ci *
161cb0ef41Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
171cb0ef41Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
181cb0ef41Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
191cb0ef41Sopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
201cb0ef41Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
211cb0ef41Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
221cb0ef41Sopenharmony_ci * SOFTWARE.
231cb0ef41Sopenharmony_ci *
241cb0ef41Sopenharmony_ci * SPDX-License-Identifier: MIT
251cb0ef41Sopenharmony_ci */
261cb0ef41Sopenharmony_ci#include "ares_setup.h"
271cb0ef41Sopenharmony_ci#include "ares.h"
281cb0ef41Sopenharmony_ci#include "ares_private.h"
291cb0ef41Sopenharmony_ci#include "ares__buf.h"
301cb0ef41Sopenharmony_ci#include <limits.h>
311cb0ef41Sopenharmony_ci#ifdef HAVE_STDINT_H
321cb0ef41Sopenharmony_ci#  include <stdint.h>
331cb0ef41Sopenharmony_ci#endif
341cb0ef41Sopenharmony_ci
351cb0ef41Sopenharmony_cistruct ares__buf {
361cb0ef41Sopenharmony_ci  const unsigned char *data;          /*!< pointer to start of data buffer */
371cb0ef41Sopenharmony_ci  size_t               data_len;      /*!< total size of data in buffer */
381cb0ef41Sopenharmony_ci
391cb0ef41Sopenharmony_ci  unsigned char       *alloc_buf;     /*!< Pointer to allocated data buffer,
401cb0ef41Sopenharmony_ci                                       *   not used for const buffers */
411cb0ef41Sopenharmony_ci  size_t               alloc_buf_len; /*!< Size of allocated data buffer */
421cb0ef41Sopenharmony_ci
431cb0ef41Sopenharmony_ci  size_t               offset;        /*!< Current working offset in buffer */
441cb0ef41Sopenharmony_ci  size_t               tag_offset;    /*!< Tagged offset in buffer. Uses
451cb0ef41Sopenharmony_ci                                       *   SIZE_MAX if not set. */
461cb0ef41Sopenharmony_ci};
471cb0ef41Sopenharmony_ci
481cb0ef41Sopenharmony_ciares_bool_t ares__isprint(int ch)
491cb0ef41Sopenharmony_ci{
501cb0ef41Sopenharmony_ci  if (ch >= 0x20 && ch <= 0x7E) {
511cb0ef41Sopenharmony_ci    return ARES_TRUE;
521cb0ef41Sopenharmony_ci  }
531cb0ef41Sopenharmony_ci  return ARES_FALSE;
541cb0ef41Sopenharmony_ci}
551cb0ef41Sopenharmony_ci
561cb0ef41Sopenharmony_ci/* Character set allowed by hostnames.  This is to include the normal
571cb0ef41Sopenharmony_ci * domain name character set plus:
581cb0ef41Sopenharmony_ci *  - underscores which are used in SRV records.
591cb0ef41Sopenharmony_ci *  - Forward slashes such as are used for classless in-addr.arpa
601cb0ef41Sopenharmony_ci *    delegation (CNAMEs)
611cb0ef41Sopenharmony_ci *  - Asterisks may be used for wildcard domains in CNAMEs as seen in the
621cb0ef41Sopenharmony_ci *    real world.
631cb0ef41Sopenharmony_ci * While RFC 2181 section 11 does state not to do validation,
641cb0ef41Sopenharmony_ci * that applies to servers, not clients.  Vulnerabilities have been
651cb0ef41Sopenharmony_ci * reported when this validation is not performed.  Security is more
661cb0ef41Sopenharmony_ci * important than edge-case compatibility (which is probably invalid
671cb0ef41Sopenharmony_ci * anyhow). */
681cb0ef41Sopenharmony_ciares_bool_t ares__is_hostnamech(int ch)
691cb0ef41Sopenharmony_ci{
701cb0ef41Sopenharmony_ci  /* [A-Za-z0-9-*._/]
711cb0ef41Sopenharmony_ci   * Don't use isalnum() as it is locale-specific
721cb0ef41Sopenharmony_ci   */
731cb0ef41Sopenharmony_ci  if (ch >= 'A' && ch <= 'Z') {
741cb0ef41Sopenharmony_ci    return ARES_TRUE;
751cb0ef41Sopenharmony_ci  }
761cb0ef41Sopenharmony_ci  if (ch >= 'a' && ch <= 'z') {
771cb0ef41Sopenharmony_ci    return ARES_TRUE;
781cb0ef41Sopenharmony_ci  }
791cb0ef41Sopenharmony_ci  if (ch >= '0' && ch <= '9') {
801cb0ef41Sopenharmony_ci    return ARES_TRUE;
811cb0ef41Sopenharmony_ci  }
821cb0ef41Sopenharmony_ci  if (ch == '-' || ch == '.' || ch == '_' || ch == '/' || ch == '*') {
831cb0ef41Sopenharmony_ci    return ARES_TRUE;
841cb0ef41Sopenharmony_ci  }
851cb0ef41Sopenharmony_ci
861cb0ef41Sopenharmony_ci  return ARES_FALSE;
871cb0ef41Sopenharmony_ci}
881cb0ef41Sopenharmony_ci
891cb0ef41Sopenharmony_ciares__buf_t *ares__buf_create(void)
901cb0ef41Sopenharmony_ci{
911cb0ef41Sopenharmony_ci  ares__buf_t *buf = ares_malloc_zero(sizeof(*buf));
921cb0ef41Sopenharmony_ci  if (buf == NULL) {
931cb0ef41Sopenharmony_ci    return NULL;
941cb0ef41Sopenharmony_ci  }
951cb0ef41Sopenharmony_ci
961cb0ef41Sopenharmony_ci  buf->tag_offset = SIZE_MAX;
971cb0ef41Sopenharmony_ci  return buf;
981cb0ef41Sopenharmony_ci}
991cb0ef41Sopenharmony_ci
1001cb0ef41Sopenharmony_ciares__buf_t *ares__buf_create_const(const unsigned char *data, size_t data_len)
1011cb0ef41Sopenharmony_ci{
1021cb0ef41Sopenharmony_ci  ares__buf_t *buf;
1031cb0ef41Sopenharmony_ci
1041cb0ef41Sopenharmony_ci  if (data == NULL || data_len == 0) {
1051cb0ef41Sopenharmony_ci    return NULL;
1061cb0ef41Sopenharmony_ci  }
1071cb0ef41Sopenharmony_ci
1081cb0ef41Sopenharmony_ci  buf = ares__buf_create();
1091cb0ef41Sopenharmony_ci  if (buf == NULL) {
1101cb0ef41Sopenharmony_ci    return NULL;
1111cb0ef41Sopenharmony_ci  }
1121cb0ef41Sopenharmony_ci
1131cb0ef41Sopenharmony_ci  buf->data     = data;
1141cb0ef41Sopenharmony_ci  buf->data_len = data_len;
1151cb0ef41Sopenharmony_ci
1161cb0ef41Sopenharmony_ci  return buf;
1171cb0ef41Sopenharmony_ci}
1181cb0ef41Sopenharmony_ci
1191cb0ef41Sopenharmony_civoid ares__buf_destroy(ares__buf_t *buf)
1201cb0ef41Sopenharmony_ci{
1211cb0ef41Sopenharmony_ci  if (buf == NULL) {
1221cb0ef41Sopenharmony_ci    return;
1231cb0ef41Sopenharmony_ci  }
1241cb0ef41Sopenharmony_ci  ares_free(buf->alloc_buf);
1251cb0ef41Sopenharmony_ci  ares_free(buf);
1261cb0ef41Sopenharmony_ci}
1271cb0ef41Sopenharmony_ci
1281cb0ef41Sopenharmony_cistatic ares_bool_t ares__buf_is_const(const ares__buf_t *buf)
1291cb0ef41Sopenharmony_ci{
1301cb0ef41Sopenharmony_ci  if (buf == NULL) {
1311cb0ef41Sopenharmony_ci    return ARES_FALSE;
1321cb0ef41Sopenharmony_ci  }
1331cb0ef41Sopenharmony_ci
1341cb0ef41Sopenharmony_ci  if (buf->data != NULL && buf->alloc_buf == NULL) {
1351cb0ef41Sopenharmony_ci    return ARES_TRUE;
1361cb0ef41Sopenharmony_ci  }
1371cb0ef41Sopenharmony_ci
1381cb0ef41Sopenharmony_ci  return ARES_FALSE;
1391cb0ef41Sopenharmony_ci}
1401cb0ef41Sopenharmony_ci
1411cb0ef41Sopenharmony_civoid ares__buf_reclaim(ares__buf_t *buf)
1421cb0ef41Sopenharmony_ci{
1431cb0ef41Sopenharmony_ci  size_t prefix_size;
1441cb0ef41Sopenharmony_ci  size_t data_size;
1451cb0ef41Sopenharmony_ci
1461cb0ef41Sopenharmony_ci  if (buf == NULL) {
1471cb0ef41Sopenharmony_ci    return;
1481cb0ef41Sopenharmony_ci  }
1491cb0ef41Sopenharmony_ci
1501cb0ef41Sopenharmony_ci  if (ares__buf_is_const(buf)) {
1511cb0ef41Sopenharmony_ci    return;
1521cb0ef41Sopenharmony_ci  }
1531cb0ef41Sopenharmony_ci
1541cb0ef41Sopenharmony_ci  /* Silence coverity.  All lengths are zero so would bail out later but
1551cb0ef41Sopenharmony_ci   * coverity doesn't know this */
1561cb0ef41Sopenharmony_ci  if (buf->alloc_buf == NULL) {
1571cb0ef41Sopenharmony_ci    return;
1581cb0ef41Sopenharmony_ci  }
1591cb0ef41Sopenharmony_ci
1601cb0ef41Sopenharmony_ci  if (buf->tag_offset != SIZE_MAX && buf->tag_offset < buf->offset) {
1611cb0ef41Sopenharmony_ci    prefix_size = buf->tag_offset;
1621cb0ef41Sopenharmony_ci  } else {
1631cb0ef41Sopenharmony_ci    prefix_size = buf->offset;
1641cb0ef41Sopenharmony_ci  }
1651cb0ef41Sopenharmony_ci
1661cb0ef41Sopenharmony_ci  if (prefix_size == 0) {
1671cb0ef41Sopenharmony_ci    return;
1681cb0ef41Sopenharmony_ci  }
1691cb0ef41Sopenharmony_ci
1701cb0ef41Sopenharmony_ci  data_size = buf->data_len - prefix_size;
1711cb0ef41Sopenharmony_ci
1721cb0ef41Sopenharmony_ci  memmove(buf->alloc_buf, buf->alloc_buf + prefix_size, data_size);
1731cb0ef41Sopenharmony_ci  buf->data      = buf->alloc_buf;
1741cb0ef41Sopenharmony_ci  buf->data_len  = data_size;
1751cb0ef41Sopenharmony_ci  buf->offset   -= prefix_size;
1761cb0ef41Sopenharmony_ci  if (buf->tag_offset != SIZE_MAX) {
1771cb0ef41Sopenharmony_ci    buf->tag_offset -= prefix_size;
1781cb0ef41Sopenharmony_ci  }
1791cb0ef41Sopenharmony_ci
1801cb0ef41Sopenharmony_ci  return;
1811cb0ef41Sopenharmony_ci}
1821cb0ef41Sopenharmony_ci
1831cb0ef41Sopenharmony_cistatic ares_status_t ares__buf_ensure_space(ares__buf_t *buf,
1841cb0ef41Sopenharmony_ci                                            size_t       needed_size)
1851cb0ef41Sopenharmony_ci{
1861cb0ef41Sopenharmony_ci  size_t         remaining_size;
1871cb0ef41Sopenharmony_ci  size_t         alloc_size;
1881cb0ef41Sopenharmony_ci  unsigned char *ptr;
1891cb0ef41Sopenharmony_ci
1901cb0ef41Sopenharmony_ci  if (buf == NULL) {
1911cb0ef41Sopenharmony_ci    return ARES_EFORMERR;
1921cb0ef41Sopenharmony_ci  }
1931cb0ef41Sopenharmony_ci
1941cb0ef41Sopenharmony_ci  if (ares__buf_is_const(buf)) {
1951cb0ef41Sopenharmony_ci    return ARES_EFORMERR;
1961cb0ef41Sopenharmony_ci  }
1971cb0ef41Sopenharmony_ci
1981cb0ef41Sopenharmony_ci  /* When calling ares__buf_finish_str() we end up adding a null terminator,
1991cb0ef41Sopenharmony_ci   * so we want to ensure the size is always sufficient for this as we don't
2001cb0ef41Sopenharmony_ci   * want an ARES_ENOMEM at that point */
2011cb0ef41Sopenharmony_ci  needed_size++;
2021cb0ef41Sopenharmony_ci
2031cb0ef41Sopenharmony_ci  /* No need to do an expensive move operation, we have enough to just append */
2041cb0ef41Sopenharmony_ci  remaining_size = buf->alloc_buf_len - buf->data_len;
2051cb0ef41Sopenharmony_ci  if (remaining_size >= needed_size) {
2061cb0ef41Sopenharmony_ci    return ARES_SUCCESS;
2071cb0ef41Sopenharmony_ci  }
2081cb0ef41Sopenharmony_ci
2091cb0ef41Sopenharmony_ci  /* See if just moving consumed data frees up enough space */
2101cb0ef41Sopenharmony_ci  ares__buf_reclaim(buf);
2111cb0ef41Sopenharmony_ci
2121cb0ef41Sopenharmony_ci  remaining_size = buf->alloc_buf_len - buf->data_len;
2131cb0ef41Sopenharmony_ci  if (remaining_size >= needed_size) {
2141cb0ef41Sopenharmony_ci    return ARES_SUCCESS;
2151cb0ef41Sopenharmony_ci  }
2161cb0ef41Sopenharmony_ci
2171cb0ef41Sopenharmony_ci  alloc_size = buf->alloc_buf_len;
2181cb0ef41Sopenharmony_ci
2191cb0ef41Sopenharmony_ci  /* Not yet started */
2201cb0ef41Sopenharmony_ci  if (alloc_size == 0) {
2211cb0ef41Sopenharmony_ci    alloc_size = 16; /* Always shifts 1, so ends up being 32 minimum */
2221cb0ef41Sopenharmony_ci  }
2231cb0ef41Sopenharmony_ci
2241cb0ef41Sopenharmony_ci  /* Increase allocation by powers of 2 */
2251cb0ef41Sopenharmony_ci  do {
2261cb0ef41Sopenharmony_ci    alloc_size     <<= 1;
2271cb0ef41Sopenharmony_ci    remaining_size   = alloc_size - buf->data_len;
2281cb0ef41Sopenharmony_ci  } while (remaining_size < needed_size);
2291cb0ef41Sopenharmony_ci
2301cb0ef41Sopenharmony_ci  ptr = ares_realloc(buf->alloc_buf, alloc_size);
2311cb0ef41Sopenharmony_ci  if (ptr == NULL) {
2321cb0ef41Sopenharmony_ci    return ARES_ENOMEM;
2331cb0ef41Sopenharmony_ci  }
2341cb0ef41Sopenharmony_ci
2351cb0ef41Sopenharmony_ci  buf->alloc_buf     = ptr;
2361cb0ef41Sopenharmony_ci  buf->alloc_buf_len = alloc_size;
2371cb0ef41Sopenharmony_ci  buf->data          = ptr;
2381cb0ef41Sopenharmony_ci
2391cb0ef41Sopenharmony_ci  return ARES_SUCCESS;
2401cb0ef41Sopenharmony_ci}
2411cb0ef41Sopenharmony_ci
2421cb0ef41Sopenharmony_ciares_status_t ares__buf_set_length(ares__buf_t *buf, size_t len)
2431cb0ef41Sopenharmony_ci{
2441cb0ef41Sopenharmony_ci  if (buf == NULL || ares__buf_is_const(buf)) {
2451cb0ef41Sopenharmony_ci    return ARES_EFORMERR;
2461cb0ef41Sopenharmony_ci  }
2471cb0ef41Sopenharmony_ci
2481cb0ef41Sopenharmony_ci  if (len >= buf->alloc_buf_len - buf->offset) {
2491cb0ef41Sopenharmony_ci    return ARES_EFORMERR;
2501cb0ef41Sopenharmony_ci  }
2511cb0ef41Sopenharmony_ci
2521cb0ef41Sopenharmony_ci  buf->data_len = len;
2531cb0ef41Sopenharmony_ci  return ARES_SUCCESS;
2541cb0ef41Sopenharmony_ci}
2551cb0ef41Sopenharmony_ci
2561cb0ef41Sopenharmony_ciares_status_t ares__buf_append(ares__buf_t *buf, const unsigned char *data,
2571cb0ef41Sopenharmony_ci                               size_t data_len)
2581cb0ef41Sopenharmony_ci{
2591cb0ef41Sopenharmony_ci  ares_status_t status;
2601cb0ef41Sopenharmony_ci
2611cb0ef41Sopenharmony_ci  if (data == NULL || data_len == 0) {
2621cb0ef41Sopenharmony_ci    return ARES_EFORMERR;
2631cb0ef41Sopenharmony_ci  }
2641cb0ef41Sopenharmony_ci
2651cb0ef41Sopenharmony_ci  status = ares__buf_ensure_space(buf, data_len);
2661cb0ef41Sopenharmony_ci  if (status != ARES_SUCCESS) {
2671cb0ef41Sopenharmony_ci    return status;
2681cb0ef41Sopenharmony_ci  }
2691cb0ef41Sopenharmony_ci
2701cb0ef41Sopenharmony_ci  memcpy(buf->alloc_buf + buf->data_len, data, data_len);
2711cb0ef41Sopenharmony_ci  buf->data_len += data_len;
2721cb0ef41Sopenharmony_ci  return ARES_SUCCESS;
2731cb0ef41Sopenharmony_ci}
2741cb0ef41Sopenharmony_ci
2751cb0ef41Sopenharmony_ciares_status_t ares__buf_append_byte(ares__buf_t *buf, unsigned char byte)
2761cb0ef41Sopenharmony_ci{
2771cb0ef41Sopenharmony_ci  return ares__buf_append(buf, &byte, 1);
2781cb0ef41Sopenharmony_ci}
2791cb0ef41Sopenharmony_ci
2801cb0ef41Sopenharmony_ciares_status_t ares__buf_append_be16(ares__buf_t *buf, unsigned short u16)
2811cb0ef41Sopenharmony_ci{
2821cb0ef41Sopenharmony_ci  ares_status_t status;
2831cb0ef41Sopenharmony_ci
2841cb0ef41Sopenharmony_ci  status = ares__buf_append_byte(buf, (unsigned char)((u16 >> 8) & 0xff));
2851cb0ef41Sopenharmony_ci  if (status != ARES_SUCCESS) {
2861cb0ef41Sopenharmony_ci    return status;
2871cb0ef41Sopenharmony_ci  }
2881cb0ef41Sopenharmony_ci
2891cb0ef41Sopenharmony_ci  status = ares__buf_append_byte(buf, (unsigned char)(u16 & 0xff));
2901cb0ef41Sopenharmony_ci  if (status != ARES_SUCCESS) {
2911cb0ef41Sopenharmony_ci    return status;
2921cb0ef41Sopenharmony_ci  }
2931cb0ef41Sopenharmony_ci
2941cb0ef41Sopenharmony_ci  return ARES_SUCCESS;
2951cb0ef41Sopenharmony_ci}
2961cb0ef41Sopenharmony_ci
2971cb0ef41Sopenharmony_ciares_status_t ares__buf_append_be32(ares__buf_t *buf, unsigned int u32)
2981cb0ef41Sopenharmony_ci{
2991cb0ef41Sopenharmony_ci  ares_status_t status;
3001cb0ef41Sopenharmony_ci
3011cb0ef41Sopenharmony_ci  status = ares__buf_append_byte(buf, ((unsigned char)(u32 >> 24) & 0xff));
3021cb0ef41Sopenharmony_ci  if (status != ARES_SUCCESS) {
3031cb0ef41Sopenharmony_ci    return status;
3041cb0ef41Sopenharmony_ci  }
3051cb0ef41Sopenharmony_ci
3061cb0ef41Sopenharmony_ci  status = ares__buf_append_byte(buf, ((unsigned char)(u32 >> 16) & 0xff));
3071cb0ef41Sopenharmony_ci  if (status != ARES_SUCCESS) {
3081cb0ef41Sopenharmony_ci    return status;
3091cb0ef41Sopenharmony_ci  }
3101cb0ef41Sopenharmony_ci
3111cb0ef41Sopenharmony_ci  status = ares__buf_append_byte(buf, ((unsigned char)(u32 >> 8) & 0xff));
3121cb0ef41Sopenharmony_ci  if (status != ARES_SUCCESS) {
3131cb0ef41Sopenharmony_ci    return status;
3141cb0ef41Sopenharmony_ci  }
3151cb0ef41Sopenharmony_ci
3161cb0ef41Sopenharmony_ci  status = ares__buf_append_byte(buf, ((unsigned char)u32 & 0xff));
3171cb0ef41Sopenharmony_ci  if (status != ARES_SUCCESS) {
3181cb0ef41Sopenharmony_ci    return status;
3191cb0ef41Sopenharmony_ci  }
3201cb0ef41Sopenharmony_ci
3211cb0ef41Sopenharmony_ci  return ARES_SUCCESS;
3221cb0ef41Sopenharmony_ci}
3231cb0ef41Sopenharmony_ci
3241cb0ef41Sopenharmony_ciunsigned char *ares__buf_append_start(ares__buf_t *buf, size_t *len)
3251cb0ef41Sopenharmony_ci{
3261cb0ef41Sopenharmony_ci  ares_status_t status;
3271cb0ef41Sopenharmony_ci
3281cb0ef41Sopenharmony_ci  if (len == NULL || *len == 0) {
3291cb0ef41Sopenharmony_ci    return NULL;
3301cb0ef41Sopenharmony_ci  }
3311cb0ef41Sopenharmony_ci
3321cb0ef41Sopenharmony_ci  status = ares__buf_ensure_space(buf, *len);
3331cb0ef41Sopenharmony_ci  if (status != ARES_SUCCESS) {
3341cb0ef41Sopenharmony_ci    return NULL;
3351cb0ef41Sopenharmony_ci  }
3361cb0ef41Sopenharmony_ci
3371cb0ef41Sopenharmony_ci  /* -1 for possible null terminator for ares__buf_finish_str() */
3381cb0ef41Sopenharmony_ci  *len = buf->alloc_buf_len - buf->data_len - 1;
3391cb0ef41Sopenharmony_ci  return buf->alloc_buf + buf->data_len;
3401cb0ef41Sopenharmony_ci}
3411cb0ef41Sopenharmony_ci
3421cb0ef41Sopenharmony_civoid ares__buf_append_finish(ares__buf_t *buf, size_t len)
3431cb0ef41Sopenharmony_ci{
3441cb0ef41Sopenharmony_ci  if (buf == NULL) {
3451cb0ef41Sopenharmony_ci    return;
3461cb0ef41Sopenharmony_ci  }
3471cb0ef41Sopenharmony_ci
3481cb0ef41Sopenharmony_ci  buf->data_len += len;
3491cb0ef41Sopenharmony_ci}
3501cb0ef41Sopenharmony_ci
3511cb0ef41Sopenharmony_ciunsigned char *ares__buf_finish_bin(ares__buf_t *buf, size_t *len)
3521cb0ef41Sopenharmony_ci{
3531cb0ef41Sopenharmony_ci  unsigned char *ptr = NULL;
3541cb0ef41Sopenharmony_ci  if (buf == NULL || len == NULL || ares__buf_is_const(buf)) {
3551cb0ef41Sopenharmony_ci    return NULL;
3561cb0ef41Sopenharmony_ci  }
3571cb0ef41Sopenharmony_ci
3581cb0ef41Sopenharmony_ci  ares__buf_reclaim(buf);
3591cb0ef41Sopenharmony_ci
3601cb0ef41Sopenharmony_ci  /* We don't want to return NULL except on failure, may be zero-length */
3611cb0ef41Sopenharmony_ci  if (buf->alloc_buf == NULL &&
3621cb0ef41Sopenharmony_ci      ares__buf_ensure_space(buf, 1) != ARES_SUCCESS) {
3631cb0ef41Sopenharmony_ci    return NULL;
3641cb0ef41Sopenharmony_ci  }
3651cb0ef41Sopenharmony_ci  ptr  = buf->alloc_buf;
3661cb0ef41Sopenharmony_ci  *len = buf->data_len;
3671cb0ef41Sopenharmony_ci  ares_free(buf);
3681cb0ef41Sopenharmony_ci  return ptr;
3691cb0ef41Sopenharmony_ci}
3701cb0ef41Sopenharmony_ci
3711cb0ef41Sopenharmony_cichar *ares__buf_finish_str(ares__buf_t *buf, size_t *len)
3721cb0ef41Sopenharmony_ci{
3731cb0ef41Sopenharmony_ci  char  *ptr;
3741cb0ef41Sopenharmony_ci  size_t mylen;
3751cb0ef41Sopenharmony_ci
3761cb0ef41Sopenharmony_ci  ptr = (char *)ares__buf_finish_bin(buf, &mylen);
3771cb0ef41Sopenharmony_ci  if (ptr == NULL) {
3781cb0ef41Sopenharmony_ci    return NULL;
3791cb0ef41Sopenharmony_ci  }
3801cb0ef41Sopenharmony_ci
3811cb0ef41Sopenharmony_ci  if (len != NULL) {
3821cb0ef41Sopenharmony_ci    *len = mylen;
3831cb0ef41Sopenharmony_ci  }
3841cb0ef41Sopenharmony_ci
3851cb0ef41Sopenharmony_ci  /* NOTE: ensured via ares__buf_ensure_space() that there is always at least
3861cb0ef41Sopenharmony_ci   *       1 extra byte available for this specific use-case */
3871cb0ef41Sopenharmony_ci  ptr[mylen] = 0;
3881cb0ef41Sopenharmony_ci
3891cb0ef41Sopenharmony_ci  return ptr;
3901cb0ef41Sopenharmony_ci}
3911cb0ef41Sopenharmony_ci
3921cb0ef41Sopenharmony_civoid ares__buf_tag(ares__buf_t *buf)
3931cb0ef41Sopenharmony_ci{
3941cb0ef41Sopenharmony_ci  if (buf == NULL) {
3951cb0ef41Sopenharmony_ci    return;
3961cb0ef41Sopenharmony_ci  }
3971cb0ef41Sopenharmony_ci
3981cb0ef41Sopenharmony_ci  buf->tag_offset = buf->offset;
3991cb0ef41Sopenharmony_ci}
4001cb0ef41Sopenharmony_ci
4011cb0ef41Sopenharmony_ciares_status_t ares__buf_tag_rollback(ares__buf_t *buf)
4021cb0ef41Sopenharmony_ci{
4031cb0ef41Sopenharmony_ci  if (buf == NULL || buf->tag_offset == SIZE_MAX) {
4041cb0ef41Sopenharmony_ci    return ARES_EFORMERR;
4051cb0ef41Sopenharmony_ci  }
4061cb0ef41Sopenharmony_ci
4071cb0ef41Sopenharmony_ci  buf->offset     = buf->tag_offset;
4081cb0ef41Sopenharmony_ci  buf->tag_offset = SIZE_MAX;
4091cb0ef41Sopenharmony_ci  return ARES_SUCCESS;
4101cb0ef41Sopenharmony_ci}
4111cb0ef41Sopenharmony_ci
4121cb0ef41Sopenharmony_ciares_status_t ares__buf_tag_clear(ares__buf_t *buf)
4131cb0ef41Sopenharmony_ci{
4141cb0ef41Sopenharmony_ci  if (buf == NULL || buf->tag_offset == SIZE_MAX) {
4151cb0ef41Sopenharmony_ci    return ARES_EFORMERR;
4161cb0ef41Sopenharmony_ci  }
4171cb0ef41Sopenharmony_ci
4181cb0ef41Sopenharmony_ci  buf->tag_offset = SIZE_MAX;
4191cb0ef41Sopenharmony_ci  return ARES_SUCCESS;
4201cb0ef41Sopenharmony_ci}
4211cb0ef41Sopenharmony_ci
4221cb0ef41Sopenharmony_ciconst unsigned char *ares__buf_tag_fetch(const ares__buf_t *buf, size_t *len)
4231cb0ef41Sopenharmony_ci{
4241cb0ef41Sopenharmony_ci  if (buf == NULL || buf->tag_offset == SIZE_MAX || len == NULL) {
4251cb0ef41Sopenharmony_ci    return NULL;
4261cb0ef41Sopenharmony_ci  }
4271cb0ef41Sopenharmony_ci
4281cb0ef41Sopenharmony_ci  *len = buf->offset - buf->tag_offset;
4291cb0ef41Sopenharmony_ci  return buf->data + buf->tag_offset;
4301cb0ef41Sopenharmony_ci}
4311cb0ef41Sopenharmony_ci
4321cb0ef41Sopenharmony_cisize_t ares__buf_tag_length(const ares__buf_t *buf)
4331cb0ef41Sopenharmony_ci{
4341cb0ef41Sopenharmony_ci  if (buf == NULL || buf->tag_offset == SIZE_MAX) {
4351cb0ef41Sopenharmony_ci    return 0;
4361cb0ef41Sopenharmony_ci  }
4371cb0ef41Sopenharmony_ci  return buf->offset - buf->tag_offset;
4381cb0ef41Sopenharmony_ci}
4391cb0ef41Sopenharmony_ci
4401cb0ef41Sopenharmony_ciares_status_t ares__buf_tag_fetch_bytes(const ares__buf_t *buf,
4411cb0ef41Sopenharmony_ci                                        unsigned char *bytes, size_t *len)
4421cb0ef41Sopenharmony_ci{
4431cb0ef41Sopenharmony_ci  size_t               ptr_len = 0;
4441cb0ef41Sopenharmony_ci  const unsigned char *ptr     = ares__buf_tag_fetch(buf, &ptr_len);
4451cb0ef41Sopenharmony_ci
4461cb0ef41Sopenharmony_ci  if (ptr == NULL || bytes == NULL || len == NULL) {
4471cb0ef41Sopenharmony_ci    return ARES_EFORMERR;
4481cb0ef41Sopenharmony_ci  }
4491cb0ef41Sopenharmony_ci
4501cb0ef41Sopenharmony_ci  if (*len < ptr_len) {
4511cb0ef41Sopenharmony_ci    return ARES_EFORMERR;
4521cb0ef41Sopenharmony_ci  }
4531cb0ef41Sopenharmony_ci
4541cb0ef41Sopenharmony_ci  *len = ptr_len;
4551cb0ef41Sopenharmony_ci
4561cb0ef41Sopenharmony_ci  if (ptr_len > 0) {
4571cb0ef41Sopenharmony_ci    memcpy(bytes, ptr, ptr_len);
4581cb0ef41Sopenharmony_ci  }
4591cb0ef41Sopenharmony_ci  return ARES_SUCCESS;
4601cb0ef41Sopenharmony_ci}
4611cb0ef41Sopenharmony_ci
4621cb0ef41Sopenharmony_ciares_status_t ares__buf_tag_fetch_string(const ares__buf_t *buf, char *str,
4631cb0ef41Sopenharmony_ci                                         size_t len)
4641cb0ef41Sopenharmony_ci{
4651cb0ef41Sopenharmony_ci  size_t        out_len;
4661cb0ef41Sopenharmony_ci  ares_status_t status;
4671cb0ef41Sopenharmony_ci  size_t        i;
4681cb0ef41Sopenharmony_ci
4691cb0ef41Sopenharmony_ci  if (str == NULL || len == 0) {
4701cb0ef41Sopenharmony_ci    return ARES_EFORMERR;
4711cb0ef41Sopenharmony_ci  }
4721cb0ef41Sopenharmony_ci
4731cb0ef41Sopenharmony_ci  /* Space for NULL terminator */
4741cb0ef41Sopenharmony_ci  out_len = len - 1;
4751cb0ef41Sopenharmony_ci
4761cb0ef41Sopenharmony_ci  status = ares__buf_tag_fetch_bytes(buf, (unsigned char *)str, &out_len);
4771cb0ef41Sopenharmony_ci  if (status != ARES_SUCCESS) {
4781cb0ef41Sopenharmony_ci    return status;
4791cb0ef41Sopenharmony_ci  }
4801cb0ef41Sopenharmony_ci
4811cb0ef41Sopenharmony_ci  /* NULL terminate */
4821cb0ef41Sopenharmony_ci  str[out_len] = 0;
4831cb0ef41Sopenharmony_ci
4841cb0ef41Sopenharmony_ci  /* Validate string is printable */
4851cb0ef41Sopenharmony_ci  for (i = 0; i < out_len; i++) {
4861cb0ef41Sopenharmony_ci    if (!ares__isprint(str[i])) {
4871cb0ef41Sopenharmony_ci      return ARES_EBADSTR;
4881cb0ef41Sopenharmony_ci    }
4891cb0ef41Sopenharmony_ci  }
4901cb0ef41Sopenharmony_ci
4911cb0ef41Sopenharmony_ci  return ARES_SUCCESS;
4921cb0ef41Sopenharmony_ci}
4931cb0ef41Sopenharmony_ci
4941cb0ef41Sopenharmony_cistatic const unsigned char *ares__buf_fetch(const ares__buf_t *buf, size_t *len)
4951cb0ef41Sopenharmony_ci{
4961cb0ef41Sopenharmony_ci  if (len != NULL) {
4971cb0ef41Sopenharmony_ci    *len = 0;
4981cb0ef41Sopenharmony_ci  }
4991cb0ef41Sopenharmony_ci
5001cb0ef41Sopenharmony_ci  if (buf == NULL || len == NULL || buf->data == NULL) {
5011cb0ef41Sopenharmony_ci    return NULL;
5021cb0ef41Sopenharmony_ci  }
5031cb0ef41Sopenharmony_ci
5041cb0ef41Sopenharmony_ci  *len = buf->data_len - buf->offset;
5051cb0ef41Sopenharmony_ci  if (*len == 0) {
5061cb0ef41Sopenharmony_ci    return NULL;
5071cb0ef41Sopenharmony_ci  }
5081cb0ef41Sopenharmony_ci
5091cb0ef41Sopenharmony_ci  return buf->data + buf->offset;
5101cb0ef41Sopenharmony_ci}
5111cb0ef41Sopenharmony_ci
5121cb0ef41Sopenharmony_ciares_status_t ares__buf_consume(ares__buf_t *buf, size_t len)
5131cb0ef41Sopenharmony_ci{
5141cb0ef41Sopenharmony_ci  size_t remaining_len = ares__buf_len(buf);
5151cb0ef41Sopenharmony_ci
5161cb0ef41Sopenharmony_ci  if (remaining_len < len) {
5171cb0ef41Sopenharmony_ci    return ARES_EBADRESP;
5181cb0ef41Sopenharmony_ci  }
5191cb0ef41Sopenharmony_ci
5201cb0ef41Sopenharmony_ci  buf->offset += len;
5211cb0ef41Sopenharmony_ci  return ARES_SUCCESS;
5221cb0ef41Sopenharmony_ci}
5231cb0ef41Sopenharmony_ci
5241cb0ef41Sopenharmony_ciares_status_t ares__buf_fetch_be16(ares__buf_t *buf, unsigned short *u16)
5251cb0ef41Sopenharmony_ci{
5261cb0ef41Sopenharmony_ci  size_t               remaining_len;
5271cb0ef41Sopenharmony_ci  const unsigned char *ptr = ares__buf_fetch(buf, &remaining_len);
5281cb0ef41Sopenharmony_ci  unsigned int         u32;
5291cb0ef41Sopenharmony_ci
5301cb0ef41Sopenharmony_ci  if (buf == NULL || u16 == NULL || remaining_len < sizeof(*u16)) {
5311cb0ef41Sopenharmony_ci    return ARES_EBADRESP;
5321cb0ef41Sopenharmony_ci  }
5331cb0ef41Sopenharmony_ci
5341cb0ef41Sopenharmony_ci  /* Do math in an unsigned int in order to prevent warnings due to automatic
5351cb0ef41Sopenharmony_ci   * conversion by the compiler from short to int during shifts */
5361cb0ef41Sopenharmony_ci  u32  = ((unsigned int)(ptr[0]) << 8 | (unsigned int)ptr[1]);
5371cb0ef41Sopenharmony_ci  *u16 = (unsigned short)(u32 & 0xFFFF);
5381cb0ef41Sopenharmony_ci
5391cb0ef41Sopenharmony_ci  return ares__buf_consume(buf, sizeof(*u16));
5401cb0ef41Sopenharmony_ci}
5411cb0ef41Sopenharmony_ci
5421cb0ef41Sopenharmony_ciares_status_t ares__buf_fetch_be32(ares__buf_t *buf, unsigned int *u32)
5431cb0ef41Sopenharmony_ci{
5441cb0ef41Sopenharmony_ci  size_t               remaining_len;
5451cb0ef41Sopenharmony_ci  const unsigned char *ptr = ares__buf_fetch(buf, &remaining_len);
5461cb0ef41Sopenharmony_ci
5471cb0ef41Sopenharmony_ci  if (buf == NULL || u32 == NULL || remaining_len < sizeof(*u32)) {
5481cb0ef41Sopenharmony_ci    return ARES_EBADRESP;
5491cb0ef41Sopenharmony_ci  }
5501cb0ef41Sopenharmony_ci
5511cb0ef41Sopenharmony_ci  *u32 = ((unsigned int)(ptr[0]) << 24 | (unsigned int)(ptr[1]) << 16 |
5521cb0ef41Sopenharmony_ci          (unsigned int)(ptr[2]) << 8 | (unsigned int)(ptr[3]));
5531cb0ef41Sopenharmony_ci
5541cb0ef41Sopenharmony_ci  return ares__buf_consume(buf, sizeof(*u32));
5551cb0ef41Sopenharmony_ci}
5561cb0ef41Sopenharmony_ci
5571cb0ef41Sopenharmony_ciares_status_t ares__buf_fetch_bytes(ares__buf_t *buf, unsigned char *bytes,
5581cb0ef41Sopenharmony_ci                                    size_t len)
5591cb0ef41Sopenharmony_ci{
5601cb0ef41Sopenharmony_ci  size_t               remaining_len;
5611cb0ef41Sopenharmony_ci  const unsigned char *ptr = ares__buf_fetch(buf, &remaining_len);
5621cb0ef41Sopenharmony_ci
5631cb0ef41Sopenharmony_ci  if (buf == NULL || bytes == NULL || len == 0 || remaining_len < len) {
5641cb0ef41Sopenharmony_ci    return ARES_EBADRESP;
5651cb0ef41Sopenharmony_ci  }
5661cb0ef41Sopenharmony_ci
5671cb0ef41Sopenharmony_ci  memcpy(bytes, ptr, len);
5681cb0ef41Sopenharmony_ci  return ares__buf_consume(buf, len);
5691cb0ef41Sopenharmony_ci}
5701cb0ef41Sopenharmony_ci
5711cb0ef41Sopenharmony_ciares_status_t ares__buf_fetch_bytes_dup(ares__buf_t *buf, size_t len,
5721cb0ef41Sopenharmony_ci                                        ares_bool_t     null_term,
5731cb0ef41Sopenharmony_ci                                        unsigned char **bytes)
5741cb0ef41Sopenharmony_ci{
5751cb0ef41Sopenharmony_ci  size_t               remaining_len;
5761cb0ef41Sopenharmony_ci  const unsigned char *ptr = ares__buf_fetch(buf, &remaining_len);
5771cb0ef41Sopenharmony_ci
5781cb0ef41Sopenharmony_ci  if (buf == NULL || bytes == NULL || len == 0 || remaining_len < len) {
5791cb0ef41Sopenharmony_ci    return ARES_EBADRESP;
5801cb0ef41Sopenharmony_ci  }
5811cb0ef41Sopenharmony_ci
5821cb0ef41Sopenharmony_ci  *bytes = ares_malloc(null_term ? len + 1 : len);
5831cb0ef41Sopenharmony_ci  if (*bytes == NULL) {
5841cb0ef41Sopenharmony_ci    return ARES_ENOMEM;
5851cb0ef41Sopenharmony_ci  }
5861cb0ef41Sopenharmony_ci
5871cb0ef41Sopenharmony_ci  memcpy(*bytes, ptr, len);
5881cb0ef41Sopenharmony_ci  if (null_term) {
5891cb0ef41Sopenharmony_ci    (*bytes)[len] = 0;
5901cb0ef41Sopenharmony_ci  }
5911cb0ef41Sopenharmony_ci  return ares__buf_consume(buf, len);
5921cb0ef41Sopenharmony_ci}
5931cb0ef41Sopenharmony_ci
5941cb0ef41Sopenharmony_ciares_status_t ares__buf_fetch_str_dup(ares__buf_t *buf, size_t len, char **str)
5951cb0ef41Sopenharmony_ci{
5961cb0ef41Sopenharmony_ci  size_t               remaining_len;
5971cb0ef41Sopenharmony_ci  const unsigned char *ptr = ares__buf_fetch(buf, &remaining_len);
5981cb0ef41Sopenharmony_ci
5991cb0ef41Sopenharmony_ci  if (buf == NULL || str == NULL || len == 0 || remaining_len < len) {
6001cb0ef41Sopenharmony_ci    return ARES_EBADRESP;
6011cb0ef41Sopenharmony_ci  }
6021cb0ef41Sopenharmony_ci
6031cb0ef41Sopenharmony_ci  *str = ares_malloc(len + 1);
6041cb0ef41Sopenharmony_ci  if (*str == NULL) {
6051cb0ef41Sopenharmony_ci    return ARES_ENOMEM;
6061cb0ef41Sopenharmony_ci  }
6071cb0ef41Sopenharmony_ci
6081cb0ef41Sopenharmony_ci  memcpy(*str, ptr, len);
6091cb0ef41Sopenharmony_ci  (*str)[len] = 0;
6101cb0ef41Sopenharmony_ci
6111cb0ef41Sopenharmony_ci  return ares__buf_consume(buf, len);
6121cb0ef41Sopenharmony_ci}
6131cb0ef41Sopenharmony_ci
6141cb0ef41Sopenharmony_ciares_status_t ares__buf_fetch_bytes_into_buf(ares__buf_t *buf,
6151cb0ef41Sopenharmony_ci                                             ares__buf_t *dest, size_t len)
6161cb0ef41Sopenharmony_ci{
6171cb0ef41Sopenharmony_ci  size_t               remaining_len;
6181cb0ef41Sopenharmony_ci  const unsigned char *ptr = ares__buf_fetch(buf, &remaining_len);
6191cb0ef41Sopenharmony_ci  ares_status_t        status;
6201cb0ef41Sopenharmony_ci
6211cb0ef41Sopenharmony_ci  if (buf == NULL || dest == NULL || len == 0 || remaining_len < len) {
6221cb0ef41Sopenharmony_ci    return ARES_EBADRESP;
6231cb0ef41Sopenharmony_ci  }
6241cb0ef41Sopenharmony_ci
6251cb0ef41Sopenharmony_ci  status = ares__buf_append(dest, ptr, len);
6261cb0ef41Sopenharmony_ci  if (status != ARES_SUCCESS) {
6271cb0ef41Sopenharmony_ci    return status;
6281cb0ef41Sopenharmony_ci  }
6291cb0ef41Sopenharmony_ci
6301cb0ef41Sopenharmony_ci  return ares__buf_consume(buf, len);
6311cb0ef41Sopenharmony_ci}
6321cb0ef41Sopenharmony_ci
6331cb0ef41Sopenharmony_cisize_t ares__buf_consume_whitespace(ares__buf_t *buf,
6341cb0ef41Sopenharmony_ci                                    ares_bool_t  include_linefeed)
6351cb0ef41Sopenharmony_ci{
6361cb0ef41Sopenharmony_ci  size_t               remaining_len = 0;
6371cb0ef41Sopenharmony_ci  const unsigned char *ptr           = ares__buf_fetch(buf, &remaining_len);
6381cb0ef41Sopenharmony_ci  size_t               i;
6391cb0ef41Sopenharmony_ci
6401cb0ef41Sopenharmony_ci  if (ptr == NULL) {
6411cb0ef41Sopenharmony_ci    return 0;
6421cb0ef41Sopenharmony_ci  }
6431cb0ef41Sopenharmony_ci
6441cb0ef41Sopenharmony_ci  for (i = 0; i < remaining_len; i++) {
6451cb0ef41Sopenharmony_ci    switch (ptr[i]) {
6461cb0ef41Sopenharmony_ci      case '\r':
6471cb0ef41Sopenharmony_ci      case '\t':
6481cb0ef41Sopenharmony_ci      case ' ':
6491cb0ef41Sopenharmony_ci      case '\v':
6501cb0ef41Sopenharmony_ci      case '\f':
6511cb0ef41Sopenharmony_ci        break;
6521cb0ef41Sopenharmony_ci      case '\n':
6531cb0ef41Sopenharmony_ci        if (!include_linefeed) {
6541cb0ef41Sopenharmony_ci          goto done;
6551cb0ef41Sopenharmony_ci        }
6561cb0ef41Sopenharmony_ci        break;
6571cb0ef41Sopenharmony_ci      default:
6581cb0ef41Sopenharmony_ci        goto done;
6591cb0ef41Sopenharmony_ci    }
6601cb0ef41Sopenharmony_ci  }
6611cb0ef41Sopenharmony_ci
6621cb0ef41Sopenharmony_cidone:
6631cb0ef41Sopenharmony_ci  if (i > 0) {
6641cb0ef41Sopenharmony_ci    ares__buf_consume(buf, i);
6651cb0ef41Sopenharmony_ci  }
6661cb0ef41Sopenharmony_ci  return i;
6671cb0ef41Sopenharmony_ci}
6681cb0ef41Sopenharmony_ci
6691cb0ef41Sopenharmony_cisize_t ares__buf_consume_nonwhitespace(ares__buf_t *buf)
6701cb0ef41Sopenharmony_ci{
6711cb0ef41Sopenharmony_ci  size_t               remaining_len = 0;
6721cb0ef41Sopenharmony_ci  const unsigned char *ptr           = ares__buf_fetch(buf, &remaining_len);
6731cb0ef41Sopenharmony_ci  size_t               i;
6741cb0ef41Sopenharmony_ci
6751cb0ef41Sopenharmony_ci  if (ptr == NULL) {
6761cb0ef41Sopenharmony_ci    return 0;
6771cb0ef41Sopenharmony_ci  }
6781cb0ef41Sopenharmony_ci
6791cb0ef41Sopenharmony_ci  for (i = 0; i < remaining_len; i++) {
6801cb0ef41Sopenharmony_ci    switch (ptr[i]) {
6811cb0ef41Sopenharmony_ci      case '\r':
6821cb0ef41Sopenharmony_ci      case '\t':
6831cb0ef41Sopenharmony_ci      case ' ':
6841cb0ef41Sopenharmony_ci      case '\v':
6851cb0ef41Sopenharmony_ci      case '\f':
6861cb0ef41Sopenharmony_ci      case '\n':
6871cb0ef41Sopenharmony_ci        goto done;
6881cb0ef41Sopenharmony_ci      default:
6891cb0ef41Sopenharmony_ci        break;
6901cb0ef41Sopenharmony_ci    }
6911cb0ef41Sopenharmony_ci  }
6921cb0ef41Sopenharmony_ci
6931cb0ef41Sopenharmony_cidone:
6941cb0ef41Sopenharmony_ci  if (i > 0) {
6951cb0ef41Sopenharmony_ci    ares__buf_consume(buf, i);
6961cb0ef41Sopenharmony_ci  }
6971cb0ef41Sopenharmony_ci  return i;
6981cb0ef41Sopenharmony_ci}
6991cb0ef41Sopenharmony_ci
7001cb0ef41Sopenharmony_cisize_t ares__buf_consume_line(ares__buf_t *buf, ares_bool_t include_linefeed)
7011cb0ef41Sopenharmony_ci{
7021cb0ef41Sopenharmony_ci  size_t               remaining_len = 0;
7031cb0ef41Sopenharmony_ci  const unsigned char *ptr           = ares__buf_fetch(buf, &remaining_len);
7041cb0ef41Sopenharmony_ci  size_t               i;
7051cb0ef41Sopenharmony_ci
7061cb0ef41Sopenharmony_ci  if (ptr == NULL) {
7071cb0ef41Sopenharmony_ci    return 0;
7081cb0ef41Sopenharmony_ci  }
7091cb0ef41Sopenharmony_ci
7101cb0ef41Sopenharmony_ci  for (i = 0; i < remaining_len; i++) {
7111cb0ef41Sopenharmony_ci    if (ptr[i] == '\n') {
7121cb0ef41Sopenharmony_ci      goto done;
7131cb0ef41Sopenharmony_ci    }
7141cb0ef41Sopenharmony_ci  }
7151cb0ef41Sopenharmony_ci
7161cb0ef41Sopenharmony_cidone:
7171cb0ef41Sopenharmony_ci  if (include_linefeed && i < remaining_len && ptr[i] == '\n') {
7181cb0ef41Sopenharmony_ci    i++;
7191cb0ef41Sopenharmony_ci  }
7201cb0ef41Sopenharmony_ci
7211cb0ef41Sopenharmony_ci  if (i > 0) {
7221cb0ef41Sopenharmony_ci    ares__buf_consume(buf, i);
7231cb0ef41Sopenharmony_ci  }
7241cb0ef41Sopenharmony_ci  return i;
7251cb0ef41Sopenharmony_ci}
7261cb0ef41Sopenharmony_ci
7271cb0ef41Sopenharmony_cisize_t ares__buf_consume_until_charset(ares__buf_t         *buf,
7281cb0ef41Sopenharmony_ci                                       const unsigned char *charset, size_t len,
7291cb0ef41Sopenharmony_ci                                       ares_bool_t require_charset)
7301cb0ef41Sopenharmony_ci{
7311cb0ef41Sopenharmony_ci  size_t               remaining_len = 0;
7321cb0ef41Sopenharmony_ci  const unsigned char *ptr           = ares__buf_fetch(buf, &remaining_len);
7331cb0ef41Sopenharmony_ci  size_t               i;
7341cb0ef41Sopenharmony_ci  ares_bool_t          found = ARES_FALSE;
7351cb0ef41Sopenharmony_ci
7361cb0ef41Sopenharmony_ci  if (ptr == NULL || charset == NULL || len == 0) {
7371cb0ef41Sopenharmony_ci    return 0;
7381cb0ef41Sopenharmony_ci  }
7391cb0ef41Sopenharmony_ci
7401cb0ef41Sopenharmony_ci  for (i = 0; i < remaining_len; i++) {
7411cb0ef41Sopenharmony_ci    size_t j;
7421cb0ef41Sopenharmony_ci    for (j = 0; j < len; j++) {
7431cb0ef41Sopenharmony_ci      if (ptr[i] == charset[j]) {
7441cb0ef41Sopenharmony_ci        found = ARES_TRUE;
7451cb0ef41Sopenharmony_ci        goto done;
7461cb0ef41Sopenharmony_ci      }
7471cb0ef41Sopenharmony_ci    }
7481cb0ef41Sopenharmony_ci  }
7491cb0ef41Sopenharmony_ci
7501cb0ef41Sopenharmony_cidone:
7511cb0ef41Sopenharmony_ci  if (require_charset && !found) {
7521cb0ef41Sopenharmony_ci    return 0;
7531cb0ef41Sopenharmony_ci  }
7541cb0ef41Sopenharmony_ci
7551cb0ef41Sopenharmony_ci  if (i > 0) {
7561cb0ef41Sopenharmony_ci    ares__buf_consume(buf, i);
7571cb0ef41Sopenharmony_ci  }
7581cb0ef41Sopenharmony_ci  return i;
7591cb0ef41Sopenharmony_ci}
7601cb0ef41Sopenharmony_ci
7611cb0ef41Sopenharmony_cisize_t ares__buf_consume_charset(ares__buf_t *buf, const unsigned char *charset,
7621cb0ef41Sopenharmony_ci                                 size_t len)
7631cb0ef41Sopenharmony_ci{
7641cb0ef41Sopenharmony_ci  size_t               remaining_len = 0;
7651cb0ef41Sopenharmony_ci  const unsigned char *ptr           = ares__buf_fetch(buf, &remaining_len);
7661cb0ef41Sopenharmony_ci  size_t               i;
7671cb0ef41Sopenharmony_ci
7681cb0ef41Sopenharmony_ci  if (ptr == NULL || charset == NULL || len == 0) {
7691cb0ef41Sopenharmony_ci    return 0;
7701cb0ef41Sopenharmony_ci  }
7711cb0ef41Sopenharmony_ci
7721cb0ef41Sopenharmony_ci  for (i = 0; i < remaining_len; i++) {
7731cb0ef41Sopenharmony_ci    size_t j;
7741cb0ef41Sopenharmony_ci    for (j = 0; j < len; j++) {
7751cb0ef41Sopenharmony_ci      if (ptr[i] == charset[j]) {
7761cb0ef41Sopenharmony_ci        break;
7771cb0ef41Sopenharmony_ci      }
7781cb0ef41Sopenharmony_ci    }
7791cb0ef41Sopenharmony_ci    /* Not found */
7801cb0ef41Sopenharmony_ci    if (j == len) {
7811cb0ef41Sopenharmony_ci      break;
7821cb0ef41Sopenharmony_ci    }
7831cb0ef41Sopenharmony_ci  }
7841cb0ef41Sopenharmony_ci
7851cb0ef41Sopenharmony_ci  if (i > 0) {
7861cb0ef41Sopenharmony_ci    ares__buf_consume(buf, i);
7871cb0ef41Sopenharmony_ci  }
7881cb0ef41Sopenharmony_ci  return i;
7891cb0ef41Sopenharmony_ci}
7901cb0ef41Sopenharmony_ci
7911cb0ef41Sopenharmony_cistatic void ares__buf_destroy_cb(void *arg)
7921cb0ef41Sopenharmony_ci{
7931cb0ef41Sopenharmony_ci  ares__buf_destroy(arg);
7941cb0ef41Sopenharmony_ci}
7951cb0ef41Sopenharmony_ci
7961cb0ef41Sopenharmony_cistatic ares_bool_t ares__buf_split_isduplicate(ares__llist_t       *list,
7971cb0ef41Sopenharmony_ci                                               const unsigned char *val,
7981cb0ef41Sopenharmony_ci                                               size_t               len,
7991cb0ef41Sopenharmony_ci                                               ares__buf_split_t    flags)
8001cb0ef41Sopenharmony_ci{
8011cb0ef41Sopenharmony_ci  ares__llist_node_t *node;
8021cb0ef41Sopenharmony_ci
8031cb0ef41Sopenharmony_ci  for (node = ares__llist_node_first(list); node != NULL;
8041cb0ef41Sopenharmony_ci       node = ares__llist_node_next(node)) {
8051cb0ef41Sopenharmony_ci    const ares__buf_t   *buf  = ares__llist_node_val(node);
8061cb0ef41Sopenharmony_ci    size_t               plen = 0;
8071cb0ef41Sopenharmony_ci    const unsigned char *ptr  = ares__buf_peek(buf, &plen);
8081cb0ef41Sopenharmony_ci
8091cb0ef41Sopenharmony_ci    /* Can't be duplicate if lengths mismatch */
8101cb0ef41Sopenharmony_ci    if (plen != len) {
8111cb0ef41Sopenharmony_ci      continue;
8121cb0ef41Sopenharmony_ci    }
8131cb0ef41Sopenharmony_ci
8141cb0ef41Sopenharmony_ci    if (flags & ARES_BUF_SPLIT_CASE_INSENSITIVE) {
8151cb0ef41Sopenharmony_ci      if (ares__memeq_ci(ptr, val, len)) {
8161cb0ef41Sopenharmony_ci        return ARES_TRUE;
8171cb0ef41Sopenharmony_ci      }
8181cb0ef41Sopenharmony_ci    } else {
8191cb0ef41Sopenharmony_ci      if (memcmp(ptr, val, len) == 0) {
8201cb0ef41Sopenharmony_ci        return ARES_TRUE;
8211cb0ef41Sopenharmony_ci      }
8221cb0ef41Sopenharmony_ci    }
8231cb0ef41Sopenharmony_ci  }
8241cb0ef41Sopenharmony_ci  return ARES_FALSE;
8251cb0ef41Sopenharmony_ci}
8261cb0ef41Sopenharmony_ci
8271cb0ef41Sopenharmony_ciares_status_t ares__buf_split(ares__buf_t *buf, const unsigned char *delims,
8281cb0ef41Sopenharmony_ci                              size_t delims_len, ares__buf_split_t flags,
8291cb0ef41Sopenharmony_ci                              ares__llist_t **list)
8301cb0ef41Sopenharmony_ci{
8311cb0ef41Sopenharmony_ci  ares_status_t status = ARES_SUCCESS;
8321cb0ef41Sopenharmony_ci  ares_bool_t   first  = ARES_TRUE;
8331cb0ef41Sopenharmony_ci
8341cb0ef41Sopenharmony_ci  if (buf == NULL || delims == NULL || delims_len == 0 || list == NULL) {
8351cb0ef41Sopenharmony_ci    return ARES_EFORMERR;
8361cb0ef41Sopenharmony_ci  }
8371cb0ef41Sopenharmony_ci
8381cb0ef41Sopenharmony_ci  *list = ares__llist_create(ares__buf_destroy_cb);
8391cb0ef41Sopenharmony_ci  if (*list == NULL) {
8401cb0ef41Sopenharmony_ci    status = ARES_ENOMEM;
8411cb0ef41Sopenharmony_ci    goto done;
8421cb0ef41Sopenharmony_ci  }
8431cb0ef41Sopenharmony_ci
8441cb0ef41Sopenharmony_ci  while (ares__buf_len(buf)) {
8451cb0ef41Sopenharmony_ci    size_t len;
8461cb0ef41Sopenharmony_ci
8471cb0ef41Sopenharmony_ci    ares__buf_tag(buf);
8481cb0ef41Sopenharmony_ci
8491cb0ef41Sopenharmony_ci    len = ares__buf_consume_until_charset(buf, delims, delims_len, ARES_FALSE);
8501cb0ef41Sopenharmony_ci
8511cb0ef41Sopenharmony_ci    /* Don't treat a delimiter as part of the length */
8521cb0ef41Sopenharmony_ci    if (!first && len && flags & ARES_BUF_SPLIT_DONT_CONSUME_DELIMS) {
8531cb0ef41Sopenharmony_ci      len--;
8541cb0ef41Sopenharmony_ci    }
8551cb0ef41Sopenharmony_ci
8561cb0ef41Sopenharmony_ci    if (len != 0 || flags & ARES_BUF_SPLIT_ALLOW_BLANK) {
8571cb0ef41Sopenharmony_ci      const unsigned char *ptr = ares__buf_tag_fetch(buf, &len);
8581cb0ef41Sopenharmony_ci      ares__buf_t         *data;
8591cb0ef41Sopenharmony_ci
8601cb0ef41Sopenharmony_ci      if (!(flags & ARES_BUF_SPLIT_NO_DUPLICATES) ||
8611cb0ef41Sopenharmony_ci          !ares__buf_split_isduplicate(*list, ptr, len, flags)) {
8621cb0ef41Sopenharmony_ci        /* Since we don't allow const buffers of 0 length, and user wants
8631cb0ef41Sopenharmony_ci         * 0-length buffers, swap what we do here */
8641cb0ef41Sopenharmony_ci        if (len) {
8651cb0ef41Sopenharmony_ci          data = ares__buf_create_const(ptr, len);
8661cb0ef41Sopenharmony_ci        } else {
8671cb0ef41Sopenharmony_ci          data = ares__buf_create();
8681cb0ef41Sopenharmony_ci        }
8691cb0ef41Sopenharmony_ci
8701cb0ef41Sopenharmony_ci        if (data == NULL) {
8711cb0ef41Sopenharmony_ci          status = ARES_ENOMEM;
8721cb0ef41Sopenharmony_ci          goto done;
8731cb0ef41Sopenharmony_ci        }
8741cb0ef41Sopenharmony_ci
8751cb0ef41Sopenharmony_ci        if (ares__llist_insert_last(*list, data) == NULL) {
8761cb0ef41Sopenharmony_ci          ares__buf_destroy(data);
8771cb0ef41Sopenharmony_ci          status = ARES_ENOMEM;
8781cb0ef41Sopenharmony_ci          goto done;
8791cb0ef41Sopenharmony_ci        }
8801cb0ef41Sopenharmony_ci      }
8811cb0ef41Sopenharmony_ci    }
8821cb0ef41Sopenharmony_ci
8831cb0ef41Sopenharmony_ci    if (!(flags & ARES_BUF_SPLIT_DONT_CONSUME_DELIMS) &&
8841cb0ef41Sopenharmony_ci        ares__buf_len(buf) != 0) {
8851cb0ef41Sopenharmony_ci      /* Consume delimiter */
8861cb0ef41Sopenharmony_ci      ares__buf_consume(buf, 1);
8871cb0ef41Sopenharmony_ci    }
8881cb0ef41Sopenharmony_ci
8891cb0ef41Sopenharmony_ci    first = ARES_FALSE;
8901cb0ef41Sopenharmony_ci  }
8911cb0ef41Sopenharmony_ci
8921cb0ef41Sopenharmony_cidone:
8931cb0ef41Sopenharmony_ci  if (status != ARES_SUCCESS) {
8941cb0ef41Sopenharmony_ci    ares__llist_destroy(*list);
8951cb0ef41Sopenharmony_ci    *list = NULL;
8961cb0ef41Sopenharmony_ci  }
8971cb0ef41Sopenharmony_ci
8981cb0ef41Sopenharmony_ci  return status;
8991cb0ef41Sopenharmony_ci}
9001cb0ef41Sopenharmony_ci
9011cb0ef41Sopenharmony_ciares_bool_t ares__buf_begins_with(const ares__buf_t   *buf,
9021cb0ef41Sopenharmony_ci                                  const unsigned char *data, size_t data_len)
9031cb0ef41Sopenharmony_ci{
9041cb0ef41Sopenharmony_ci  size_t               remaining_len = 0;
9051cb0ef41Sopenharmony_ci  const unsigned char *ptr           = ares__buf_fetch(buf, &remaining_len);
9061cb0ef41Sopenharmony_ci
9071cb0ef41Sopenharmony_ci  if (ptr == NULL || data == NULL || data_len == 0) {
9081cb0ef41Sopenharmony_ci    return ARES_FALSE;
9091cb0ef41Sopenharmony_ci  }
9101cb0ef41Sopenharmony_ci
9111cb0ef41Sopenharmony_ci  if (data_len > remaining_len) {
9121cb0ef41Sopenharmony_ci    return ARES_FALSE;
9131cb0ef41Sopenharmony_ci  }
9141cb0ef41Sopenharmony_ci
9151cb0ef41Sopenharmony_ci  if (memcmp(ptr, data, data_len) != 0) {
9161cb0ef41Sopenharmony_ci    return ARES_FALSE;
9171cb0ef41Sopenharmony_ci  }
9181cb0ef41Sopenharmony_ci
9191cb0ef41Sopenharmony_ci  return ARES_TRUE;
9201cb0ef41Sopenharmony_ci}
9211cb0ef41Sopenharmony_ci
9221cb0ef41Sopenharmony_cisize_t ares__buf_len(const ares__buf_t *buf)
9231cb0ef41Sopenharmony_ci{
9241cb0ef41Sopenharmony_ci  if (buf == NULL) {
9251cb0ef41Sopenharmony_ci    return 0;
9261cb0ef41Sopenharmony_ci  }
9271cb0ef41Sopenharmony_ci
9281cb0ef41Sopenharmony_ci  return buf->data_len - buf->offset;
9291cb0ef41Sopenharmony_ci}
9301cb0ef41Sopenharmony_ci
9311cb0ef41Sopenharmony_ciconst unsigned char *ares__buf_peek(const ares__buf_t *buf, size_t *len)
9321cb0ef41Sopenharmony_ci{
9331cb0ef41Sopenharmony_ci  return ares__buf_fetch(buf, len);
9341cb0ef41Sopenharmony_ci}
9351cb0ef41Sopenharmony_ci
9361cb0ef41Sopenharmony_cisize_t ares__buf_get_position(const ares__buf_t *buf)
9371cb0ef41Sopenharmony_ci{
9381cb0ef41Sopenharmony_ci  if (buf == NULL) {
9391cb0ef41Sopenharmony_ci    return 0;
9401cb0ef41Sopenharmony_ci  }
9411cb0ef41Sopenharmony_ci  return buf->offset;
9421cb0ef41Sopenharmony_ci}
9431cb0ef41Sopenharmony_ci
9441cb0ef41Sopenharmony_ciares_status_t ares__buf_set_position(ares__buf_t *buf, size_t idx)
9451cb0ef41Sopenharmony_ci{
9461cb0ef41Sopenharmony_ci  if (buf == NULL) {
9471cb0ef41Sopenharmony_ci    return ARES_EFORMERR;
9481cb0ef41Sopenharmony_ci  }
9491cb0ef41Sopenharmony_ci
9501cb0ef41Sopenharmony_ci  if (idx > buf->data_len) {
9511cb0ef41Sopenharmony_ci    return ARES_EFORMERR;
9521cb0ef41Sopenharmony_ci  }
9531cb0ef41Sopenharmony_ci
9541cb0ef41Sopenharmony_ci  buf->offset = idx;
9551cb0ef41Sopenharmony_ci  return ARES_SUCCESS;
9561cb0ef41Sopenharmony_ci}
9571cb0ef41Sopenharmony_ci
9581cb0ef41Sopenharmony_ciares_status_t ares__buf_parse_dns_binstr(ares__buf_t *buf, size_t remaining_len,
9591cb0ef41Sopenharmony_ci                                         unsigned char **bin, size_t *bin_len,
9601cb0ef41Sopenharmony_ci                                         ares_bool_t allow_multiple)
9611cb0ef41Sopenharmony_ci{
9621cb0ef41Sopenharmony_ci  unsigned char len;
9631cb0ef41Sopenharmony_ci  ares_status_t status;
9641cb0ef41Sopenharmony_ci  ares__buf_t  *binbuf   = NULL;
9651cb0ef41Sopenharmony_ci  size_t        orig_len = ares__buf_len(buf);
9661cb0ef41Sopenharmony_ci
9671cb0ef41Sopenharmony_ci  if (buf == NULL) {
9681cb0ef41Sopenharmony_ci    return ARES_EFORMERR;
9691cb0ef41Sopenharmony_ci  }
9701cb0ef41Sopenharmony_ci
9711cb0ef41Sopenharmony_ci  if (remaining_len == 0) {
9721cb0ef41Sopenharmony_ci    return ARES_EBADRESP;
9731cb0ef41Sopenharmony_ci  }
9741cb0ef41Sopenharmony_ci
9751cb0ef41Sopenharmony_ci  binbuf = ares__buf_create();
9761cb0ef41Sopenharmony_ci  if (binbuf == NULL) {
9771cb0ef41Sopenharmony_ci    return ARES_ENOMEM;
9781cb0ef41Sopenharmony_ci  }
9791cb0ef41Sopenharmony_ci
9801cb0ef41Sopenharmony_ci  while (orig_len - ares__buf_len(buf) < remaining_len) {
9811cb0ef41Sopenharmony_ci    status = ares__buf_fetch_bytes(buf, &len, 1);
9821cb0ef41Sopenharmony_ci    if (status != ARES_SUCCESS) {
9831cb0ef41Sopenharmony_ci      break;
9841cb0ef41Sopenharmony_ci    }
9851cb0ef41Sopenharmony_ci
9861cb0ef41Sopenharmony_ci    if (len) {
9871cb0ef41Sopenharmony_ci      /* XXX: Maybe we should scan to make sure it is printable? */
9881cb0ef41Sopenharmony_ci      if (bin != NULL) {
9891cb0ef41Sopenharmony_ci        status = ares__buf_fetch_bytes_into_buf(buf, binbuf, len);
9901cb0ef41Sopenharmony_ci      } else {
9911cb0ef41Sopenharmony_ci        status = ares__buf_consume(buf, len);
9921cb0ef41Sopenharmony_ci      }
9931cb0ef41Sopenharmony_ci      if (status != ARES_SUCCESS) {
9941cb0ef41Sopenharmony_ci        break;
9951cb0ef41Sopenharmony_ci      }
9961cb0ef41Sopenharmony_ci    }
9971cb0ef41Sopenharmony_ci
9981cb0ef41Sopenharmony_ci    if (!allow_multiple) {
9991cb0ef41Sopenharmony_ci      break;
10001cb0ef41Sopenharmony_ci    }
10011cb0ef41Sopenharmony_ci  }
10021cb0ef41Sopenharmony_ci
10031cb0ef41Sopenharmony_ci
10041cb0ef41Sopenharmony_ci  if (status != ARES_SUCCESS) {
10051cb0ef41Sopenharmony_ci    ares__buf_destroy(binbuf);
10061cb0ef41Sopenharmony_ci  } else {
10071cb0ef41Sopenharmony_ci    if (bin != NULL) {
10081cb0ef41Sopenharmony_ci      size_t mylen = 0;
10091cb0ef41Sopenharmony_ci      /* NOTE: we use ares__buf_finish_str() here as we guarantee NULL
10101cb0ef41Sopenharmony_ci       *       Termination even though we are technically returning binary data.
10111cb0ef41Sopenharmony_ci       */
10121cb0ef41Sopenharmony_ci      *bin     = (unsigned char *)ares__buf_finish_str(binbuf, &mylen);
10131cb0ef41Sopenharmony_ci      *bin_len = mylen;
10141cb0ef41Sopenharmony_ci    }
10151cb0ef41Sopenharmony_ci  }
10161cb0ef41Sopenharmony_ci
10171cb0ef41Sopenharmony_ci  return status;
10181cb0ef41Sopenharmony_ci}
10191cb0ef41Sopenharmony_ci
10201cb0ef41Sopenharmony_ciares_status_t ares__buf_parse_dns_str(ares__buf_t *buf, size_t remaining_len,
10211cb0ef41Sopenharmony_ci                                      char **str, ares_bool_t allow_multiple)
10221cb0ef41Sopenharmony_ci{
10231cb0ef41Sopenharmony_ci  size_t len;
10241cb0ef41Sopenharmony_ci  return ares__buf_parse_dns_binstr(buf, remaining_len, (unsigned char **)str,
10251cb0ef41Sopenharmony_ci                                    &len, allow_multiple);
10261cb0ef41Sopenharmony_ci}
10271cb0ef41Sopenharmony_ci
10281cb0ef41Sopenharmony_ciares_status_t ares__buf_append_num_dec(ares__buf_t *buf, size_t num, size_t len)
10291cb0ef41Sopenharmony_ci{
10301cb0ef41Sopenharmony_ci  size_t i;
10311cb0ef41Sopenharmony_ci  size_t mod;
10321cb0ef41Sopenharmony_ci
10331cb0ef41Sopenharmony_ci  if (len == 0) {
10341cb0ef41Sopenharmony_ci    len = ares__count_digits(num);
10351cb0ef41Sopenharmony_ci  }
10361cb0ef41Sopenharmony_ci
10371cb0ef41Sopenharmony_ci  mod = ares__pow(10, len);
10381cb0ef41Sopenharmony_ci
10391cb0ef41Sopenharmony_ci  for (i = len; i > 0; i--) {
10401cb0ef41Sopenharmony_ci    size_t        digit = (num % mod);
10411cb0ef41Sopenharmony_ci    ares_status_t status;
10421cb0ef41Sopenharmony_ci
10431cb0ef41Sopenharmony_ci    mod /= 10;
10441cb0ef41Sopenharmony_ci
10451cb0ef41Sopenharmony_ci    /* Silence coverity.  Shouldn't be possible since we calculate it above */
10461cb0ef41Sopenharmony_ci    if (mod == 0) {
10471cb0ef41Sopenharmony_ci      return ARES_EFORMERR;
10481cb0ef41Sopenharmony_ci    }
10491cb0ef41Sopenharmony_ci
10501cb0ef41Sopenharmony_ci    digit  /= mod;
10511cb0ef41Sopenharmony_ci    status  = ares__buf_append_byte(buf, '0' + (unsigned char)(digit & 0xFF));
10521cb0ef41Sopenharmony_ci    if (status != ARES_SUCCESS) {
10531cb0ef41Sopenharmony_ci      return status;
10541cb0ef41Sopenharmony_ci    }
10551cb0ef41Sopenharmony_ci  }
10561cb0ef41Sopenharmony_ci  return ARES_SUCCESS;
10571cb0ef41Sopenharmony_ci}
10581cb0ef41Sopenharmony_ci
10591cb0ef41Sopenharmony_ciares_status_t ares__buf_append_num_hex(ares__buf_t *buf, size_t num, size_t len)
10601cb0ef41Sopenharmony_ci{
10611cb0ef41Sopenharmony_ci  size_t                     i;
10621cb0ef41Sopenharmony_ci  static const unsigned char hexbytes[] = "0123456789ABCDEF";
10631cb0ef41Sopenharmony_ci
10641cb0ef41Sopenharmony_ci  if (len == 0) {
10651cb0ef41Sopenharmony_ci    len = ares__count_hexdigits(num);
10661cb0ef41Sopenharmony_ci  }
10671cb0ef41Sopenharmony_ci
10681cb0ef41Sopenharmony_ci  for (i = len; i > 0; i--) {
10691cb0ef41Sopenharmony_ci    ares_status_t status;
10701cb0ef41Sopenharmony_ci    status = ares__buf_append_byte(buf, hexbytes[(num >> ((i - 1) * 4)) & 0xF]);
10711cb0ef41Sopenharmony_ci    if (status != ARES_SUCCESS) {
10721cb0ef41Sopenharmony_ci      return status;
10731cb0ef41Sopenharmony_ci    }
10741cb0ef41Sopenharmony_ci  }
10751cb0ef41Sopenharmony_ci  return ARES_SUCCESS;
10761cb0ef41Sopenharmony_ci}
10771cb0ef41Sopenharmony_ci
10781cb0ef41Sopenharmony_ciares_status_t ares__buf_append_str(ares__buf_t *buf, const char *str)
10791cb0ef41Sopenharmony_ci{
10801cb0ef41Sopenharmony_ci  return ares__buf_append(buf, (const unsigned char *)str, ares_strlen(str));
10811cb0ef41Sopenharmony_ci}
10821cb0ef41Sopenharmony_ci
10831cb0ef41Sopenharmony_cistatic ares_status_t ares__buf_hexdump_line(ares__buf_t *buf, size_t idx,
10841cb0ef41Sopenharmony_ci                                            const unsigned char *data,
10851cb0ef41Sopenharmony_ci                                            size_t               len)
10861cb0ef41Sopenharmony_ci{
10871cb0ef41Sopenharmony_ci  size_t        i;
10881cb0ef41Sopenharmony_ci  ares_status_t status;
10891cb0ef41Sopenharmony_ci
10901cb0ef41Sopenharmony_ci  /* Address */
10911cb0ef41Sopenharmony_ci  status = ares__buf_append_num_hex(buf, idx, 6);
10921cb0ef41Sopenharmony_ci  if (status != ARES_SUCCESS) {
10931cb0ef41Sopenharmony_ci    return status;
10941cb0ef41Sopenharmony_ci  }
10951cb0ef41Sopenharmony_ci
10961cb0ef41Sopenharmony_ci  /* | */
10971cb0ef41Sopenharmony_ci  status = ares__buf_append_str(buf, " | ");
10981cb0ef41Sopenharmony_ci  if (status != ARES_SUCCESS) {
10991cb0ef41Sopenharmony_ci    return status;
11001cb0ef41Sopenharmony_ci  }
11011cb0ef41Sopenharmony_ci
11021cb0ef41Sopenharmony_ci  for (i = 0; i < 16; i++) {
11031cb0ef41Sopenharmony_ci    if (i >= len) {
11041cb0ef41Sopenharmony_ci      status = ares__buf_append_str(buf, "  ");
11051cb0ef41Sopenharmony_ci    } else {
11061cb0ef41Sopenharmony_ci      status = ares__buf_append_num_hex(buf, data[i], 2);
11071cb0ef41Sopenharmony_ci    }
11081cb0ef41Sopenharmony_ci    if (status != ARES_SUCCESS) {
11091cb0ef41Sopenharmony_ci      return status;
11101cb0ef41Sopenharmony_ci    }
11111cb0ef41Sopenharmony_ci
11121cb0ef41Sopenharmony_ci    status = ares__buf_append_byte(buf, ' ');
11131cb0ef41Sopenharmony_ci    if (status != ARES_SUCCESS) {
11141cb0ef41Sopenharmony_ci      return status;
11151cb0ef41Sopenharmony_ci    }
11161cb0ef41Sopenharmony_ci  }
11171cb0ef41Sopenharmony_ci
11181cb0ef41Sopenharmony_ci  /* | */
11191cb0ef41Sopenharmony_ci  status = ares__buf_append_str(buf, " | ");
11201cb0ef41Sopenharmony_ci  if (status != ARES_SUCCESS) {
11211cb0ef41Sopenharmony_ci    return status;
11221cb0ef41Sopenharmony_ci  }
11231cb0ef41Sopenharmony_ci
11241cb0ef41Sopenharmony_ci  for (i = 0; i < 16; i++) {
11251cb0ef41Sopenharmony_ci    if (i >= len) {
11261cb0ef41Sopenharmony_ci      break;
11271cb0ef41Sopenharmony_ci    }
11281cb0ef41Sopenharmony_ci    status = ares__buf_append_byte(buf, ares__isprint(data[i]) ? data[i] : '.');
11291cb0ef41Sopenharmony_ci    if (status != ARES_SUCCESS) {
11301cb0ef41Sopenharmony_ci      return status;
11311cb0ef41Sopenharmony_ci    }
11321cb0ef41Sopenharmony_ci  }
11331cb0ef41Sopenharmony_ci
11341cb0ef41Sopenharmony_ci  return ares__buf_append_byte(buf, '\n');
11351cb0ef41Sopenharmony_ci}
11361cb0ef41Sopenharmony_ci
11371cb0ef41Sopenharmony_ciares_status_t ares__buf_hexdump(ares__buf_t *buf, const unsigned char *data,
11381cb0ef41Sopenharmony_ci                                size_t len)
11391cb0ef41Sopenharmony_ci{
11401cb0ef41Sopenharmony_ci  size_t i;
11411cb0ef41Sopenharmony_ci
11421cb0ef41Sopenharmony_ci  /* Each line is 16 bytes */
11431cb0ef41Sopenharmony_ci  for (i = 0; i < len; i += 16) {
11441cb0ef41Sopenharmony_ci    ares_status_t status;
11451cb0ef41Sopenharmony_ci    status = ares__buf_hexdump_line(buf, i, data + i, len - i);
11461cb0ef41Sopenharmony_ci    if (status != ARES_SUCCESS) {
11471cb0ef41Sopenharmony_ci      return status;
11481cb0ef41Sopenharmony_ci    }
11491cb0ef41Sopenharmony_ci  }
11501cb0ef41Sopenharmony_ci
11511cb0ef41Sopenharmony_ci  return ARES_SUCCESS;
11521cb0ef41Sopenharmony_ci}
1153