boost json serialization and message_queue segfault - c++

i'm making some test with boost interprocess and ptree structure, i have a segfault when i try to read the message sent(or when i try to parse it in json).
i'm using boost1.49 on debian linux.
i'm serializing it in json for later uses, and because i didn't find any good doc for the direct serialization of the boost property threes.
this is the code i'm using to test(the commed say where the segfault is):
recv.cc
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/interprocess/ipc/message_queue.hpp>
#include <sstream>
struct test_data{
std::string action;
std::string name;
int faceID;
uint32_t Flags;
uint32_t freshness;
};
test_data recvData()
{
boost::interprocess::message_queue::remove("queue");
boost::property_tree::ptree pt;
test_data data;
std::istringstream buffer;
boost::interprocess::message_queue mq(boost::interprocess::open_or_create,"queue", 1, sizeof(buffer)
boost::interprocess::message_queue::size_type recvd_size;
unsigned int pri;
mq.receive(&buffer,sizeof(buffer),recvd_size,pri);
std::cout << buffer.str() << std::endl; //the segfault is there
boost::property_tree::read_json(buffer,pt);
data.action = pt.get<std::string>("action");
data.name = pt.get<std::string>("name");
data.faceID = pt.get<int>("face");
data.Flags = pt.get<uint32_t>("flags");
data.freshness = pt.get<uint32_t>("freshness");
boost::interprocess::message_queue::remove("queue");
return data;
}
int main()
{
test_data test;
test = recvData();
std::cout << test.action << test.name << test.faceID << test.Flags << test.freshness << std::endl;
}
sender.cc
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/interprocess/ipc/message_queue.hpp>
#include <sstream>
struct test_data{
std::string action;
std::string name;
int faceID;
uint32_t Flags;
uint32_t freshness;
};
int sendData(test_data data)
{
boost::property_tree::ptree pt;
pt.put("action",data.action);
pt.put("name",data.name);
pt.put("face",data.faceID);
pt.put("flags",data.Flags);
pt.put("freshness",data.freshness);
std::ostringstream buffer;
boost::property_tree::write_json(buffer,pt,false);
boost::interprocess::message_queue mq(boost::interprocess::open_only,"chiappen")
std::cout << sizeof(buffer) << std::endl;
mq.send(&buffer,sizeof(buffer),0);
return 0;
}
int main ()
{
test_data prova;
prova.action = "registration";
prova.name = "prefix";
prova.Flags = 0;
prova.freshness = 52;
sendData(prova);
}

I know it's a bit late to an answer right now, but anyway..
You can't pass an istringstream as a buffer for receive. Boost message queues only handle raw bytes and don't handle std like objects.
To make it work, you must use a char array or any buffer previously reserved with malloc.
Ex:
char buffer [1024];
mq.receive(buffer, sizeof(buffer), recvd_size, pri);
For sending it's the same, you can only send raw bytes, so you can't use ostringstream.
Hope it helps.

Related

Boost gzip how to output compressed string as text

I'm using boost gzip example code here.
I am attempting to compress a simple string test and am expecting the compressed string H4sIAAAAAAAACitJLS4BAAx+f9gEAAAA as shown in this online compressor
static std::string compress(const std::string& data)
{
namespace bio = boost::iostreams;
std::stringstream compressed;
std::stringstream origin(data);
bio::filtering_streambuf<bio::input> out;
out.push(bio::gzip_compressor(bio::gzip_params(bio::gzip::best_compression)));
out.push(origin);
bio::copy(out, compressed);
return compressed.str();
}
int main(int argc, char* argv[]){
std::cout << compress("text") << std::endl;
// prints out garabage
return 0;
}
However when I print out the result of the conversion I get garbage values like +I-. ~
I know that it's a valid conversion because the decompression value returns the correct string. However I need the format of the string to be human readable i.e. H4sIAAAAAAAACitJLS4BAAx+f9gEAAAA.
How can I modify the code to output human readable text?
Thanks
Motivation
The garbage format is not compatible with my JSON library where I will send the compressed text through.
The example site completely fails to mention they also base64 encode the result:
base64 -d <<< 'H4sIAAAAAAAACitJLS4BAAx+f9gEAAAA' | gunzip -
Prints:
test
In short, you need to also do that:
Live On Coliru
#include <boost/iostreams/copy.hpp>
#include <boost/iostreams/filter/gzip.hpp>
#include <boost/iostreams/filtering_streambuf.hpp>
#include <iostream>
#include <sstream>
#include <boost/archive/iterators/binary_from_base64.hpp>
#include <boost/archive/iterators/base64_from_binary.hpp>
#include <boost/archive/iterators/transform_width.hpp>
std::string decode64(std::string const& val)
{
using namespace boost::archive::iterators;
return {
transform_width<binary_from_base64<std::string::const_iterator>, 8, 6>{
std::begin(val)},
{std::end(val)},
};
}
std::string encode64(std::string const& val)
{
using namespace boost::archive::iterators;
std::string r{
base64_from_binary<transform_width<std::string::const_iterator, 6, 8>>{
std::begin(val)},
{std::end(val)},
};
return r.append((3 - val.size() % 3) % 3, '=');
}
static std::string compress(const std::string& data)
{
namespace bio = boost::iostreams;
std::istringstream origin(data);
bio::filtering_istreambuf in;
in.push(
bio::gzip_compressor(bio::gzip_params(bio::gzip::best_compression)));
in.push(origin);
std::ostringstream compressed;
bio::copy(in, compressed);
return compressed.str();
}
static std::string decompress(const std::string& data)
{
namespace bio = boost::iostreams;
std::istringstream compressed(data);
bio::filtering_istreambuf in;
in.push(bio::gzip_decompressor());
in.push(compressed);
std::ostringstream origin;
bio::copy(in, origin);
return origin.str();
}
int main() {
auto msg = encode64(compress("test"));
std::cout << msg << std::endl;
std::cout << decompress(decode64(msg)) << std::endl;
}
Prints
H4sIAAAAAAAC/ytJLS4BAAx+f9gEAAAA
test

How to use boost to put a stream into a buffer

I am new to Streams and Buffers implementation and I do not really know how to fix this:
#include <boost/beast/core.hpp>
#include <boost/beast/websocket.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <cstdlib>
#include <functional>
#include <iostream>
#include <string>
#include <thread>
#include <boost/property_tree/json_parser.hpp>
#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/stream.hpp>
using tcp = boost::asio::ip::tcp;
namespace websocket = boost::beast::websocket;
namespace pt = boost::property_tree;
struct DefaultMessage {
std::string command;
int value;
};
void defaultMessage(DefaultMessage *dm ,pt::ptree *root) {
root->put("command", dm->command);
root->put("value", dm->value);
}
// Echoes back all received WebSocket messages
void do_session(tcp::socket &socket) {
try {
// Construct the stream by moving in the socket
websocket::stream<tcp::socket> ws{std::move(socket)};
// Accept the websocket handshake
ws.accept();
for (;;) {
// Read a message into the buffer
boost::beast::multi_buffer buffer;
ws.read(buffer);
// Make string from buffer
auto s = boost::beast::buffers_to_string(buffer.data());
// Create ptree root
pt::ptree root;
// Create array source from s
boost::iostreams::array_source array_source(&s[0], s.size());
// Create input stream from array source
boost::iostreams::stream<boost::iostreams::array_source> input_stream(array_source);
// Read the json an populate ptree root
pt::read_json(input_stream, root);
// Discard all in buffer
buffer.consume(buffer.size());
// Construct a default message
auto message = DefaultMessage{
root.get<std::string>("command"),
root.get<int>("value")
};
defaultMessage(&message, &root);
// **This won't compile.**
pt::write_json(buffer, root);
// Echo the message back
ws.text(ws.got_text());
ws.write(buffer.data());
}
}
catch (boost::system::system_error const &se) {
// This indicates that the session was closed
if (se.code() != websocket::error::closed) {
std::cerr << "Error: " << se.code().message() << std::endl;
}
}
catch (std::exception const &e) {
std::cerr << "Error: " << e.what() << std::endl;
}
}
I want to respond with the message struct. So I guess I need to put it back in the buffer. This part is what is do not know how to do.
If efficiency is not your top concern, I'd suggest
std::ostringstream oss;
pt::write_json(oss, root);
to write to a string, and
// Echo the message back
ws.text(ws.got_text());
ws.write(boost::asio::buffer(oss.str()));
to write that buffer out.
Caveats:
this does more allocations than strictly required, probably
Boost PropertyTree is NOT a JSON library

Splitting read file C++

Lets start with that I have absolutely no experience with C++ , but I got this project to connect a POS with a verifone. We do not have the standard verifone SDK but something custom.
At fist I needed to prepair data to send to C++ and C++ will send it to the Verifone. This is where I am getting stuck, I have a .txt file, which I can read with C++ but now I need to split the data.
This is my current code:
#include "stdafx.h"
#include <sstream>
#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
string file_get_contents(const char *filename)
{
ifstream in(filename);
if (in.fail())
{
cerr << "File not found: " << filename << endl;
return "";
}
std::stringstream buffer;
buffer << in.rdbuf();
in.close();
return buffer.str();
}
int main(int argc, char **argv)
{
vector<string> strings;
string contents = file_get_contents("C:/wamp/www/cmd/config.txt");
string s;
while (contents, s, '||') {
cout << s << endl;
strings.push_back(s);
}
cout << s; // ECHO CONTENTS
std::cin.ignore(); // pause
return 0;
}
With this code my console just stays blank, no data is being displayed.
The full string I am splitting is:
"notepad://amount=10320.53||session_id=7946548443287465/"
The result that I want is to get an array that uses "amount" and "session_id" as keys and their values as value.
What is the best way of achieving this?
I used the following code to actually display the string in my console which was working:
int main(int argc, char **argv)
{
string contents = file_get_contents("config.txt");
cout << contents; // ECHO CONTENTS
std::cin.ignore(); // pause
return 0;
}
This shows how to use a regex to extract the information you want, there are a lot of online resources on how to read files properly so I left that part out.
#include <iostream>
#include <regex>
#include <unordered_map>
#include <string>
int main(int argc, char **argv)
{
std::regex pattern("amount=([[:digit:]\\.]*)\\|\\|session_id=([[:digit:]]*)");
std::smatch results;
std::unordered_map<std::string, std::string> data;
std::string contents = "notepad://amount=10320.53||session_id=7946548443287465/";
//string contents = file_get_contents("C:/wamp/www/cmd/file.txt");
if(std::regex_search(contents, results, pattern))
{
data["amount"] = results[1];
data["session_id"] = results[2];
}
std::cout << "Amount: " << data["amount"] << std::endl;
std::cout << "Seesion ID: " << data["session_id"] << std::endl;
return 0;
}

Json-cpp - how to initialize from string and get string value?

My code below crashes(Debug Error! R6010 abort() has been called). Can you help me? I'd also would like to know how to initialize the json object from a string value.
Json::Value obj;
obj["test"] = 5;
obj["testsd"] = 655;
string c = obj.asString();
Hello it is pretty simple:
1 - You need a CPP JSON value object (Json::Value) to store your data
2 - Use a Json Reader (Json::Reader) to read a JSON String and parse into a JSON Object
3 - Do your Stuff :)
Here is a simple code to make those steps:
#include <stdio.h>
#include <jsoncpp/json/json.h>
#include <jsoncpp/json/reader.h>
#include <jsoncpp/json/writer.h>
#include <jsoncpp/json/value.h>
#include <string>
int main( int argc, const char* argv[] )
{
std::string strJson = "{\"mykey\" : \"myvalue\"}"; // need escape the quotes
Json::Value root;
Json::Reader reader;
bool parsingSuccessful = reader.parse( strJson.c_str(), root ); //parse process
if ( !parsingSuccessful )
{
std::cout << "Failed to parse"
<< reader.getFormattedErrorMessages();
return 0;
}
std::cout << root.get("mykey", "A Default Value if not exists" ).asString() << std::endl;
return 0;
}
To compile: g++ YourMainFile.cpp -o main -l jsoncpp
I hope it helps ;)
Json::Reader is deprecated. Use Json::CharReader and Json::CharReaderBuilder instead:
std::string strJson = R"({"foo": "bar"})";
Json::CharReaderBuilder builder;
Json::CharReader* reader = builder.newCharReader();
Json::Value json;
std::string errors;
bool parsingSuccessful = reader->parse(
strJson.c_str(),
strJson.c_str() + strJson.size(),
&json,
&errors
);
delete reader;
if (!parsingSuccessful) {
std::cout << "Failed to parse the JSON, errors:" << std::endl;
std::cout << errors << std::endl;
return;
}
std::cout << json.get("foo", "default value").asString() << std::endl;
Kudos to p-a-o-l-o for their answer here: Parsing JSON string with jsoncpp
You can avoid using Json::CharReader and Json::CharReaderBuilder by using stringstream instead.
#include <string>
#include <sstream>
#include "jsoncpp/json/json.h"
int main() {
std::string strJson = "{\"mykey\" : \"myvalue\"}";
Json::Value obj;
// read a JSON String
stringstream(strJson) >> obj;
// get string value
std::string value1 = obj["mykey"].asString();
// or to get a default value if it isn't set
std::string value2 = obj.get("mykey", "...").asString();
return 0;
}

JSONCPP Not reading files correctly

So I recently installed JSONCPP and for some reason it gives me errors when I try this code:
#include <json.h>
#include <iostream>
#include <fstream>
int main(){
bool alive = true;
while (alive){
Json::Value root; // will contains the root value after parsing.
Json::Reader reader;
std::string test = "testis.json";
bool parsingSuccessful = reader.parse( test, root, false );
if ( !parsingSuccessful )
{
// report to the user the failure and their locations in the document.
std::cout << reader.getFormatedErrorMessages()
<< "\n";
}
std::string encoding = root.get("encoding", "UTF-8" ).asString();
std::cout << encoding << "\n";
alive = false;
}
return 0;
}
And here is the file:
{
"encoding" : "lab"
}
It says that there is a syntax error on Line 1, Column 1, and that there must be a value, object or array. Anyone know how to fix this?
EDIT: Changed to current code, from pastebin
See the Json::Reader::parse documentation. For that overload, the string needs to be the actual document, not the filename.
You can use the istream overload with a ifstream instead.
std::ifstream test("testis.json", std::ifstream::binary);
EDIT: I got it work with:
#include "json/json.h"
#include <iostream>
#include <fstream>
int main(){
bool alive = true;
while (alive){
Json::Value root; // will contains the root value after parsing.
Json::Reader reader;
std::ifstream test("testis.json", std::ifstream::binary);
bool parsingSuccessful = reader.parse( test, root, false );
if ( !parsingSuccessful )
{
// report to the user the failure and their locations in the document.
std::cout << reader.getFormatedErrorMessages()
<< "\n";
}
std::string encoding = root.get("encoding", "UTF-8" ).asString();
std::cout << encoding << "\n";
alive = false;
}
return 0;
}
#include "json/json.h"
#include <iostream>
#include <fstream>
int main(){
Json::Value root; // will contain the root value after parsing.
std::ifstream stream("testis.json", std::ifstream::binary);
stream >> root;
std::string encoding = root.get("encoding", "UTF-8" ).asString();
std::cout << encoding << "\n";
return 0;
}
Or more generally:
#include "json/json.h"
#include <iostream>
#include <fstream>
int main(){
Json::Value root; // will contain the root value after parsing.
Json::CharReaderBuilder builder;
std::ifstream test("testis.json", std::ifstream::binary);
std::string errs;
bool ok = Json::parseFromStream(builder, test, &root, &errs);
if ( !ok )
{
// report to the user the failure and their locations in the document.
std::cout << errs << "\n";
}
std::string encoding = root.get("encoding", "UTF-8" ).asString();
std::cout << encoding << "\n";
return 0;
}
http://open-source-parsers.github.io/jsoncpp-docs/doxygen/namespace_json.html
json cannot contain newlines. Try this instead:
{"encoding": "lab"}
You may need to ensure the file is saved without a final newline.
EDIT: Maybe your parser tolerates newlines, but some don't. Something to try if the other answers don't work