diff --git a/include/yaml-cpp/emitter.h b/include/yaml-cpp/emitter.h index 69021e8..a1980e9 100644 --- a/include/yaml-cpp/emitter.h +++ b/include/yaml-cpp/emitter.h @@ -53,6 +53,7 @@ namespace YAML Emitter& Write(const _Tag& tag); Emitter& Write(const _Comment& comment); Emitter& Write(const _Null& null); + Emitter& Write(const _Binary& binary); template Emitter& WriteIntegralType(T value); @@ -127,6 +128,7 @@ namespace YAML inline Emitter& operator << (Emitter& emitter, const _Tag& v) { return emitter.Write(v); } inline Emitter& operator << (Emitter& emitter, const _Comment& v) { return emitter.Write(v); } inline Emitter& operator << (Emitter& emitter, const _Null& v) { return emitter.Write(v); } + inline Emitter& operator << (Emitter& emitter, const _Binary& b) { return emitter.Write(b); } inline Emitter& operator << (Emitter& emitter, const char *v) { return emitter.Write(std::string(v)); } diff --git a/include/yaml-cpp/emittermanip.h b/include/yaml-cpp/emittermanip.h index a20bfb6..5ce0503 100644 --- a/include/yaml-cpp/emittermanip.h +++ b/include/yaml-cpp/emittermanip.h @@ -111,6 +111,16 @@ namespace YAML inline _Comment Comment(const std::string content) { return _Comment(content); } + + struct _Binary { + _Binary(const char *data_, std::size_t size_): data(data_), size(size_) {} + const char *data; + std::size_t size; + }; + + inline _Binary Binary(const char *data, std::size_t size) { + return _Binary(data, size); + } } #endif // EMITTERMANIP_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/src/emitter.cpp b/src/emitter.cpp index 1b847e1..91500a8 100644 --- a/src/emitter.cpp +++ b/src/emitter.cpp @@ -724,5 +724,19 @@ namespace YAML PostAtomicWrite(); return *this; } + + Emitter& Emitter::Write(const _Binary& binary) + { + if(!good()) + return *this; + + // TODO: write tag !!binary + + PreAtomicWrite(); + EmitSeparationIfNecessary(); + Utils::WriteBinary(m_stream, binary.data, binary.size); + PostAtomicWrite(); + return *this; + } } diff --git a/src/emitterutils.cpp b/src/emitterutils.cpp index 45e9f69..7bd03d8 100644 --- a/src/emitterutils.cpp +++ b/src/emitterutils.cpp @@ -313,6 +313,43 @@ namespace YAML out << ">"; return true; } + + bool WriteBinary(ostream& out, const char *data, std::size_t size) + { + static const char encoding[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + const char PAD = '='; + + out << "\""; + std::size_t chunks = size / 3; + std::size_t remainder = size % 3; + + for(std::size_t i=0;i> 2]; + out << encoding[((data[0] & 0x3) << 4) | (data[1] >> 4)]; + out << encoding[((data[1] & 0xf) << 2) | (data[2] >> 6)]; + out << encoding[data[2] & 0x3f]; + } + + switch(remainder) { + case 0: + break; + case 1: + out << encoding[data[0] >> 2]; + out << encoding[((data[0] & 0x3) << 4)]; + out << PAD; + out << PAD; + break; + case 2: + out << encoding[data[0] >> 2]; + out << encoding[((data[0] & 0x3) << 4) | (data[1] >> 4)]; + out << encoding[((data[1] & 0xf) << 2)]; + out << PAD; + break; + } + + out << "\""; + return true; + } } } diff --git a/src/emitterutils.h b/src/emitterutils.h index 8e2356c..aa108c1 100644 --- a/src/emitterutils.h +++ b/src/emitterutils.h @@ -19,6 +19,7 @@ namespace YAML bool WriteAlias(ostream& out, const std::string& str); bool WriteAnchor(ostream& out, const std::string& str); bool WriteTag(ostream& out, const std::string& str, bool verbatim); + bool WriteBinary(ostream& out, const char *data, std::size_t size); } } diff --git a/test/emittertests.cpp b/test/emittertests.cpp index cce4e01..cfbac82 100644 --- a/test/emittertests.cpp +++ b/test/emittertests.cpp @@ -708,6 +708,24 @@ namespace Test out << YAML::EndSeq; desiredOutput = "---\n- a\n\n-\n - b\n - c\n\n\n-\n\n d: e\n ? f\n\n : foo"; } + + void Binary(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::Binary("Hello, World!", 13); + desiredOutput = "--- !!binary \"SGVsbG8sIFdvcmxkIQ==\""; + } + + void LongBinary(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::Binary("Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure.\n", 270); + desiredOutput = "--- !!binary \"TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4K\""; + } + + void EmptyBinary(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::Binary("", 0); + desiredOutput = "--- !!binary \"\""; + } //////////////////////////////////////////////////////////////////////////////////////////////////////// // incorrect emitting @@ -895,6 +913,9 @@ namespace Test RunEmitterTest(&Emitter::NewlineInBlockMap, "newline in block map", passed, total); RunEmitterTest(&Emitter::NewlineInFlowMap, "newline in flow map", passed, total); RunEmitterTest(&Emitter::LotsOfNewlines, "lots of newlines", passed, total); + RunEmitterTest(&Emitter::Binary, "binary", passed, total); + RunEmitterTest(&Emitter::LongBinary, "long binary", passed, total); + RunEmitterTest(&Emitter::EmptyBinary, "empty binary", passed, total); RunEmitterErrorTest(&Emitter::ExtraEndSeq, "extra EndSeq", passed, total); RunEmitterErrorTest(&Emitter::ExtraEndMap, "extra EndMap", passed, total);