From cdecd084dd9eec0acbf04c629f38dd5ce7c36460 Mon Sep 17 00:00:00 2001 From: sxrzh Date: Mon, 1 Jun 2026 13:22:48 +0800 Subject: [PATCH 1/3] Support line wrapping for literal binary emitting. --- include/yaml-cpp/emitter.h | 5 +++++ include/yaml-cpp/emittermanip.h | 7 +++++++ src/emitter.cpp | 8 +++++++- src/emitterstate.cpp | 6 ++++++ src/emitterstate.h | 4 ++++ src/emitterutils.cpp | 19 +++++++++++++++++-- src/emitterutils.h | 2 +- 7 files changed, 47 insertions(+), 4 deletions(-) diff --git a/include/yaml-cpp/emitter.h b/include/yaml-cpp/emitter.h index 44eb36624..d236bef40 100644 --- a/include/yaml-cpp/emitter.h +++ b/include/yaml-cpp/emitter.h @@ -71,6 +71,7 @@ class YAML_CPP_API Emitter { // local setters Emitter& SetLocalValue(EMITTER_MANIP value); Emitter& SetLocalIndent(const _Indent& indent); + Emitter& SetLocalWrap(const _Wrap& wrap); Emitter& SetLocalPrecision(const _Precision& precision); // overloads of write @@ -298,6 +299,10 @@ inline Emitter& operator<<(Emitter& emitter, _Indent indent) { return emitter.SetLocalIndent(indent); } +inline Emitter& operator<<(Emitter& emitter, _Wrap wrap) { + return emitter.SetLocalWrap(wrap); +} + inline Emitter& operator<<(Emitter& emitter, _Precision precision) { return emitter.SetLocalPrecision(precision); } diff --git a/include/yaml-cpp/emittermanip.h b/include/yaml-cpp/emittermanip.h index 976d14950..ff333e113 100644 --- a/include/yaml-cpp/emittermanip.h +++ b/include/yaml-cpp/emittermanip.h @@ -76,6 +76,13 @@ struct _Indent { inline _Indent Indent(int value) { return _Indent(value); } +struct _Wrap { + _Wrap(int value_) : value(value_) {} + int value; +}; + +inline _Wrap Wrap(int value) { return _Wrap(value); } + struct _Alias { _Alias(const std::string& content_) : content(content_) {} std::string content; diff --git a/src/emitter.cpp b/src/emitter.cpp index 324246818..9e559d64c 100644 --- a/src/emitter.cpp +++ b/src/emitter.cpp @@ -145,6 +145,11 @@ Emitter& Emitter::SetLocalIndent(const _Indent& indent) { return *this; } +Emitter& Emitter::SetLocalWrap(const _Wrap& wrap) { + m_pState->SetWrap(wrap.value, FmtScope::Local); + return *this; +} + Emitter& Emitter::SetLocalPrecision(const _Precision& precision) { if (precision.floatPrecision >= 0) m_pState->SetFloatPrecision(precision.floatPrecision, FmtScope::Local); @@ -998,7 +1003,8 @@ Emitter& Emitter::Write(const Binary& binary) { break; case StringFormat::Literal: Utils::WriteLiteralBinary(m_stream, binary, - m_pState->CurIndent() + m_pState->GetIndent()); + m_pState->CurIndent() + m_pState->GetIndent(), + m_pState->GetWrap()); break; } diff --git a/src/emitterstate.cpp b/src/emitterstate.cpp index 5dfad04f2..b04951e5e 100644 --- a/src/emitterstate.cpp +++ b/src/emitterstate.cpp @@ -18,6 +18,7 @@ EmitterState::EmitterState() m_indent(2), m_preCommentIndent(2), m_postCommentIndent(1), + m_wrap(80), m_seqFmt(Block), m_mapFmt(Block), m_mapKeyFmt(Auto), @@ -352,6 +353,11 @@ bool EmitterState::SetPostCommentIndent(std::size_t value, return true; } +bool EmitterState::SetWrap(std::size_t value, FmtScope::value scope) { + _Set(m_wrap, value, scope); + return true; +} + bool EmitterState::SetFlowType(GroupType::value groupType, EMITTER_MANIP value, FmtScope::value scope) { switch (value) { diff --git a/src/emitterstate.h b/src/emitterstate.h index 351a09622..896134956 100644 --- a/src/emitterstate.h +++ b/src/emitterstate.h @@ -108,6 +108,9 @@ class EmitterState { bool SetPostCommentIndent(std::size_t value, FmtScope::value scope); std::size_t GetPostCommentIndent() const { return m_postCommentIndent.get(); } + bool SetWrap(std::size_t value, FmtScope::value scope); + std::size_t GetWrap() const { return m_wrap.get(); } + bool SetFlowType(GroupType::value groupType, EMITTER_MANIP value, FmtScope::value scope); EMITTER_MANIP GetFlowType(GroupType::value groupType) const; @@ -143,6 +146,7 @@ class EmitterState { Setting m_intFmt; Setting m_indent; Setting m_preCommentIndent, m_postCommentIndent; + Setting m_wrap; // applied to literal binary Setting m_seqFmt; Setting m_mapFmt; Setting m_mapKeyFmt; diff --git a/src/emitterutils.cpp b/src/emitterutils.cpp index ce9bed15f..ed9814158 100644 --- a/src/emitterutils.cpp +++ b/src/emitterutils.cpp @@ -544,9 +544,24 @@ bool WriteBinary(ostream_wrapper& out, const Binary& binary) { return true; } -bool WriteLiteralBinary(ostream_wrapper& out, const Binary& binary, std::size_t indent) { +bool WriteLiteralBinary(ostream_wrapper& out, const Binary& binary, std::size_t indent, std::size_t wrap) { std::string encoded = EncodeBase64(binary.data(), binary.size()); - WriteLiteralString(out, encoded.data(), encoded.size(), indent); + std::string wrapped = ""; + if(wrap) { + if(wrap <= indent) return false; + wrap -= indent; + std::size_t point = wrap; + for(std::size_t i = 0; i < encoded.size(); i++) { + if(i == point) { + wrapped += '\n'; + point += wrap; + } + wrapped += encoded[i]; + } + } + else + wrapped = encoded; + WriteLiteralString(out, wrapped.data(), wrapped.size(), indent); return true; } diff --git a/src/emitterutils.h b/src/emitterutils.h index 209a674bc..328f782b4 100644 --- a/src/emitterutils.h +++ b/src/emitterutils.h @@ -53,7 +53,7 @@ bool WriteTagWithPrefix(ostream_wrapper& out, const std::string& prefix, const std::string& tag); bool WriteBinary(ostream_wrapper& out, const Binary& binary); bool WriteSingleQuotedBinary(ostream_wrapper& out, const Binary& binary); -bool WriteLiteralBinary(ostream_wrapper& out, const Binary& binary, std::size_t indent); +bool WriteLiteralBinary(ostream_wrapper& out, const Binary& binary, std::size_t indent, std::size_t wrap); } } From c0fb7f1bdf6799ffa7c484eb576bd0e193da46a1 Mon Sep 17 00:00:00 2001 From: sxrzh Date: Mon, 1 Jun 2026 15:14:36 +0800 Subject: [PATCH 2/3] Add test for literal binary wrapping --- test/integration/emitter_test.cpp | 61 +++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/test/integration/emitter_test.cpp b/test/integration/emitter_test.cpp index 1e67f2fca..4736d2349 100644 --- a/test/integration/emitter_test.cpp +++ b/test/integration/emitter_test.cpp @@ -1219,6 +1219,67 @@ TEST_F(EmitterTest, BinaryStyles) { ); } +TEST_F(EmitterTest, BinaryWrap) { + Binary binary(reinterpret_cast( + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed eiusmod " + "tempor incididunt ut labore et dolore magna aliqua." + "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris " + "nisi ut aliquip exea commodo consequat." + ), 226); + + out << BeginMap; + out << Key << "wrap80"; + out << Value << Literal << binary; + out << Key << "wrap80_indent4"; + out << Value << Literal << Indent(4) << binary; + out << Key << "wrap60"; + out << Value << Literal << Wrap(60) << binary; + out << Key << "wrap60_indent4"; + out << Value << Literal << Wrap(60) << Indent(4) << binary; + out << Key << "wrap_off"; + out << Value << Literal << Wrap(0) << binary; + out << Key << "wrap_off_indent4"; + out << Value << Literal << Wrap(0) << Indent(4) << binary; + ExpectEmit( + "wrap80: !!binary |-\n" + " TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4gU2\n" + " VkIGVpdXNtb2QgdGVtcG9yIGluY2lkaWR1bnQgdXQgbGFib3JlIGV0IGRvbG9yZSBtYWduYSBhbGlx\n" + " dWEuVXQgZW5pbSBhZCBtaW5pbSB2ZW5pYW0sIHF1aXMgbm9zdHJ1ZCBleGVyY2l0YXRpb24gdWxsYW\n" + " 1jbyBsYWJvcmlzIG5pc2kgdXQgYWxpcXVpcCBleGVhIGNvbW1vZG8gY29uc2VxdWF0Lg==\n" + "wrap80_indent4: !!binary |-\n" + " TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4g\n" + " U2VkIGVpdXNtb2QgdGVtcG9yIGluY2lkaWR1bnQgdXQgbGFib3JlIGV0IGRvbG9yZSBtYWduYSBh\n" + " bGlxdWEuVXQgZW5pbSBhZCBtaW5pbSB2ZW5pYW0sIHF1aXMgbm9zdHJ1ZCBleGVyY2l0YXRpb24g\n" + " dWxsYW1jbyBsYWJvcmlzIG5pc2kgdXQgYWxpcXVpcCBleGVhIGNvbW1vZG8gY29uc2VxdWF0Lg==\n" + "wrap60: !!binary |-\n" + " TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaX\n" + " Bpc2NpbmcgZWxpdC4gU2VkIGVpdXNtb2QgdGVtcG9yIGluY2lkaWR1bnQg\n" + " dXQgbGFib3JlIGV0IGRvbG9yZSBtYWduYSBhbGlxdWEuVXQgZW5pbSBhZC\n" + " BtaW5pbSB2ZW5pYW0sIHF1aXMgbm9zdHJ1ZCBleGVyY2l0YXRpb24gdWxs\n" + " YW1jbyBsYWJvcmlzIG5pc2kgdXQgYWxpcXVpcCBleGVhIGNvbW1vZG8gY2\n" + " 9uc2VxdWF0Lg==\n" + "wrap60_indent4: !!binary |-\n" + " TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFk\n" + " aXBpc2NpbmcgZWxpdC4gU2VkIGVpdXNtb2QgdGVtcG9yIGluY2lkaWR1\n" + " bnQgdXQgbGFib3JlIGV0IGRvbG9yZSBtYWduYSBhbGlxdWEuVXQgZW5p\n" + " bSBhZCBtaW5pbSB2ZW5pYW0sIHF1aXMgbm9zdHJ1ZCBleGVyY2l0YXRp\n" + " b24gdWxsYW1jbyBsYWJvcmlzIG5pc2kgdXQgYWxpcXVpcCBleGVhIGNv\n" + " bW1vZG8gY29uc2VxdWF0Lg==\n" + "wrap_off: !!binary |-\n" + " TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZW" + "xpdC4gU2VkIGVpdXNtb2QgdGVtcG9yIGluY2lkaWR1bnQgdXQgbGFib3JlIGV0IGRvbG9yZS" + "BtYWduYSBhbGlxdWEuVXQgZW5pbSBhZCBtaW5pbSB2ZW5pYW0sIHF1aXMgbm9zdHJ1ZCBleG" + "VyY2l0YXRpb24gdWxsYW1jbyBsYWJvcmlzIG5pc2kgdXQgYWxpcXVpcCBleGVhIGNvbW1vZG" + "8gY29uc2VxdWF0Lg==\n" + "wrap_off_indent4: !!binary |-\n" + " TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2Npbmcg" + "ZWxpdC4gU2VkIGVpdXNtb2QgdGVtcG9yIGluY2lkaWR1bnQgdXQgbGFib3JlIGV0IGRvbG9y" + "ZSBtYWduYSBhbGlxdWEuVXQgZW5pbSBhZCBtaW5pbSB2ZW5pYW0sIHF1aXMgbm9zdHJ1ZCBl" + "eGVyY2l0YXRpb24gdWxsYW1jbyBsYWJvcmlzIG5pc2kgdXQgYWxpcXVpcCBleGVhIGNvbW1v" + "ZG8gY29uc2VxdWF0Lg==" + ); +} + TEST_F(EmitterTest, ColonAtEndOfScalar) { out << "a:"; ExpectEmit("\"a:\""); From 9be0b4b30c3d4232c3db4bb3bb4e2b89298f6605 Mon Sep 17 00:00:00 2001 From: sxrzh Date: Fri, 3 Jul 2026 16:31:50 +0800 Subject: [PATCH 3/3] fix code style and maintainability --- src/emitterutils.cpp | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/emitterutils.cpp b/src/emitterutils.cpp index ed9814158..69c701683 100644 --- a/src/emitterutils.cpp +++ b/src/emitterutils.cpp @@ -539,20 +539,19 @@ bool WriteTagWithPrefix(ostream_wrapper& out, const std::string& prefix, bool WriteBinary(ostream_wrapper& out, const Binary& binary) { std::string encoded = EncodeBase64(binary.data(), binary.size()); - WriteDoubleQuotedString(out, encoded.data(), encoded.size(), - StringEscaping::None); - return true; + return WriteDoubleQuotedString(out, encoded.data(), encoded.size(), + StringEscaping::None); } bool WriteLiteralBinary(ostream_wrapper& out, const Binary& binary, std::size_t indent, std::size_t wrap) { std::string encoded = EncodeBase64(binary.data(), binary.size()); std::string wrapped = ""; - if(wrap) { - if(wrap <= indent) return false; + if (wrap) { + if (wrap <= indent) return false; wrap -= indent; std::size_t point = wrap; - for(std::size_t i = 0; i < encoded.size(); i++) { - if(i == point) { + for (std::size_t i = 0; i < encoded.size(); i++) { + if (i == point) { wrapped += '\n'; point += wrap; } @@ -561,14 +560,12 @@ bool WriteLiteralBinary(ostream_wrapper& out, const Binary& binary, std::size_t } else wrapped = encoded; - WriteLiteralString(out, wrapped.data(), wrapped.size(), indent); - return true; + return WriteLiteralString(out, wrapped.data(), wrapped.size(), indent); } bool WriteSingleQuotedBinary(ostream_wrapper& out, const Binary& binary) { std::string encoded = EncodeBase64(binary.data(), binary.size()); - WriteSingleQuotedString(out, encoded.data(), encoded.size()); - return true; + return WriteSingleQuotedString(out, encoded.data(), encoded.size()); } } // namespace Utils