#ifndef CONNECT___NCBI_BASE64__H
#define CONNECT___NCBI_BASE64__H

/* $Id: ncbi_base64.h 607740 2020-05-06 22:16:57Z lavr $
 * ===========================================================================
 *
 *                            PUBLIC DOMAIN NOTICE
 *               National Center for Biotechnology Information
 *
 *  This software/database is a "United States Government Work" under the
 *  terms of the United States Copyright Act.  It was written as part of
 *  the author's official duties as a United States Government employee and
 *  thus cannot be copyrighted.  This software/database is freely available
 *  to the public for use. The National Library of Medicine and the U.S.
 *  Government have not placed any restriction on its use or reproduction.
 *
 *  Although all reasonable efforts have been taken to ensure the accuracy
 *  and reliability of the software and data, the NLM and the U.S.
 *  Government do not and cannot warrant the performance or results that
 *  may be obtained by using this software or data. The NLM and the U.S.
 *  Government disclaim all warranties, express or implied, including
 *  warranties of performance, merchantability or fitness for any particular
 *  purpose.
 *
 *  Please cite the author in any work or product based on this material.
 *
 * ===========================================================================
 *
 * Author:  Anton Lavrentiev
 *          Dmitry Kazimirov (base64url variant)
 *
 * File Description:
 *   BASE-64 Encoding/Decoding (C++ Toolkit CONNECT version)
 *
 */

#include <connect/connect_export.h>
#include <stddef.h>


#define BASE64_Encode CONNECT_BASE64_Encode
#define BASE64_Decode CONNECT_BASE64_Decode
#define EBase64_Result CONNECT_EBase64_Result
#define base64url_encode CONNECT_base64url_encode
#define base64url_decode CONNECT_base64url_decode


#ifdef __cplusplus
extern "C" {
#endif /*__cplusplus*/


/** BASE64-encode up to "src_size" symbols(bytes) from buffer "src_buf".
 *  Write the encoded data to buffer "dst_buf", but no more than "dst_size"
 *  bytes.
 *  Assign "*src_read" with the # of bytes successfully encoded from "src_buf".
 *  Assign "*dst_written" with the # of bytes written to buffer "dst_buf".
 *  Resulting lines will not exceed "*line_len" (or the standard default
 *  if "line_len" is NULL) bytes;  *line_len == 0 disables the line breaks.
 *  To estimate required destination buffer size, you can take into account
 *  that BASE64 encoding converts every 3 bytes of source into 4 bytes of
 *  encoded output, not including the additional line breaks ('\n').
 */
extern NCBI_XCONNECT_EXPORT void        BASE64_Encode
(const void* src_buf,     /* [in]     non-NULL */
 size_t      src_size,    /* [in]              */
 size_t*     src_read,    /* [out]    non-NULL */
 void*       dst_buf,     /* [in/out] non-NULL */
 size_t      dst_size,    /* [in]              */
 size_t*     dst_written, /* [out]    non-NULL */
 size_t*     line_len     /* [in]  may be NULL */
 );


/** BASE64-decode up to "src_size" symbols(bytes) from buffer "src_buf".
 *  Write the decoded data to buffer "dst_buf", but no more than "dst_size"
 *  bytes.
 *  Assign "*src_read" with the # of bytes successfully decoded from "src_buf".
 *  Assign "*dst_written" with the # of bytes written to buffer "dst_buf".
 *  Return FALSE (0) only if this call cannot decode anything at all.
 *  The destination buffer size, as a worst case, equal to the source size
 *  will accommodate the entire output.  As a rule, each 4 bytes of source
 *  (line breaks ignored) get converted into 3 bytes of decoded output.
 */
extern NCBI_XCONNECT_EXPORT int/*bool*/ BASE64_Decode
(const void* src_buf,     /* [in]     non-NULL */
 size_t      src_size,    /* [in]              */
 size_t*     src_read,    /* [out]    non-NULL */
 void*       dst_buf,     /* [in/out] non-NULL */
 size_t      dst_size,    /* [in]              */
 size_t*     dst_written  /* [out]    non-NULL */
 );


/**
 * Constants that define whether a base64 encoding or decoding operation
 * was successful.
 */
typedef enum {
    eBase64_OK,             /**< Transcoded successfully. */
    eBase64_BufferTooSmall, /**< The output buffer is too small. */
    eBase64_InvalidInput    /**< Input contains characters outside alphabet. */
} EBase64_Result;


/**
 * Encode binary data using the base64url variant of the Base64 family of
 * encodings.  The input data is read from src_buf and the result is stored
 * in dst_buf.  This implementation does not pad the output with '=';  nor it
 * terminates the output with '\0'.  When called with a dst_size of zero, this
 * function simply returns the required destination buffer size in output_len.
 *
 * Large inputs can be processed incrementally by dividing the input into
 * chunks and calling this function for each chunk.
 * Important:  When large inputs are incrementally encoded in this way, the
 * source buffer size for all but the last chunk must be a multiple of 3 bytes.
 *
 * For information about the base64url variant of the Base64 family of
 * encodings, please refer to RFC 4648.
 *
 * @param src_buf
 *  [in]  Data to encode.  Ignored if dst_size is zero.
 * @param src_size
 *  [in]  The size of the input data.
 * @param dst_buf
 *  [out] Output buffer.  Ignored if dst_size is zero.
 * @param dst_size
 *  [in]  The size of the output buffer or zero.
 * @param output_len
 *  [out] Variable for storing the length of the encoded string.
 *        If it turns out to be greater than dst_size, dst_buf is not
 *        written and the function returns eBase64_BufferTooSmall.
 *        Can be NULL.
 *
 * @return eBase64_OK if the input string has been successfully encoded;
 *         eBase64_BufferTooSmall if the input buffer is too small to store
 *         the encoded string.
 */
extern NCBI_XCONNECT_EXPORT EBase64_Result base64url_encode
(const void*    src_buf,    /* [in]     */
 size_t         src_size,   /* [in]     */
 void*          dst_buf,    /* [out]    */
 size_t         dst_size,   /* [in]     */
 size_t*        output_len  /* [out]    */
 );


/**
 * Decode the base64url-encoded src_buf and store the result in dst_buf, not
 * '\0'-terminated.  This implementation reports the padding character ('=')
 * as an error, so those symbols must be removed before calling this function.
 * When called with a dst_size of zero, this function simply returns the
 * required destination buffer size in output_len.
 *
 * Large inputs can be processed incrementally by dividing the input into
 * chunks and calling this function for each chunk.
 * Important:  When large inputs are incrementally decoded in this way, the
 * source buffer size for all but the last chunk must be a multiple of 4 bytes.
 *
 * For information about the base64url variant of the Base64 family of
 * encodings, please refer to RFC 4648.
 *
 * @param src_buf
 *  [in]  Base64url-encoded data to decode.  Ignored if dst_size is zero.
 * @param src_size
 *  [in]  The size of src_buf.
 * @param dst_buf
 *  [out] Output buffer.  Ignored if dst_size is zero.
 * @param dst_size
 *  [in]  The size of the output buffer or zero.
 * @param output_len
 *  [out] Variable for storing the length of the decoded string.
 *        If more space than dst_size bytes is required, dst_buf is not
 *        written and the function returns eBase64_BufferTooSmall.
 *        Can be NULL.
 *
 * @return eBase64_OK if the input string has been successfully decoded;
 *         eBase64_BufferTooSmall if the input buffer is too small to store
 *         the decoded string;
 *         eBase64_InvalidInput if there's a character in src_buf that's not
 *         from the base64url alphabet (alphanumeric, underscore, and dash
 *         characters).
 */
extern NCBI_XCONNECT_EXPORT EBase64_Result base64url_decode
(const void*    src_buf,    /* [in]     */
 size_t         src_size,   /* [in]     */
 void*          dst_buf,    /* [out]    */
 size_t         dst_size,   /* [in]     */
 size_t*        output_len  /* [out]    */
 );


#ifdef __cplusplus
}
#endif /*__cplusplus*/


#endif  /* CONNECT___NCBI_BASE64__H */
