//
//  File:   hzCodec.h
//
//  Legal Notice: This file is part of the HadronZoo C++ Class Library.
//
//  Copyright 2025 HadronZoo Project (http://www.hadronzoo.com)
//
//  The HadronZoo C++ Class Library is free software: You can redistribute it, and/or modify it under the terms of the GNU Lesser General Public License, as published by the Free
//  Software Foundation, either version 3 of the License, or any later version.
//
//  The HadronZoo C++ Class Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
//  A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public License along with the HadronZoo C++ Class Library. If not, see http://www.gnu.org/licenses.
//
#ifndef hzCodec_h
#define hzCodec_h
#include <openssl/sha.h>
#include "hzChain.h"
#include "hzXbuf.h"
enum    hzCoding
{
    //  Category:   Codec
    //
    //  List of supported encodings
    ENCODING_UNDEFINED,     //  No coding specified
    ENCODING_UTF8,          //  Standard unicode
    ENCODING_BASE64,        //  The windows-1252 char set (char/byte ratio of 1, assigned meanings to high end ASCII)
    ENCODING_QP,            //  Quoted-printable encoding
    ENCODING_INVALID        //  Invalid encoding
} ;
class   hzMD5
{
    //  Category:   Codec
    //
    //  An MD5 digest is a 128-bit hash value, commonly used as a checksum in such applications as messaging and file transmission. The hzMD5 class is simply a
    //  wrapper to limit the operations that may be performed.
    uint32_t    m_Parts[4] ;    //  Total 128 bits
public:
    hzMD5   (void) ;
    //  Set functions
    hzEcode CalcMD5File (const char* filepath) ;
    hzEcode CalcMD5     (const hzChain& Z) ;
    hzEcode CalcMD5     (const char* cstr) ;
    void    Clear       (void) ;
    //  Get functions
    const uchar*    Value   (void) const    { return (const uchar*) m_Parts ; }
    bool            IsNull  (void) const ;
    const char*     Txt     (void) const ;
    operator const char*    (void) const    { return Txt() ; }
    //  Assignement Operators
    hzMD5&  operator=   (const char* pMd5) ;
    hzMD5&  operator=   (const hzString& md5) ;
    //  Test operators
    bool    operator==  (const hzMD5& op) const ;
    bool    operator!=  (const hzMD5& op) const ;
    //  Stream operators
    //friend    std::istream&   operator>>  (std::istream& is, hzMD5& md5) ;
    //friend    std::ostream&   operator<<  (std::ostream& os, const hzMD5& md5) ;
} ;
/*
**  Endian conversion
**
**  The common assertion that there is no difference between little endian machines and big endian machines, is not completely true. With big endian architecture, string comparison
**  can be sped up by casting char* pointers to int and comparing integers - on the very strict proviso that the string addresses are an exact multiple of the int size. With little
**  endian architecture, the same technique can only be used to test for equality. The _endian_import functions convert strings in chunks of 2, 4 or 8 bytes to integers that can be
**  compared, independent of architecture. The _endian_export functions convert integers back to string chunks.
*/
//  Import an internal uint16_t from char array of 2 bytes
void    _endian_import2 (uint16_t& v, const uchar* i) ;
//  Import an internal uint32_t from char array of 2 to 4 bytes
void    _endian_import2 (uint32_t& v, const uchar* i) ;
void    _endian_import3 (uint32_t& v, const uchar* i) ;
void    _endian_import4 (uint32_t& v, const uchar* i) ;
//  Import an internal uint32_t from char array of 2 to 8 bytes
void    _endian_import2 (uint64_t& v, const uchar* i) ;
void    _endian_import3 (uint64_t& v, const uchar* i) ;
void    _endian_import4 (uint64_t& v, const uchar* i) ;
void    _endian_import5 (uint64_t& v, const uchar* i) ;
void    _endian_import6 (uint64_t& v, const uchar* i) ;
void    _endian_import7 (uint64_t& v, const uchar* i) ;
void    _endian_import8 (uint64_t& v, const uchar* i) ;
//  Export an internal uint16_t to char array of 2 bytes
void    _endian_export2 (uchar* s, uint16_t n) ;
//  Export an internal uint32_t to char array of 2 to 4 bytes
void    _endian_export2 (uchar* s, uint32_t n) ;
void    _endian_export3 (uchar* s, uint32_t n) ;
void    _endian_export4 (uchar* s, uint32_t n) ;
//  Export an internal uint64_t to char array of 2 to 8 bytes
void    _endian_export2 (uchar* s, uint64_t n) ;
void    _endian_export3 (uchar* s, uint64_t n) ;
void    _endian_export4 (uchar* s, uint64_t n) ;
void    _endian_export5 (uchar* s, uint64_t n) ;
void    _endian_export6 (uchar* s, uint64_t n) ;
void    _endian_export7 (uchar* s, uint64_t n) ;
void    _endian_export8 (uchar* s, uint64_t n) ;
/*
**  Serial Integer Read and Write functions
*/
//  State size of serial integer based on the integer
#define SizeSerialUINT32(val)   (val<0x80?1:val<0x2000?2:val<0x20000?3:val<0x20000000?4:5)
//  Read integer from uchar buffer
hzEcode ReadSerialUINT64    (uint64_t& nValue, uint32_t& nLen, const uchar* ptr) ;
hzEcode ReadSerialUINT32    (uint32_t& nValue, uint32_t& nLen, const uchar* ptr) ;
hzEcode ReadSerialSINT64    (int64_t& nValue, uint32_t& nLen, const uchar* ptr) ;
hzEcode ReadSerialSINT32    (int32_t& nValue, uint32_t& nLen, const uchar* ptr) ;
//  Read integer from hzChain
hzEcode ReadSerialUINT64    (uint64_t& nValue, hzChain::Iter& zi) ;
hzEcode ReadSerialUINT32    (uint32_t& nValue, hzChain::Iter& zi) ;
hzEcode ReadSerialSINT64    (int64_t& nValue, hzChain::Iter& zi) ;
hzEcode ReadSerialSINT32    (int32_t& nValue, hzChain::Iter& zi) ;
//  Read integer from hzXbuf
hzEcode ReadSerialUINT64    (uint64_t& nValue, xbufIter& zi) ;
hzEcode ReadSerialUINT32    (uint32_t& nValue, xbufIter& zi) ;
//  Serialize integer to uchar buffer
void    WriteSerialUINT64   (uchar* pBuf, uint32_t& nLen, uint64_t nValue) ;
void    WriteSerialUINT32   (uchar* pBuf, uint32_t& nLen, uint32_t nValue) ;
void    WriteSerialSINT64   (uchar* pBuf, uint32_t& nLen, int64_t nValue) ;
void    WriteSerialSINT32   (uchar* pBuf, uint32_t& nLen, int32_t nValue) ;
//  Serialize integer to hzChain
void    WriteSerialUINT64   (hzChain& Z, uint32_t& nLen, uint64_t nValue) ;
void    WriteSerialUINT32   (hzChain& Z, uint32_t& nLen, uint32_t nValue) ;
void    WriteSerialSINT64   (hzChain& Z, uint32_t& nLen, int64_t nValue) ;
void    WriteSerialSINT32   (hzChain& Z, uint32_t& nLen, int32_t nValue) ;
/*
**  Base-64 encoding/decoding
*/
void        Base64Encode    (hzChain& Encoded, const char* pRaw) ;
void        Base64Encode    (hzChain& Encoded, const hzString& raw) ;
void        Base64Encode    (hzChain& Encoded, const hzChain& raw) ;
hzEcode     Base64Encode    (hzChain& Encoded, const char* cpDir, const char* cpFilename) ;
hzEcode     Base64Decode    (hzChain& Decoded, const char* pRaw) ;
hzEcode     Base64Decode    (hzChain& Decoded, const hzString& raw) ;
hzEcode     Base64Decode    (hzChain& Decoded, const hzChain& raw) ;
hzEcode     Base64Decode    (hzChain& Decoded, hzChain::Iter& raw) ;
hzEcode     Base64Decode    (hzString& Decoded, const char* pRaw) ;
hzEcode     Base64Decode    (hzString& Decoded, const hzString& raw) ;
hzEcode     Base64Decode    (hzString& Decoded, const hzChain& raw) ;
hzEcode     Base64Decode    (hzString& Decoded, hzChain::Iter& raw) ;
/*
**  Quoted-printable decoding (HadronZoo does not use QP encoding)
*/
hzEcode     QPDecode        (hzString& Decoded, const char* pRaw) ;
hzEcode     QPDecode        (hzChain& Decoded, const hzChain& Raw) ;
//  Decoding for short, charset encoded strings
hzEcode     CharsetStringDecode (hzString& Decoded, const hzString& raw) ;
/*
**  Zipping & un-zipping
*/
hzEcode     Gzip    (hzChain& compressed, const hzChain& orig) ;
hzEcode     Gunzip  (hzChain& orig, const hzChain& compressed) ;
//  Globals
extern  const hzMD5 _hz_null_hzMD5 ;
#endif  //  hzCodec_h