/*
 * Copyright 2009-present MongoDB, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <bson/bson-prelude.h>


#ifndef BSON_ITER_H
#define BSON_ITER_H


#include <bson/bson-endian.h>
#include <bson/bson-types.h>
#include <bson/bson.h>
#include <bson/macros.h>


BSON_BEGIN_DECLS


#define BSON_ITER_HOLDS_DOUBLE(iter) (bson_iter_type((iter)) == BSON_TYPE_DOUBLE)

#define BSON_ITER_HOLDS_UTF8(iter) (bson_iter_type((iter)) == BSON_TYPE_UTF8)

#define BSON_ITER_HOLDS_DOCUMENT(iter) (bson_iter_type((iter)) == BSON_TYPE_DOCUMENT)

#define BSON_ITER_HOLDS_ARRAY(iter) (bson_iter_type((iter)) == BSON_TYPE_ARRAY)

#define BSON_ITER_HOLDS_BINARY(iter) (bson_iter_type((iter)) == BSON_TYPE_BINARY)

#define BSON_ITER_HOLDS_VECTOR(iter) \
   (BSON_ITER_HOLDS_BINARY(iter) && bson_iter_binary_subtype(iter) == BSON_SUBTYPE_VECTOR)

#define BSON_ITER_HOLDS_VECTOR_INT8(iter) (bson_vector_int8_const_view_from_iter(NULL, iter))

#define BSON_ITER_HOLDS_VECTOR_FLOAT32(iter) (bson_vector_float32_const_view_from_iter(NULL, iter))

#define BSON_ITER_HOLDS_VECTOR_PACKED_BIT(iter) (bson_vector_packed_bit_const_view_from_iter(NULL, iter))

#define BSON_ITER_HOLDS_UNDEFINED(iter) (bson_iter_type((iter)) == BSON_TYPE_UNDEFINED)

#define BSON_ITER_HOLDS_OID(iter) (bson_iter_type((iter)) == BSON_TYPE_OID)

#define BSON_ITER_HOLDS_BOOL(iter) (bson_iter_type((iter)) == BSON_TYPE_BOOL)

#define BSON_ITER_HOLDS_DATE_TIME(iter) (bson_iter_type((iter)) == BSON_TYPE_DATE_TIME)

#define BSON_ITER_HOLDS_NULL(iter) (bson_iter_type((iter)) == BSON_TYPE_NULL)

#define BSON_ITER_HOLDS_REGEX(iter) (bson_iter_type((iter)) == BSON_TYPE_REGEX)

#define BSON_ITER_HOLDS_DBPOINTER(iter) (bson_iter_type((iter)) == BSON_TYPE_DBPOINTER)

#define BSON_ITER_HOLDS_CODE(iter) (bson_iter_type((iter)) == BSON_TYPE_CODE)

#define BSON_ITER_HOLDS_SYMBOL(iter) (bson_iter_type((iter)) == BSON_TYPE_SYMBOL)

#define BSON_ITER_HOLDS_CODEWSCOPE(iter) (bson_iter_type((iter)) == BSON_TYPE_CODEWSCOPE)

#define BSON_ITER_HOLDS_INT32(iter) (bson_iter_type((iter)) == BSON_TYPE_INT32)

#define BSON_ITER_HOLDS_TIMESTAMP(iter) (bson_iter_type((iter)) == BSON_TYPE_TIMESTAMP)

#define BSON_ITER_HOLDS_INT64(iter) (bson_iter_type((iter)) == BSON_TYPE_INT64)

#define BSON_ITER_HOLDS_DECIMAL128(iter) (bson_iter_type((iter)) == BSON_TYPE_DECIMAL128)

#define BSON_ITER_HOLDS_MAXKEY(iter) (bson_iter_type((iter)) == BSON_TYPE_MAXKEY)

#define BSON_ITER_HOLDS_MINKEY(iter) (bson_iter_type((iter)) == BSON_TYPE_MINKEY)

#define BSON_ITER_HOLDS_INT(iter) (BSON_ITER_HOLDS_INT32(iter) || BSON_ITER_HOLDS_INT64(iter))

#define BSON_ITER_HOLDS_NUMBER(iter) (BSON_ITER_HOLDS_INT(iter) || BSON_ITER_HOLDS_DOUBLE(iter))

#define BSON_ITER_IS_KEY(iter, key) (0 == strcmp((key), bson_iter_key((iter))))


BSON_EXPORT(const bson_value_t *)
bson_iter_value(bson_iter_t *iter);


/**
 * bson_iter_utf8_len_unsafe:
 * @iter: a bson_iter_t.
 *
 * Returns the length of a string currently pointed to by @iter. This performs
 * no validation so the is responsible for knowing the BSON is valid. Calling
 * bson_validate() is one way to do this ahead of time.
 */
static BSON_INLINE uint32_t
bson_iter_utf8_len_unsafe(const bson_iter_t *iter)
{
   uint32_t raw;
   BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_BEGIN
   memcpy(&raw, iter->raw + iter->d1, sizeof(raw));
   BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_END

   const uint32_t native = BSON_UINT32_FROM_LE(raw);

   int32_t len;
   memcpy(&len, &native, sizeof(len));

   return len <= 0 ? 0u : (uint32_t)(len - 1);
}


BSON_EXPORT(void)
bson_iter_array(const bson_iter_t *iter, uint32_t *array_len, const uint8_t **array);


BSON_EXPORT(void)
bson_iter_binary(const bson_iter_t *iter, bson_subtype_t *subtype, uint32_t *binary_len, const uint8_t **binary);

BSON_EXPORT(void)
bson_iter_overwrite_binary(bson_iter_t *iter, bson_subtype_t subtype, uint32_t *binary_len, uint8_t **binary);

BSON_EXPORT(bson_subtype_t)
bson_iter_binary_subtype(const bson_iter_t *iter);

BSON_EXPORT(bool)
bson_iter_binary_equal(const bson_iter_t *iter_a, const bson_iter_t *iter_b);


BSON_EXPORT(const char *)
bson_iter_code(const bson_iter_t *iter, uint32_t *length);


/**
 * bson_iter_code_unsafe:
 * @iter: A bson_iter_t.
 * @length: A location for the length of the resulting string.
 *
 * Like bson_iter_code() but performs no integrity checks.
 *
 * Returns: A string that should not be modified or freed.
 */
static BSON_INLINE const char *
bson_iter_code_unsafe(const bson_iter_t *iter, uint32_t *length)
{
   *length = bson_iter_utf8_len_unsafe(iter);
   BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_BEGIN
   return (const char *)(iter->raw + iter->d2);
   BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_END
}


BSON_EXPORT(const char *)
bson_iter_codewscope(const bson_iter_t *iter, uint32_t *length, uint32_t *scope_len, const uint8_t **scope);


BSON_EXPORT(void)
bson_iter_dbpointer(const bson_iter_t *iter, uint32_t *collection_len, const char **collection, const bson_oid_t **oid);


BSON_EXPORT(void)
bson_iter_document(const bson_iter_t *iter, uint32_t *document_len, const uint8_t **document);


BSON_EXPORT(double)
bson_iter_double(const bson_iter_t *iter);

BSON_EXPORT(double)
bson_iter_as_double(const bson_iter_t *iter);

/**
 * bson_iter_double_unsafe:
 * @iter: A bson_iter_t.
 *
 * Similar to bson_iter_double() but does not perform an integrity checking.
 *
 * Returns: A double.
 */
static BSON_INLINE double
bson_iter_double_unsafe(const bson_iter_t *iter)
{
   double val;

   BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_BEGIN
   memcpy(&val, iter->raw + iter->d1, sizeof(val));
   BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_END
   return BSON_DOUBLE_FROM_LE(val);
}


BSON_EXPORT(bool)
bson_iter_init(bson_iter_t *iter, const bson_t *bson);

BSON_EXPORT(bool)
bson_iter_init_from_data(bson_iter_t *iter, const uint8_t *data, size_t length);


BSON_EXPORT(bool)
bson_iter_init_find(bson_iter_t *iter, const bson_t *bson, const char *key);


BSON_EXPORT(bool)
bson_iter_init_find_w_len(bson_iter_t *iter, const bson_t *bson, const char *key, int keylen);


BSON_EXPORT(bool)
bson_iter_init_find_case(bson_iter_t *iter, const bson_t *bson, const char *key);

BSON_EXPORT(bool)
bson_iter_init_from_data_at_offset(
   bson_iter_t *iter, const uint8_t *data, size_t length, uint32_t offset, uint32_t keylen);

BSON_EXPORT(int32_t)
bson_iter_int32(const bson_iter_t *iter);


/**
 * bson_iter_int32_unsafe:
 * @iter: A bson_iter_t.
 *
 * Similar to bson_iter_int32() but with no integrity checking.
 *
 * Returns: A 32-bit signed integer.
 */
static BSON_INLINE int32_t
bson_iter_int32_unsafe(const bson_iter_t *iter)
{
   uint32_t raw;
   BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_BEGIN
   memcpy(&raw, iter->raw + iter->d1, sizeof(raw));
   BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_END

   const uint32_t native = BSON_UINT32_FROM_LE(raw);

   int32_t res;
   memcpy(&res, &native, sizeof(res));
   return res;
}


BSON_EXPORT(int64_t)
bson_iter_int64(const bson_iter_t *iter);


BSON_EXPORT(int64_t)
bson_iter_as_int64(const bson_iter_t *iter);


/**
 * bson_iter_int64_unsafe:
 * @iter: a bson_iter_t.
 *
 * Similar to bson_iter_int64() but without integrity checking.
 *
 * Returns: A 64-bit signed integer.
 */
static BSON_INLINE int64_t
bson_iter_int64_unsafe(const bson_iter_t *iter)
{
   uint64_t raw;
   BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_BEGIN
   memcpy(&raw, iter->raw + iter->d1, sizeof(raw));
   BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_END

   const uint64_t native = BSON_UINT64_FROM_LE(raw);

   int64_t res;
   memcpy(&res, &native, sizeof(res));
   return res;
}


BSON_EXPORT(bool)
bson_iter_find(bson_iter_t *iter, const char *key);


BSON_EXPORT(bool)
bson_iter_find_w_len(bson_iter_t *iter, const char *key, int keylen);


BSON_EXPORT(bool)
bson_iter_find_case(bson_iter_t *iter, const char *key);


BSON_EXPORT(bool)
bson_iter_find_descendant(bson_iter_t *iter, const char *dotkey, bson_iter_t *descendant);


BSON_EXPORT(bool)
bson_iter_next(bson_iter_t *iter);


BSON_EXPORT(const bson_oid_t *)
bson_iter_oid(const bson_iter_t *iter);


/**
 * bson_iter_oid_unsafe:
 * @iter: A #bson_iter_t.
 *
 * Similar to bson_iter_oid() but performs no integrity checks.
 *
 * Returns: A #bson_oid_t that should not be modified or freed.
 */
static BSON_INLINE const bson_oid_t *
bson_iter_oid_unsafe(const bson_iter_t *iter)
{
   BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_BEGIN
   return (const bson_oid_t *)(iter->raw + iter->d1);
   BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_END
}


BSON_EXPORT(bool)
bson_iter_decimal128(const bson_iter_t *iter, bson_decimal128_t *dec);


/**
 * bson_iter_decimal128_unsafe:
 * @iter: A #bson_iter_t.
 *
 * Similar to bson_iter_decimal128() but performs no integrity checks.
 *
 * Returns: A #bson_decimal128_t.
 */
static BSON_INLINE void
bson_iter_decimal128_unsafe(const bson_iter_t *iter, bson_decimal128_t *dec)
{
   uint64_t low_le;
   uint64_t high_le;

   BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_BEGIN
   memcpy(&low_le, iter->raw + iter->d1, sizeof(low_le));
   memcpy(&high_le, iter->raw + iter->d1 + 8, sizeof(high_le));
   BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_END

   dec->low = BSON_UINT64_FROM_LE(low_le);
   dec->high = BSON_UINT64_FROM_LE(high_le);
}


BSON_EXPORT(const char *)
bson_iter_key(const bson_iter_t *iter);

BSON_EXPORT(uint32_t)
bson_iter_key_len(const bson_iter_t *iter);


/**
 * bson_iter_key_unsafe:
 * @iter: A bson_iter_t.
 *
 * Similar to bson_iter_key() but performs no integrity checking.
 *
 * Returns: A string that should not be modified or freed.
 */
static BSON_INLINE const char *
bson_iter_key_unsafe(const bson_iter_t *iter)
{
   BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_BEGIN
   return (const char *)(iter->raw + iter->key);
   BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_END
}


BSON_EXPORT(const char *)
bson_iter_utf8(const bson_iter_t *iter, uint32_t *length);


/**
 * bson_iter_utf8_unsafe:
 *
 * Similar to bson_iter_utf8() but performs no integrity checking.
 *
 * Returns: A string that should not be modified or freed.
 */
static BSON_INLINE const char *
bson_iter_utf8_unsafe(const bson_iter_t *iter, size_t *length)
{
   *length = bson_iter_utf8_len_unsafe(iter);
   BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_BEGIN
   return (const char *)(iter->raw + iter->d2);
   BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_END
}


BSON_EXPORT(char *)
bson_iter_dup_utf8(const bson_iter_t *iter, uint32_t *length);


BSON_EXPORT(int64_t)
bson_iter_date_time(const bson_iter_t *iter);


BSON_EXPORT(time_t)
bson_iter_time_t(const bson_iter_t *iter);


/**
 * bson_iter_time_t_unsafe:
 * @iter: A bson_iter_t.
 *
 * Similar to bson_iter_time_t() but performs no integrity checking.
 *
 * Returns: A time_t containing the number of seconds since UNIX epoch
 *          in UTC.
 */
static BSON_INLINE time_t
bson_iter_time_t_unsafe(const bson_iter_t *iter)
{
   return (time_t)(bson_iter_int64_unsafe(iter) / 1000);
}


BSON_EXPORT(void)
bson_iter_timeval(const bson_iter_t *iter, struct timeval *tv);


/**
 * bson_iter_timeval_unsafe:
 * @iter: A bson_iter_t.
 * @tv: A struct timeval.
 *
 * Similar to bson_iter_timeval() but performs no integrity checking.
 */
static BSON_INLINE void
bson_iter_timeval_unsafe(const bson_iter_t *iter, struct timeval *tv)
{
   int64_t value = bson_iter_int64_unsafe(iter);
#ifdef BSON_OS_WIN32
   tv->tv_sec = (long)(value / 1000);
   tv->tv_usec = (long)(value % 1000) * 1000;
#else
   tv->tv_sec = (time_t)(value / 1000);
   tv->tv_usec = (suseconds_t)(value % 1000) * 1000;
#endif
}


BSON_EXPORT(void)
bson_iter_timestamp(const bson_iter_t *iter, uint32_t *timestamp, uint32_t *increment);


BSON_EXPORT(bool)
bson_iter_bool(const bson_iter_t *iter);


/**
 * bson_iter_bool_unsafe:
 * @iter: A bson_iter_t.
 *
 * Similar to bson_iter_bool() but performs no integrity checking.
 *
 * Returns: true or false.
 */
static BSON_INLINE bool
bson_iter_bool_unsafe(const bson_iter_t *iter)
{
   char val;

   BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_BEGIN
   memcpy(&val, iter->raw + iter->d1, 1);
   BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_END
   return !!val;
}


BSON_EXPORT(bool)
bson_iter_as_bool(const bson_iter_t *iter);


BSON_EXPORT(const char *)
bson_iter_regex(const bson_iter_t *iter, const char **options);


BSON_EXPORT(const char *)
bson_iter_symbol(const bson_iter_t *iter, uint32_t *length);


BSON_EXPORT(bson_type_t)
bson_iter_type(const bson_iter_t *iter);


/**
 * bson_iter_type_unsafe:
 * @iter: A bson_iter_t.
 *
 * Similar to bson_iter_type() but performs no integrity checking.
 *
 * Returns: A bson_type_t.
 */
static BSON_INLINE bson_type_t
bson_iter_type_unsafe(const bson_iter_t *iter)
{
   BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_BEGIN
   return (bson_type_t)(iter->raw + iter->type)[0];
   BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_END
}


BSON_EXPORT(bool)
bson_iter_recurse(const bson_iter_t *iter, bson_iter_t *child);


BSON_EXPORT(void)
bson_iter_overwrite_int32(bson_iter_t *iter, int32_t value);


BSON_EXPORT(void)
bson_iter_overwrite_int64(bson_iter_t *iter, int64_t value);


BSON_EXPORT(void)
bson_iter_overwrite_double(bson_iter_t *iter, double value);


BSON_EXPORT(void)
bson_iter_overwrite_decimal128(bson_iter_t *iter, const bson_decimal128_t *value);


BSON_EXPORT(void)
bson_iter_overwrite_bool(bson_iter_t *iter, bool value);


BSON_EXPORT(void)
bson_iter_overwrite_oid(bson_iter_t *iter, const bson_oid_t *value);


BSON_EXPORT(void)
bson_iter_overwrite_timestamp(bson_iter_t *iter, uint32_t timestamp, uint32_t increment);


BSON_EXPORT(void)
bson_iter_overwrite_date_time(bson_iter_t *iter, int64_t value);


BSON_EXPORT(bool)
bson_iter_visit_all(bson_iter_t *iter, const bson_visitor_t *visitor, void *data);

BSON_EXPORT(uint32_t)
bson_iter_offset(bson_iter_t *iter);


BSON_END_DECLS


#endif /* BSON_ITER_H */
