mirror of
				https://github.com/RetroDECK/Duckstation.git
				synced 2025-04-10 19:15:14 +00:00 
			
		
		
		
	
		
			
	
	
		
			125 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			125 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
|   | #ifndef _C4_BASE64_HPP_
 | ||
|  | #define _C4_BASE64_HPP_
 | ||
|  | 
 | ||
|  | /** @file base64.hpp encoding/decoding for base64.
 | ||
|  |  * @see https://en.wikipedia.org/wiki/Base64
 | ||
|  |  * @see https://www.base64encode.org/
 | ||
|  |  * */ | ||
|  | 
 | ||
|  | #include "c4/charconv.hpp"
 | ||
|  | #include "c4/blob.hpp"
 | ||
|  | 
 | ||
|  | namespace c4 { | ||
|  | 
 | ||
|  | 
 | ||
|  | /** check that the given buffer is a valid base64 encoding
 | ||
|  |  * @see https://en.wikipedia.org/wiki/Base64 */
 | ||
|  | C4CORE_EXPORT bool base64_valid(csubstr encoded); | ||
|  | 
 | ||
|  | 
 | ||
|  | /** base64-encode binary data.
 | ||
|  |  * @param encoded [out] output buffer for encoded data | ||
|  |  * @param data [in] the input buffer with the binary data | ||
|  |  * | ||
|  |  * @return the number of bytes needed to return the output (ie the | ||
|  |  * required size for @p encoded). No writes occur beyond the end of | ||
|  |  * the output buffer, so it is safe to do a speculative call where the | ||
|  |  * encoded buffer is empty, or maybe too small. The caller should | ||
|  |  * ensure that the returned size is smaller than the size of the | ||
|  |  * encoded buffer. | ||
|  |  * | ||
|  |  * @note the result depends on endianness. If transfer between | ||
|  |  * little/big endian systems is desired, the caller should normalize | ||
|  |  * @p data before encoding. | ||
|  |  * | ||
|  |  * @see https://en.wikipedia.org/wiki/Base64 */
 | ||
|  | C4CORE_EXPORT size_t base64_encode(substr encoded, cblob data); | ||
|  | 
 | ||
|  | 
 | ||
|  | /** decode the base64 encoding in the given buffer
 | ||
|  |  * @param encoded [in] the encoded base64 | ||
|  |  * @param data [out] the output buffer | ||
|  |  * | ||
|  |  * @return the number of bytes needed to return the output (ie the | ||
|  |  * required size for @p data). No writes occur beyond the end of the | ||
|  |  * output buffer, so it is safe to do a speculative call where the | ||
|  |  * data buffer is empty, or maybe too small. The caller should ensure | ||
|  |  * that the returned size is smaller than the size of the data buffer. | ||
|  |  * | ||
|  |  * @note the result depends on endianness. If transfer between | ||
|  |  * little/big endian systems is desired, the caller should normalize | ||
|  |  * @p data after decoding. | ||
|  |  * | ||
|  |  * @see https://en.wikipedia.org/wiki/Base64 */
 | ||
|  | C4CORE_EXPORT size_t base64_decode(csubstr encoded, blob data); | ||
|  | 
 | ||
|  | 
 | ||
|  | namespace fmt { | ||
|  | 
 | ||
|  | template<typename CharOrConstChar> | ||
|  | struct base64_wrapper_ | ||
|  | { | ||
|  |     blob_<CharOrConstChar> data; | ||
|  |     base64_wrapper_() : data() {} | ||
|  |     base64_wrapper_(blob_<CharOrConstChar> blob) : data(blob) {} | ||
|  | }; | ||
|  | /** a tag type to mark a payload as base64-encoded */ | ||
|  | using const_base64_wrapper = base64_wrapper_<cbyte>; | ||
|  | /** a tag type to mark a payload to be encoded as base64 */ | ||
|  | using base64_wrapper = base64_wrapper_<byte>; | ||
|  | 
 | ||
|  | 
 | ||
|  | /** mark a variable to be written in base64 format */ | ||
|  | template<class ...Args> | ||
|  | C4_ALWAYS_INLINE const_base64_wrapper cbase64(Args const& C4_RESTRICT ...args) | ||
|  | { | ||
|  |     return const_base64_wrapper(cblob(args...)); | ||
|  | } | ||
|  | /** mark a csubstr to be written in base64 format */ | ||
|  | C4_ALWAYS_INLINE const_base64_wrapper cbase64(csubstr s) | ||
|  | { | ||
|  |     return const_base64_wrapper(cblob(s.str, s.len)); | ||
|  | } | ||
|  | /** mark a variable to be written in base64 format */ | ||
|  | template<class ...Args> | ||
|  | C4_ALWAYS_INLINE const_base64_wrapper base64(Args const& C4_RESTRICT ...args) | ||
|  | { | ||
|  |     return const_base64_wrapper(cblob(args...)); | ||
|  | } | ||
|  | /** mark a csubstr to be written in base64 format */ | ||
|  | C4_ALWAYS_INLINE const_base64_wrapper base64(csubstr s) | ||
|  | { | ||
|  |     return const_base64_wrapper(cblob(s.str, s.len)); | ||
|  | } | ||
|  | 
 | ||
|  | /** mark a variable to be read in base64 format */ | ||
|  | template<class ...Args> | ||
|  | C4_ALWAYS_INLINE base64_wrapper base64(Args &... args) | ||
|  | { | ||
|  |     return base64_wrapper(blob(args...)); | ||
|  | } | ||
|  | /** mark a variable to be read in base64 format */ | ||
|  | C4_ALWAYS_INLINE base64_wrapper base64(substr s) | ||
|  | { | ||
|  |     return base64_wrapper(blob(s.str, s.len)); | ||
|  | } | ||
|  | 
 | ||
|  | } // namespace fmt
 | ||
|  | 
 | ||
|  | 
 | ||
|  | /** write a variable in base64 format */ | ||
|  | inline size_t to_chars(substr buf, fmt::const_base64_wrapper b) | ||
|  | { | ||
|  |     return base64_encode(buf, b.data); | ||
|  | } | ||
|  | 
 | ||
|  | /** read a variable in base64 format */ | ||
|  | inline size_t from_chars(csubstr buf, fmt::base64_wrapper *b) | ||
|  | { | ||
|  |     return base64_decode(buf, b->data); | ||
|  | } | ||
|  | 
 | ||
|  | } // namespace c4
 | ||
|  | 
 | ||
|  | #endif /* _C4_BASE64_HPP_ */
 |