#ifndef BASE64_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define BASE64_H_62B23520_7C8E_11DE_8A39_0800200C9A66

#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
#pragma once
#endif

#include <string>
#include <vector>

namespace YAML
{
    class Node;
    
    std::string EncodeBase64(const unsigned char *data, std::size_t size);
    std::vector<unsigned char> DecodeBase64(const std::string& input);
    
    class Binary {
    public:
        Binary(): m_unownedData(0), m_unownedSize(0) {}
        Binary(const unsigned char *data, std::size_t size): m_unownedData(data), m_unownedSize(size) {}
        
        bool owned() const { return !m_unownedData; }
        std::size_t size() const { return owned() ? m_data.size() : m_unownedSize; }
        const unsigned char *data() const { return owned() ? &m_data[0] : m_unownedData; }
        
        void swap(std::vector<unsigned char>& rhs) {
            if(m_unownedData) {
                m_data.swap(rhs);
                rhs.clear();
                rhs.resize(m_unownedSize);
                std::copy(m_unownedData, m_unownedData + m_unownedSize, &rhs[0]);
                m_unownedData = 0;
                m_unownedSize = 0;
            } else {
                m_data.swap(rhs);
            }
        }
        
        bool operator == (const Binary& rhs) const {
            const std::size_t s = size();
            if(s != rhs.size())
                return false;
            const unsigned char *d1 = data();
            const unsigned char *d2 = rhs.data();
            for(std::size_t i=0;i<s;i++) {
                if(*d1++ != *d2++)
                    return false;
            }
            return true;
        }
        
        bool operator != (const Binary& rhs) const {
            return !(*this == rhs);
        }
        
    private:
        std::vector<unsigned char> m_data;
        const unsigned char *m_unownedData;
        std::size_t m_unownedSize;
    };
    
    void operator >> (const Node& node, Binary& binary);
}

#endif // BASE64_H_62B23520_7C8E_11DE_8A39_0800200C9A66
