/*
 * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
 *
 * Squid software is distributed under GPLv2+ license and includes
 * contributions from numerous individuals and organizations.
 * Please see the COPYING and CONTRIBUTORS files for details.
 */

#ifndef _SQUID_BASE64_H
#define _SQUID_BASE64_H

#if HAVE_NETTLE_BASE64_H && HAVE_NETTLE30_BASE64
#include <nettle/base64.h>

#else /* Base64 functions copied from Nettle 3.0 under GPLv2, with adjustments */

#ifdef __cplusplus
extern "C" {
#endif

// Decoding functions

/// Maximum length of output for base64_decode_update.
/// We have at most 6 buffered bits, and a total of (length + 1) * 6 bits.
#   define BASE64_DECODE_LENGTH(length) ((((length) + 1) * 6) / 8)

struct base64_decode_ctx
{
    unsigned word;   /* Leftover bits */
    unsigned bits;   /* Number buffered bits */

    /* Number of padding characters encountered */
    unsigned padding;
};

void base64_decode_init(struct base64_decode_ctx *ctx);

/* Returns 1 on success, 0 on error. DST should point to an area of
 * size at least BASE64_DECODE_LENGTH(length). The amount of data
 * generated is returned in *DST_LENGTH.
 */
int base64_decode_update(struct base64_decode_ctx *ctx,
                         size_t *dst_length,
                         uint8_t *dst,
                         size_t src_length,
                         const uint8_t *src);

/* Returns 1 on success. */
int base64_decode_final(struct base64_decode_ctx *ctx);

// Encoding functions

/* Maximum length of output for base64_encode_update. NOTE: Doesn't
 * include any padding that base64_encode_final may add. */
/* We have at most 4 buffered bits, and a total of (4 + length * 8) bits. */
#   define BASE64_ENCODE_LENGTH(length) (((length) * 8 + 4)/6)

/* Maximum length of output generated by base64_encode_final. */
#   define BASE64_ENCODE_FINAL_LENGTH 3

/* Exact length of output generated by base64_encode_raw, including
 * padding.
 */
#   define BASE64_ENCODE_RAW_LENGTH(length) ((((length) + 2)/3)*4)

struct base64_encode_ctx
{
    unsigned word;   /* Leftover bits */
    unsigned bits;  /* Number of bits, always 0, 2, or 4. */
};

void base64_encode_init(struct base64_encode_ctx *ctx);

/// Encodes a single byte. Returns amount of output (always 1 or 2).
size_t base64_encode_single(struct base64_encode_ctx *ctx, uint8_t *dst, uint8_t src);

/* Returns the number of output characters. DST should point to an
 * area of size at least BASE64_ENCODE_LENGTH(length).
 */
size_t base64_encode_update(struct base64_encode_ctx *ctx, uint8_t *dst, size_t length, const uint8_t *src);

/// DST should point to an area of size at least BASE64_ENCODE_FINAL_LENGTH
size_t base64_encode_final(struct base64_encode_ctx *ctx, uint8_t *dst);

#ifdef __cplusplus
}
#endif

#endif /* HAVE_NETTLE_BASE64_H */

/// Calculate the buffer size required to hold the encoded form of
/// a string of length 'decodedLen' including all terminator bytes.
#   define base64_encode_len(length) (BASE64_ENCODE_LENGTH(length)+BASE64_ENCODE_FINAL_LENGTH+1)

#endif /* _SQUID_BASE64_H */

