]> git.tdb.fi Git - libs/datafile.git/commitdiff
Write strings containing binary data as base64
authorMikko Rasa <tdb@tdb.fi>
Tue, 27 Aug 2024 11:53:18 +0000 (14:53 +0300)
committerMikko Rasa <tdb@tdb.fi>
Tue, 27 Aug 2024 11:53:18 +0000 (14:53 +0300)
source/textwriter.cpp
source/textwriter.h

index 04fccff5afaf43ae30f708be0870b1427dd67309..460bfb3e6618cbb8a67316202d3ba23d64a5e965 100644 (file)
@@ -1,4 +1,5 @@
 #include <msp/io/print.h>
+#include <msp/stringcodec/utf8.h>
 #include <msp/strings/utils.h>
 #include "output.h"
 #include "statement.h"
@@ -10,7 +11,8 @@ namespace Msp {
 namespace DataFile {
 
 TextWriter::TextWriter(Output &o):
-       WriterMode(o)
+       WriterMode(o),
+       codec(make_unique<StringCodec::Utf8>())
 {
        float_format.showpoint().precision(7);
 }
@@ -34,7 +36,13 @@ void TextWriter::write_(const Statement &st, unsigned level)
        {
                out.put(' ');
                if(v.get_signature()==StringType::signature)
-                       out.write(format("\"%s\"", c_escape(v.get<StringType::Store>(), false)));
+               {
+                       StringType::Store str = v.get<StringType::Store>();
+                       if(codec->detect(str))
+                               out.write(format("\"%s\"", c_escape(str, false)));
+                       else
+                               out.write(format("=%s=", base64_encode(str)));
+               }
                else if(v.get_signature()==BoolType::signature)
                        out.write(v.get<BoolType::Store>() ? "true" : "false");
                else if(v.get_signature()==IntType::signature)
@@ -60,5 +68,48 @@ void TextWriter::write_(const Statement &st, unsigned level)
        out.write(";\n");
 }
 
+string TextWriter::base64_encode(const string &str)
+{
+       string b64;
+       b64.reserve(str.size()*4/3+3);
+       unsigned accum = 0;
+       unsigned a_bits = 0;
+       for(auto i=str.begin(); i!=str.end(); )
+       {
+               accum = (accum<<8)|static_cast<unsigned char>(*i);
+               a_bits += 8;
+
+               ++i;
+               if(i==str.end() && a_bits%6)
+               {
+                       accum <<= 4;
+                       a_bits += 4;
+               }
+
+               while(a_bits>=6)
+               {
+                       unsigned d = (accum>>(a_bits-6))&63;
+                       a_bits -= 6;
+                       accum &= (1<<a_bits)-1;
+
+                       if(d<26)
+                               b64 += 'A'+d;
+                       else if(d<52)
+                               b64 += 'a'+(d-26);
+                       else if(d<62)
+                               b64 += '0'+(d-52);
+                       else if(d==62)
+                               b64 += '+';
+                       else if(d==63)
+                               b64 += '/';
+               }
+       }
+
+       for(unsigned i=(str.size()+2)%3; i<2; ++i)
+               b64 += '=';
+
+       return b64;
+}
+
 } // namespace DataFile
 } // namespace Msp
index 641fc2e2e01e0e7d9f9839a59e3d7e3801eeddbb..6753639fad5f73e00e16d3fb8507c9dae94f30b2 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef MSP_DATAFILE_TEXTWRITER_H_
 #define MSP_DATAFILE_TEXTWRITER_H_
 
+#include <memory>
+#include <msp/stringcodec/codec.h>
 #include <msp/strings/fmt.h>
 #include "writermode.h"
 
@@ -11,6 +13,7 @@ class TextWriter: public WriterMode
 {
 private:
        Fmt float_format;
+       std::unique_ptr<StringCodec::Codec> codec;
 
 public:
        TextWriter(Output &o);
@@ -19,6 +22,7 @@ public:
        void write(const Statement &st) override;
 private:
        void write_(const Statement &st, unsigned);
+       std::string base64_encode(const std::string &);
 };
 
 } // namespace DataFile