/
githubmirror
/
c-ares
Обзор
Документация
Войти
/
githubmirror
/
c-ares
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/lib/include/ares_buf.h
821 строка
37 KB
Brad House
Punycode/IDNA support and encoding of Windows unicode search suffixes (#1031)
08 июл 2026, 15:26
Не верифицирован
08 июл 2026, 15:26
380be0d
Код
Авторство
О чём код?
/* MIT License * * Copyright (c) 2023 Brad House * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * SPDX-License-Identifier: MIT */ #ifndef __ARES__BUF_H #define __ARES__BUF_H #include "ares.h" #include "ares_array.h" /*! \addtogroup ares_buf Safe Data Builder and buffer * * This is a buffer building and parsing framework with a focus on security over * performance. All data to be read from the buffer will perform explicit length * validation and return a success/fail result. There are also various helpers * for writing data to the buffer which dynamically grows. * * All operations that fetch or consume data from the buffer will move forward * the internal pointer, thus marking the data as processed which may no longer * be accessible after certain operations (such as append). * * The helpers for this object are meant to be added as needed. If you can't * find it, write it! * * @{ */ struct ares_buf; /*! Opaque data type for generic hash table implementation */ typedef struct ares_buf ares_buf_t; /*! Create a new buffer object that dynamically allocates buffers for data. * * \return initialized buffer object or NULL if out of memory. */ CARES_EXTERN ares_buf_t *ares_buf_create(void); /*! Create a new buffer object that uses a user-provided data pointer. The * data provided will not be manipulated, and cannot be appended to. This * is strictly used for parsing. * * \param[in] data Data to provide to buffer, must not be NULL. * \param[in] data_len Size of buffer provided, must be > 0 * * \return initialized buffer object or NULL if out of memory or misuse. */ CARES_EXTERN ares_buf_t *ares_buf_create_const(const unsigned char *data, size_t data_len); /*! Destroy an initialized buffer object. * * \param[in] buf Initialized buf object */ CARES_EXTERN void ares_buf_destroy(ares_buf_t *buf); /*! Append multiple bytes to a dynamic buffer object * * \param[in] buf Initialized buffer object * \param[in] data Data to copy to buffer object * \param[in] data_len Length of data to copy to buffer object. * \return ARES_SUCCESS or one of the c-ares error codes */ CARES_EXTERN ares_status_t ares_buf_append(ares_buf_t *buf, const unsigned char *data, size_t data_len); /*! Append a single byte to the dynamic buffer object * * \param[in] buf Initialized buffer object * \param[in] b Single byte to append to buffer object. * \return ARES_SUCCESS or one of the c-ares error codes */ CARES_EXTERN ares_status_t ares_buf_append_byte(ares_buf_t *buf, unsigned char b); /*! Append a null-terminated string to the dynamic buffer object * * \param[in] buf Initialized buffer object * \param[in] str String to append to buffer object. * \return ARES_SUCCESS or one of the c-ares error codes */ CARES_EXTERN ares_status_t ares_buf_append_str(ares_buf_t *buf, const char *str); /*! Append a 16bit Big Endian number to the buffer. * * \param[in] buf Initialized buffer object * \param[out] u16 16bit integer * \return ARES_SUCCESS or one of the c-ares error codes */ CARES_EXTERN ares_status_t ares_buf_append_be16(ares_buf_t *buf, unsigned short u16); /*! Append a 32bit Big Endian number to the buffer. * * \param[in] buf Initialized buffer object * \param[out] u32 32bit integer * \return ARES_SUCCESS or one of the c-ares error codes */ CARES_EXTERN ares_status_t ares_buf_append_be32(ares_buf_t *buf, unsigned int u32); /*! Append a 32bit UTF codepoint as UTF8. Values that are not valid Unicode * scalar values (UTF-16 surrogate halves U+D800 through U+DFFF, and anything * greater than U+10FFFF) are rejected. * * \param[in] buf Initialized buffer object * \param[in] codepoint 32bit UTF codepoint * \return ARES_SUCCESS on success, ARES_EBADSTR if the codepoint is not a * valid Unicode scalar value, or one of the c-ares error codes */ CARES_EXTERN ares_status_t ares_buf_append_codepoint(ares_buf_t *buf, unsigned int codepoint); /*! Append a number in ASCII decimal form. * * \param[in] buf Initialized buffer object * \param[in] num Number to print * \param[in] len Length to output, use 0 for no padding * \return ARES_SUCCESS on success */ CARES_EXTERN ares_status_t ares_buf_append_num_dec(ares_buf_t *buf, size_t num, size_t len); /*! Append a number in ASCII hexadecimal form. * * \param[in] buf Initialized buffer object * \param[in] num Number to print * \param[in] len Length to output, use 0 for no padding * \return ARES_SUCCESS on success */ CARES_EXTERN ares_status_t ares_buf_append_num_hex(ares_buf_t *buf, size_t num, size_t len); /*! Sets the current buffer length. This *may* be used if there is a need to * override a prior position in the buffer, such as if there is a length * prefix that isn't easily predictable, and you must go back and overwrite * that position. * * Only valid on non-const buffers. Length provided must not exceed current * allocated buffer size, but otherwise there are very few protections on * this function. Use cautiously. * * \param[in] buf Initialized buffer object * \param[in] len Length to set * \return ARES_SUCCESS or one of the c-ares error codes */ CARES_EXTERN ares_status_t ares_buf_set_length(ares_buf_t *buf, size_t len); /*! Start a dynamic append operation that returns a buffer suitable for * writing. A desired minimum length is passed in, and the actual allocated * buffer size is returned which may be greater than the requested size. * No operation other than ares_buf_append_finish() is allowed on the * buffer after this request. * * \param[in] buf Initialized buffer object * \param[in,out] len Desired non-zero length passed in, actual buffer size * returned. * \return Pointer to writable buffer or NULL on failure (usage, out of mem) */ CARES_EXTERN unsigned char *ares_buf_append_start(ares_buf_t *buf, size_t *len); /*! Finish a dynamic append operation. Called after * ares_buf_append_start() once desired data is written. * * \param[in] buf Initialized buffer object. * \param[in] len Length of data written. May be zero to terminate * operation. Must not be greater than returned from * ares_buf_append_start(). */ CARES_EXTERN void ares_buf_append_finish(ares_buf_t *buf, size_t len); /*! Write the data provided to the buffer in a hexdump format. * * \param[in] buf Initialized buffer object. * \param[in] data Data to hex dump * \param[in] len Length of data to hexdump * \return ARES_SUCCESS on success. */ CARES_EXTERN ares_status_t ares_buf_hexdump(ares_buf_t *buf, const unsigned char *data, size_t len); /*! Clean up ares_buf_t and return allocated pointer to unprocessed data. It * is the responsibility of the caller to ares_free() the returned buffer. * The passed in buf parameter is invalidated by this call. * * \param[in] buf Initialized buffer object. Can not be a "const" buffer. * \param[out] len Length of data returned * \return pointer to unprocessed data (may be zero length) or NULL on error. */ CARES_EXTERN unsigned char *ares_buf_finish_bin(ares_buf_t *buf, size_t *len); /*! Clean up ares_buf_t and return allocated pointer to unprocessed data and * return it as a string (null terminated). It is the responsibility of the * caller to ares_free() the returned buffer. The passed in buf parameter is * invalidated by this call. * * This function in no way validates the data in this buffer is actually * a string, that characters are printable, or that there aren't multiple * NULL terminators. It is assumed that the caller will either validate that * themselves or has built this buffer with only a valid character set. * * \param[in] buf Initialized buffer object. Can not be a "const" buffer. * \param[out] len Optional. Length of data returned, or NULL if not needed. * \return pointer to unprocessed data or NULL on error. */ CARES_EXTERN char *ares_buf_finish_str(ares_buf_t *buf, size_t *len); /*! Replace the given search byte sequence with the replacement byte sequence. * This is only valid for allocated buffers, not const buffers. Will replace * all byte sequences starting at the current offset to the end of the buffer. * * \param[in] buf Initialized buffer object. Can not be a "const" * buffer. * \param[in] srch Search byte sequence, must not be NULL. * \param[in] srch_size Size of byte sequence, must not be zero. * \param[in] rplc Byte sequence to use as replacement. May be NULL if * rplc_size is zero. * \param[in] rplc_size Size of replacement byte sequence, may be 0. * \return ARES_SUCCESS on success, otherwise on may return failure only on * memory allocation failure or misuse. Will not return indication * if any replacements occurred */ CARES_EXTERN ares_status_t ares_buf_replace(ares_buf_t *buf, const unsigned char *srch, size_t srch_size, const unsigned char *rplc, size_t rplc_size); /*! Tag a position to save in the buffer in case parsing needs to rollback, * such as if insufficient data is available, but more data may be added in * the future. Only a single tag can be set per buffer object. Setting a * tag will override any pre-existing tag. * * \param[in] buf Initialized buffer object */ CARES_EXTERN void ares_buf_tag(ares_buf_t *buf); /*! Rollback to a tagged position. Will automatically clear the tag. * * \param[in] buf Initialized buffer object * \return ARES_SUCCESS or one of the c-ares error codes */ CARES_EXTERN ares_status_t ares_buf_tag_rollback(ares_buf_t *buf); /*! Clear the tagged position without rolling back. You should do this any * time a tag is no longer needed as future append operations can reclaim * buffer space. * * \param[in] buf Initialized buffer object * \return ARES_SUCCESS or one of the c-ares error codes */ CARES_EXTERN ares_status_t ares_buf_tag_clear(ares_buf_t *buf); /*! Fetch the buffer and length of data starting from the tagged position up * to the _current_ position. It will not unset the tagged position. The * data may be invalidated by any future ares_buf_*() calls. * * \param[in] buf Initialized buffer object * \param[out] len Length between tag and current offset in buffer * \return NULL on failure (such as no tag), otherwise pointer to start of * buffer */ CARES_EXTERN const unsigned char *ares_buf_tag_fetch(const ares_buf_t *buf, size_t *len); /*! Get the length of the current tag offset to the current position. * * \param[in] buf Initialized buffer object * \return length */ CARES_EXTERN size_t ares_buf_tag_length(const ares_buf_t *buf); /*! Fetch the bytes starting from the tagged position up to the _current_ * position using the provided buffer. It will not unset the tagged position. * * \param[in] buf Initialized buffer object * \param[in,out] bytes Buffer to hold data * \param[in,out] len On input, buffer size, on output, bytes place in * buffer. * \return ARES_SUCCESS if fetched, ARES_EFORMERR if insufficient buffer size */ CARES_EXTERN ares_status_t ares_buf_tag_fetch_bytes(const ares_buf_t *buf, unsigned char *bytes, size_t *len); /*! Character set validation for string fetch operations */ typedef enum { /*! Validate the data is printable ASCII only */ ARES_BUF_CHARSET_ASCII = 0, /*! Validate the data is printable ASCII or valid UTF-8 sequences. Note * that non-ASCII codepoints are only validated for well-formedness, not * printability (e.g. C1 controls and zero-width codepoints pass); it is * up to the consumer (such as IDNA conversion) to apply any further * restrictions */ ARES_BUF_CHARSET_UTF8 = 1 } ares_buf_charset_t; /*! Fetch the bytes starting from the tagged position up to the _current_ * position as a NULL-terminated string using the provided buffer. The data * is validated per the requested character set. It will not unset the * tagged position. * * \param[in] buf Initialized buffer object * \param[in,out] str Buffer to hold data * \param[in] len buffer size * \param[in] charset Character set validation to perform * \return ARES_SUCCESS if fetched, ARES_EFORMERR if insufficient buffer size, * ARES_EBADSTR if character set validation fails */ CARES_EXTERN ares_status_t ares_buf_tag_fetch_string( const ares_buf_t *buf, char *str, size_t len, ares_buf_charset_t charset); /*! Fetch the bytes starting from the tagged position up to the _current_ * position as a NULL-terminated string and placed into a newly allocated * buffer. The data is validated per the requested character set. It will * not unset the tagged position. * * \param[in] buf Initialized buffer object * \param[out] str New buffer to hold output, free with ares_free() * \param[in] charset Character set validation to perform * \return ARES_SUCCESS if fetched, ARES_EFORMERR if insufficient buffer size, * ARES_EBADSTR if character set validation fails */ CARES_EXTERN ares_status_t ares_buf_tag_fetch_strdup( const ares_buf_t *buf, char **str, ares_buf_charset_t charset); /*! Fetch the bytes starting from the tagged position up to the _current_ * position as const buffer. Care must be taken to not append or destroy the * passed in buffer until the newly fetched buffer is no longer needed since * it points to memory inside the passed in buffer which could be invalidated. * * \param[in] buf Initialized buffer object * \param[out] newbuf New const buffer object, must be destroyed when done. * \return ARES_SUCCESS if fetched */ CARES_EXTERN ares_status_t ares_buf_tag_fetch_constbuf(const ares_buf_t *buf, ares_buf_t **newbuf); /*! Determine if entire remaining buffer is ASCII-printable. If there are * no remaining bytes, or buf is NULL, returns ARES_FALSE. * * \param[in] buf Initialized buffer object * \return ARES_TRUE if data is ascii-printable */ CARES_EXTERN ares_bool_t ares_buf_isprint(const ares_buf_t *buf); /*! Consume the given number of bytes without reading them. * * \param[in] buf Initialized buffer object * \param[in] len Length to consume * \return ARES_SUCCESS or one of the c-ares error codes */ CARES_EXTERN ares_status_t ares_buf_consume(ares_buf_t *buf, size_t len); /*! Fetch a 16bit Big Endian number from the buffer. * * \param[in] buf Initialized buffer object * \param[out] u16 Buffer to hold 16bit integer * \return ARES_SUCCESS or one of the c-ares error codes */ CARES_EXTERN ares_status_t ares_buf_fetch_be16(ares_buf_t *buf, unsigned short *u16); /*! Fetch a 32bit Big Endian number from the buffer. * * \param[in] buf Initialized buffer object * \param[out] u32 Buffer to hold 32bit integer * \return ARES_SUCCESS or one of the c-ares error codes */ CARES_EXTERN ares_status_t ares_buf_fetch_be32(ares_buf_t *buf, unsigned int *u32); /*! Fetch a UTF 32bit codepoint from a UTF-8 encoded string. On success * consumes exactly the length of the UTF-8 sequence; on error nothing is * consumed. * * \param[in] buf Initialized buffer object * \param[out] codepoint UTF codepoint * \return ARES_SUCCESS on success, ARES_EBADSTR if an invalid UTF-8 * sequence is found, ARES_EBADRESP if the buffer is empty or NULL */ CARES_EXTERN ares_status_t ares_buf_fetch_codepoint(ares_buf_t *buf, unsigned int *codepoint); /*! Fetch the requested number of bytes into the provided buffer * * \param[in] buf Initialized buffer object * \param[out] bytes Buffer to hold data * \param[in] len Requested number of bytes (must be > 0) * \return ARES_SUCCESS or one of the c-ares error codes */ CARES_EXTERN ares_status_t ares_buf_fetch_bytes(ares_buf_t *buf, unsigned char *bytes, size_t len); /*! Fetch the requested number of bytes and return a new buffer that must be * ares_free()'d by the caller. * * \param[in] buf Initialized buffer object * \param[in] len Requested number of bytes (must be > 0) * \param[in] null_term Even though this is considered binary data, the user * knows it may be a vald string, so add a null * terminator. * \param[out] bytes Pointer passed by reference. Will be allocated. * \return ARES_SUCCESS or one of the c-ares error codes */ CARES_EXTERN ares_status_t ares_buf_fetch_bytes_dup(ares_buf_t *buf, size_t len, ares_bool_t null_term, unsigned char **bytes); /*! Fetch the requested number of bytes and place them into the provided * dest buffer object. * * \param[in] buf Initialized buffer object * \param[out] dest Buffer object to append bytes. * \param[in] len Requested number of bytes (must be > 0) * \return ARES_SUCCESS or one of the c-ares error codes */ CARES_EXTERN ares_status_t ares_buf_fetch_bytes_into_buf(ares_buf_t *buf, ares_buf_t *dest, size_t len); /*! Fetch the requested number of bytes and return a new buffer that must be * ares_free()'d by the caller. The returned buffer is a null terminated * string. The data is validated per the requested character set. * * \param[in] buf Initialized buffer object * \param[in] len Requested number of bytes (must be > 0) * \param[out] str Pointer passed by reference. Will be allocated. * \param[in] charset Character set validation to perform * \return ARES_SUCCESS or one of the c-ares error codes */ CARES_EXTERN ares_status_t ares_buf_fetch_str_dup(ares_buf_t *buf, size_t len, char **str, ares_buf_charset_t charset); /*! Consume whitespace characters (0x09, 0x0B, 0x0C, 0x0D, 0x20, and optionally * 0x0A). * * \param[in] buf Initialized buffer object * \param[in] include_linefeed ARES_TRUE to include consuming 0x0A, * ARES_FALSE otherwise. * \return number of whitespace characters consumed */ CARES_EXTERN size_t ares_buf_consume_whitespace(ares_buf_t *buf, ares_bool_t include_linefeed); /*! Consume any non-whitespace character (anything other than 0x09, 0x0B, 0x0C, * 0x0D, 0x20, and 0x0A). * * \param[in] buf Initialized buffer object * \return number of characters consumed */ CARES_EXTERN size_t ares_buf_consume_nonwhitespace(ares_buf_t *buf); /*! Consume until a character in the character set provided is reached. Does * not include the character from the charset at the end. * * \param[in] buf Initialized buffer object * \param[in] charset character set * \param[in] len length of character set * \param[in] require_charset require we find a character from the charset. * if ARES_FALSE it will simply consume the * rest of the buffer. If ARES_TRUE will return * SIZE_MAX if not found. * \return number of characters consumed. On invalid parameters nothing is * consumed and 0 (or SIZE_MAX if require_charset is ARES_TRUE) is * returned. */ CARES_EXTERN size_t ares_buf_consume_until_charset(ares_buf_t *buf, const unsigned char *charset, size_t len, ares_bool_t require_charset); /*! Search for the last character in the buffer matching the character set * provided, and consume up to (but not including) that character. * * \param[in] buf Initialized buffer object * \param[in] charset character set * \param[in] len length of character set * \param[in] require_charset require we find a character from the charset. * if ARES_FALSE it will simply consume the * rest of the buffer. If ARES_TRUE will return * SIZE_MAX (consuming nothing) if not found, * including when the buffer is empty. * \return number of characters consumed. On invalid parameters nothing is * consumed and 0 (or SIZE_MAX if require_charset is ARES_TRUE) is * returned. */ CARES_EXTERN size_t ares_buf_consume_last_charset(ares_buf_t *buf, const unsigned char *charset, size_t len, ares_bool_t require_charset); /*! Consume until a sequence of bytes is encountered. Does not include the * sequence of characters itself. * * \param[in] buf Initialized buffer object * \param[in] seq sequence of bytes * \param[in] len length of sequence * \param[in] require_charset require we find the sequence. * if ARES_FALSE it will simply consume the * rest of the buffer. If ARES_TRUE will return * SIZE_MAX if not found. * \return number of characters consumed */ CARES_EXTERN size_t ares_buf_consume_until_seq(ares_buf_t *buf, const unsigned char *seq, size_t len, ares_bool_t require_seq); /*! Consume while the characters match the characters in the provided set. * * \param[in] buf Initialized buffer object * \param[in] charset character set * \param[in] len length of character set * \return number of characters consumed */ CARES_EXTERN size_t ares_buf_consume_charset(ares_buf_t *buf, const unsigned char *charset, size_t len); /*! Consume from the current position until the end of the line, and optionally * the end of line character (0x0A) itself. * * \param[in] buf Initialized buffer object * \param[in] include_linefeed ARES_TRUE to include consuming 0x0A, * ARES_FALSE otherwise. * \return number of characters consumed */ CARES_EXTERN size_t ares_buf_consume_line(ares_buf_t *buf, ares_bool_t include_linefeed); typedef enum { /*! No flags */ ARES_BUF_SPLIT_NONE = 0, /*! The delimiter will be the first character in the buffer, except the * first buffer since the start doesn't have a delimiter. This option is * incompatible with ARES_BUF_SPLIT_LTRIM since the delimiter is always * the first character. */ ARES_BUF_SPLIT_KEEP_DELIMS = 1 << 0, /*! Allow blank sections, by default blank sections are not emitted. If using * ARES_BUF_SPLIT_KEEP_DELIMS, the delimiter is not counted as part * of the section */ ARES_BUF_SPLIT_ALLOW_BLANK = 1 << 1, /*! Remove duplicate entries */ ARES_BUF_SPLIT_NO_DUPLICATES = 1 << 2, /*! Perform case-insensitive matching when comparing values */ ARES_BUF_SPLIT_CASE_INSENSITIVE = 1 << 3, /*! Trim leading whitespace from buffer */ ARES_BUF_SPLIT_LTRIM = 1 << 4, /*! Trim trailing whitespace from buffer */ ARES_BUF_SPLIT_RTRIM = 1 << 5, /*! Trim leading and trailing whitespace from buffer */ ARES_BUF_SPLIT_TRIM = (ARES_BUF_SPLIT_LTRIM | ARES_BUF_SPLIT_RTRIM), /*! When splitting into strings, permit validated UTF-8 sequences in * addition to printable ASCII rather than requiring printable ASCII * only. Needed for values that may legitimately contain unicode, such * as IDN search domains from system configuration. */ ARES_BUF_SPLIT_UTF8 = 1 << 6 } ares_buf_split_t; /*! Split the provided buffer into multiple sub-buffers stored in the variable * pointed to by the linked list. The sub buffers are const buffers pointing * into the buf provided. * * \param[in] buf Initialized buffer object * \param[in] delims Possible delimiters * \param[in] delims_len Length of possible delimiters * \param[in] flags One more more flags * \param[in] max_sections Maximum number of sections. Use 0 for * unlimited. Useful for splitting key/value * pairs where the delimiter may be a valid * character in the value. A value of 1 would * have little usefulness and would effectively * ignore the delimiter itself. * \param[out] arr Result. Depending on flags, this may be a * valid array with no elements. Use * ares_array_destroy() to free the memory which * will also free the contained ares_buf_t * * objects. Each buf object returned by * ares_array_at() or similar is a pointer to * an ares_buf_t * object, meaning you need to * accept it as "ares_buf_t **" then dereference. * \return ARES_SUCCESS on success, or error like ARES_ENOMEM. */ CARES_EXTERN ares_status_t ares_buf_split( ares_buf_t *buf, const unsigned char *delims, size_t delims_len, ares_buf_split_t flags, size_t max_sections, ares_array_t **arr); /*! Split the provided buffer into an ares_array_t of C strings. * * \param[in] buf Initialized buffer object * \param[in] delims Possible delimiters * \param[in] delims_len Length of possible delimiters * \param[in] flags One more more flags * \param[in] max_sections Maximum number of sections. Use 0 for * unlimited. Useful for splitting key/value * pairs where the delimiter may be a valid * character in the value. A value of 1 would * have little usefulness and would effectively * ignore the delimiter itself. * \param[out] arr Array of strings. Free using * ares_array_destroy(). * \return ARES_SUCCESS on success, or error like ARES_ENOMEM. */ CARES_EXTERN ares_status_t ares_buf_split_str_array( ares_buf_t *buf, const unsigned char *delims, size_t delims_len, ares_buf_split_t flags, size_t max_sections, ares_array_t **arr); /*! Split the provided buffer into a C array of C strings. * * \param[in] buf Initialized buffer object * \param[in] delims Possible delimiters * \param[in] delims_len Length of possible delimiters * \param[in] flags One more more flags * \param[in] max_sections Maximum number of sections. Use 0 for * unlimited. Useful for splitting key/value * pairs where the delimiter may be a valid * character in the value. A value of 1 would * have little usefulness and would effectively * ignore the delimiter itself. * \param[out] strs Array of strings. Free using * ares_free_array(strs, nstrs, ares_free) * \param[out] nstrs Number of elements in the array. * \return ARES_SUCCESS on success, or error like ARES_ENOMEM. */ CARES_EXTERN ares_status_t ares_buf_split_str( ares_buf_t *buf, const unsigned char *delims, size_t delims_len, ares_buf_split_t flags, size_t max_sections, char ***strs, size_t *nstrs); /*! Check the unprocessed buffer to see if it begins with the sequence of * characters provided. * * \param[in] buf Initialized buffer object * \param[in] data Bytes of data to compare. * \param[in] data_len Length of data to compare. * \return ARES_TRUE on match, ARES_FALSE otherwise. */ CARES_EXTERN ares_bool_t ares_buf_begins_with(const ares_buf_t *buf, const unsigned char *data, size_t data_len); /*! Size of unprocessed remaining data length * * \param[in] buf Initialized buffer object * \return length remaining */ CARES_EXTERN size_t ares_buf_len(const ares_buf_t *buf); /*! Length of unprocessed remaining data in Unicode codepoints; the data is * validated as UTF-8 while counting. * * \param[in] buf Initialized buffer object * \param[out] len Number of Unicode codepoints (0 if the buffer is empty) * \return ARES_SUCCESS on success, ARES_EBADSTR if the remaining data is * not valid UTF-8, ARES_EFORMERR on invalid parameters. */ CARES_EXTERN ares_status_t ares_buf_len_utf8(const ares_buf_t *buf, size_t *len); /*! Retrieve a pointer to the currently unprocessed data. Generally this isn't * recommended to be used in practice. The returned pointer may be invalidated * by any future ares_buf_*() calls. * * \param[in] buf Initialized buffer object * \param[out] len Length of available data * \return Pointer to buffer of unprocessed data */ CARES_EXTERN const unsigned char *ares_buf_peek(const ares_buf_t *buf, size_t *len); /*! Retrieve the next byte in the buffer without moving forward. * * \param[in] buf Initialized buffer object * \param[out] b Single byte * \return \return ARES_SUCCESS on success, or error */ CARES_EXTERN ares_status_t ares_buf_peek_byte(const ares_buf_t *buf, unsigned char *b); /*! Wipe any processed data from the beginning of the buffer. This will * move any remaining data to the front of the internally allocated buffer. * * Can not be used on const buffer objects. * * Typically not needed to call, as any new append operation will automatically * call this function if there is insufficient space to append the data in * order to try to avoid another memory allocation. * * It may be useful to call in order to ensure the current message being * processed is in the beginning of the buffer if there is an intent to use * ares_buf_set_position() and ares_buf_get_position() as may be necessary * when processing DNS compressed names. * * If there is an active tag, it will NOT clear the tag, it will use the tag * as the start of the unprocessed data rather than the current offset. If * a prior tag is no longer needed, may be wise to call ares_buf_tag_clear(). * * \param[in] buf Initialized buffer object */ CARES_EXTERN void ares_buf_reclaim(ares_buf_t *buf); /*! Set the current offset within the internal buffer. * * Typically this should not be used, if possible, use the ares_buf_tag*() * operations instead. * * One exception is DNS name compression which may backwards reference to * an index in the message. It may be necessary in such a case to call * ares_buf_reclaim() if using a dynamic (non-const) buffer before processing * such a message. * * \param[in] buf Initialized buffer object * \param[in] idx Index to set position * \return ARES_SUCCESS if valid index */ CARES_EXTERN ares_status_t ares_buf_set_position(ares_buf_t *buf, size_t idx); /*! Get the current offset within the internal buffer. * * Typically this should not be used, if possible, use the ares_buf_tag*() * operations instead. * * This can be used to get the current position, useful for saving if a * jump via ares_buf_set_position() is performed and need to restore the * current position for future operations. * * \param[in] buf Initialized buffer object * \return index of current position */ CARES_EXTERN size_t ares_buf_get_position(const ares_buf_t *buf); /*! Parse a character-string as defined in RFC1035, as a null-terminated * string. * * \param[in] buf initialized buffer object * \param[in] remaining_len maximum length that should be used for parsing * the string, this is often less than the remaining * buffer and is based on the RR record length. * \param[out] name Pointer passed by reference to be filled in with * allocated string of the parsed that must be * ares_free()'d by the caller. * \return ARES_SUCCESS on success */ CARES_EXTERN ares_status_t ares_buf_parse_dns_str(ares_buf_t *buf, size_t remaining_len, char **name); /*! Parse a character-string as defined in RFC1035, as binary, however for * convenience this does guarantee a NULL terminator (that is not included * in the returned length). * * \param[in] buf initialized buffer object * \param[in] remaining_len maximum length that should be used for parsing * the string, this is often less than the remaining * buffer and is based on the RR record length. * \param[out] bin Pointer passed by reference to be filled in with * allocated string of the parsed that must be * ares_free()'d by the caller. * \param[out] bin_len Length of returned string. * \return ARES_SUCCESS on success */ CARES_EXTERN ares_status_t ares_buf_parse_dns_binstr(ares_buf_t *buf, size_t remaining_len, unsigned char **bin, size_t *bin_len); /*! Load data from specified file path into provided buffer. The entire file * is loaded into memory. * * \param[in] filename complete path to file * \param[in,out] buf Initialized (non-const) buffer object to load data * into * \return ARES_ENOTFOUND if file not found, ARES_EFILE if issues reading * file, ARES_ENOMEM if out of memory, ARES_SUCCESS on success. */ CARES_EXTERN ares_status_t ares_buf_load_file(const char *filename, ares_buf_t *buf); /*! @} */ #endif /* __ARES__BUF_H */