#include <msp/io/print.h>
+#include <msp/stringcodec/utf8.h>
#include <msp/strings/utils.h>
#include "output.h"
#include "statement.h"
namespace DataFile {
TextWriter::TextWriter(Output &o):
- WriterMode(o)
+ WriterMode(o),
+ codec(make_unique<StringCodec::Utf8>())
{
float_format.showpoint().precision(7);
}
{
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)
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
#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"
{
private:
Fmt float_format;
+ std::unique_ptr<StringCodec::Codec> codec;
public:
TextWriter(Output &o);
void write(const Statement &st) override;
private:
void write_(const Statement &st, unsigned);
+ std::string base64_encode(const std::string &);
};
} // namespace DataFile