Here is the function that writes data to the JSON file initially:
template<typename Writer>
inline void ToJSON(Writer& writer) {
writer.StartObject();
writer.String("msg_type");
writer.Int(type);
writer.String("msg");
writer.String(msg.c_str());
writer.EndObject();
}
This message then gets parsed by this function:
static SvrMessage FromJSON(const char* json)
{
rapidjson::Document d;
qDebug() << json;
if (d.Parse<0>(json).HasParseError()) throw std::exception("Unable to parse message");
auto type = static_cast<SvrMessage::msg_type>(d["msg_type"].GetInt());
auto msg = d["msg"].GetString();
return SvrMessage(type, msg);
};
When I run the program in release mode, everything works fine and the message is parsed properly. However, in debug mode, the following line will throw an error because it is unable to parse the message.
if (d.Parse<0>(json).HasParseError()) throw std::exception("Unable to parse message");
I've looked through all of my project settings as well, and cannot find any discrepancies that would cause the parsing to fail.
Found the issue, when the JSON was being formed initially, the rapid json stringbuffer GetString() method was returning a char*, which was being freed from the stack in debug mode before it could be used. Changing the return type to a string solved the issue. Here's my fixed method that writes the JSON object:
StringBuffer sb;
Writer<StringBuffer> writer(sb);
writer.StartObject();
writer.String("msg_type");
writer.Int(msg.Type());
writer.String("msg");
writer.String(msg.Msg().c_str());
writer.EndObject();
const char* ret_val = sb.GetString();
std::string return_string(ret_val);
return return_string;
Related
I am calling a c++ method from .NET like below,
[DllImport("CPCModule.dll", EntryPoint = "FuncName", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
public static extern long FuncName([MarshalAs(UnmanagedType.LPStr)]string inFile, [MarshalAs(UnmanagedType.LPStr)]ref string OutFile);
Public Void test()
{
string altFileName = string.Empty;
string FileName = "{MyInputFullPath}"
long ret;
ret = ClassName.FuncName(FileName, ref altFileName);
........
}
The C++ code is as follows,
static ICPC* pCPC;
extern "C" long _stdcall FuncName(char* inFile, char** outFile)
{
......
hr = pCPC->UPPat2File(inFile, outFile);
return hr;
}
In the .NET code, i am passing a input file. This input file will be decoded in the method UPPat2File and put it in a output file. After the above code, the outFile is filled with proper value and the hr also return S_OK.
But after the end of the method, it was supposed to come back to .NET code (and the altFileName should be filled with the outFile). But instead it is crashing with the below exception, "An unhandled exception of type 'System.AccessViolationException' occurred in .NETdllname.dll. Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt." It is not coming back to .NET code.
I'm facing this issue on an ESP8266 (Arduino like board), but this problem is regarding c/c++, so I'm asking this here.
I have not that much experience with native languages like c/c++ and I'm facing a strange issue, which drives me crazy. So I'm using an Wemos D1 mini (ESP8266) which uses a class calles ConfigManager to read a configuration file from eeprom. The config file is formatted as json, so I'm using ArduinoJson to parse the content. I have declared a StaticJsonBuffer and pointer to a JsonObject in the header, like you can see in the code example:
//FILE: ConfigManager.h
#ifndef ConfigManager_H
#define ConfigManager_H
#include <Arduino.h>
#include <ArduinoJson.h>
#include <FS.h>
#include "Logger.h"
class ConfigManager {
public:
Settings *settings;
ConfigManager();
void read_from_eeprom();
private:
File configFile;
JsonObject *json;
StaticJsonBuffer<200> jsonBuffer;
void open_file(const char *permission);
void read_json();
void recreate_file();
void create_json();
void check_success();
void populate_settings();
void clean_up();
};
#endif
When the function read_from_eeprom is invoked, it opens the file and invokes the functionread_json:
void ConfigManager::read_json() {
size_t size = configFile.size();
Log.verbose("[ConfigManager] Config file size: %d", size);
std::unique_ptr<char[]> buf(new char[size]);
configFile.readBytes(buf.get(), size);
Log.verbose("[ConfigManager] File content: %s", buf.get());
Log.verbose("[ConfigManager] Parsing json");
json = &jsonBuffer.parseObject(buf.get());
Log.notice("[ConfigManager] Json is:");
json->printTo(Serial);
Serial.println();
}
Which is followed by a call to check_success()
void ConfigManager::check_success() {
Log.notice("[ConfigManager] Json is:");
json->printTo(Serial);
Serial.println();
bool should_recreate = true;
if (json->success()) {
Log.notice("[ConfigManager] Parsed json successfully");
auto version = json->get<const char*>("version");
if (version) {
if (strcmp(version, Settings::current_version) == 0) {
Log.notice("[ConfigManager] Config version is up2date");
should_recreate = false;
} else {
Log.warning("[ConfigManager] Config version outdated");
}
} else {
Log.warning("[ConfigManager] Invalid config file");
}
} else {
Log.warning("[ConfigManager] Config file is not valid json");
}
if (should_recreate) {
Log.notice("[ConfigManager] Recreating config file");
recreate_file();
create_json();
}
Log.notice("JSON IS: ");
json->prettyPrintTo(Serial);
Log.notice("[ConfigManager] Sucessfully read json");
}
So what I noticed is that the file content is fine. E.g. {"version":"0.2","led_count":"64"}.
Then the json is parsed, which succeeds and logs the json object, which is again {"version":"0.2","led_count":"64"}.
Afterwards the function returns, and calls check_success, which again prints the content of the json object to the log, but this time it seems that something has overwritten the JsonBuffer, which causes the json object to be corrupted. This time the logged content is {"v␂":"0.2","led_count":"64"} (with some strange unicorn characters that change as the source code changes). I'm trying to figure out whats going on for many hours now, but I'm stuck. Can someone please point me in the right direction to solve this problem? Thank you!
The full Log can be found HERE, as well as ConfigManager.h and ConfigManager.cpp
*I'd prefer write that in comments, because I don't have arduino and can't verify that my advice 100% helpful. But I can't use comments with "my reputation" :). So please don't press "minus button" if my answer didn't help... *
According to that it seems you need to keep original json string while you using json buffer.
Keep the JSON string in memory long enough
The library never make memory duplication. This has an important implication on string
values, it means that the library will return pointer to chunks of the
string.
For instance, let’s imagine that you parse ["hello","world"], like
this:
char[] json = "[\"hello\",\"world\"]";
StaticJsonBuffer<32> buffer;
JsonArray& array = buffer.parseArray(json);
const char* first = array[0];
const char* second = array[1];
In that
case, both first and second are pointers to the content of the
original string json. So this will only work if json is still in
memory.
So, it make sense try make std::unique_ptr buf a class member (same as StaticJsonBuffer) and check how it works.
BTW, IMO std::vector will be more suitable there... And I'm not sure that unique_ptr deletes arrays properly.
I am new to protobuf (C++) and my code fails during parse of my messages. How can I get more details about the errors that occurred?
Example
The following snippet illustrates the problem:
const bool ok=my_message.ParseFromCodedStream(&stream);
if(ok){
std::cout<< "message parsed. evidence:\n"<< my_message.DebugString();
}
else{
std::cerr<< "error parsing protobuf\n";
//HOW CAN I GET A REASON FOR THE FAILURE HERE?
}
If you look inside protobuf code, you will find it's using its own logging system - based on macros. By default all these messages goes to stderr, but you can capture them in your program with SetLogHandler():
typedef void LogHandler(LogLevel level, const char* filename, int line,
const std::string& message);
The possible solution is to make your own errno-like mechanism (sorry for C++11-ishness):
typedef LogMessage std::tuple<LogLevel, std::string, int, std::string>; // C++11
typedef LogStack std::list<LogMessage>;
namespace {
LogStack stack;
bool my_errno;
} // namespace
void MyLogHandler(LogLevel level, const char* filename, int line,
const std::string& message) {
stack.push_back({level, filename, line, message}); // C++11.
my_errno = true;
}
protobuf::SetLogHandler(MyLogHandler);
bool GetError(LogStack* my_stack) {
if (my_errno && my_stack) {
// Dump collected logs.
my_stack->assign(stack.begin(), stack.end());
}
stack.clear();
bool old_errno = my_errno;
my_errno = false;
return old_errno;
}
And use it in your code:
...
else {
std::cerr<< "error parsing protobuf" << std::endl;
LogStack my_stack;
if (GetError(&my_stack) {
// Handle your errors here.
}
}
The main drawback of my sample code - it doesn't work well with multiple threads. But that can be fixed on your own.
Sometimes error information will be printed to the console, but that's it. There's no way to get extra error info through the API.
That said, there are only two kinds of errors anyway:
A required field was missing. (Information should be printed to the console in this case.)
The data is corrupt. It was not generated by a valid protobuf implementation at all -- it's not even a different type of protobuf, it's simply not a protobuf.
If you are seeing the latter case, you need to compare your data on the sending and receiving side and figure out why it's different. Remember that the data you feed to the protobuf parser not only must be the same bytes, but it must end at the same place -- the protobuf parser does not know where the message ends except by receiving EOF. This means that if you are writing multiple messages to a stream, you need to write the size before the data, and make sure to read only that many bytes on the receiving end before passing on to the protobuf parser.
I have been trying to parse an XML file using boost's property tree, but every time I want to get the value of a string it throws an access violation exception. It works fine with integers so I'm a bit confused.
Here's some of the code:
class Config
{
char * test;
int test2;
public:
Config();
};
Config::Config(void)
{
boost::property_tree::ptree pt;
boost::property_tree::xml_parser::read_xml("config.xml", pt);
try
{
test = pt.get<char*>("base.char");
test2 = pt.get<int>("base.int");
}
catch(std::exception e)
{
//something wasn't specified
}
}
And the XML file:
<base>
<char>test</char>
<int>10</int>
</base>
First I thought it's because I didn't allocate space for the string but neither malloc() nor new char[] helped.
Any help would be appreciated. Thanks in advance :)
Based on this tutorial I think you need to use std::string instead of char* to get string values.
So the line test = pt.get<char*>("base.char"); would then be test = pt.get<std::string>("base.char");. (Assuming you change test's type to std::string as well).
I'm using the Xerces C++ DOM parser to read some XML files in a Visual C++ project. I have a class with a parse() method that is supposed to read and validate my XML source file. This is what the method looks like:
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/dom/DOM.hpp>
#include <xercesc/parsers/XercesDOMParser.hpp>
#include <xercesc/framework/LocalFileInputSource.hpp>
using namespace std;
XERCES_CPP_NAMESPACE_USE
unsigned long RulesParser::parse( const wstring &xmlFile )
{
if( parserInitialized_ == false ) {
try {
XMLPlatformUtils::Initialize(); /* initialize xerces */
} catch( XMLException const &e ) {
return Status::PARSER_INIT_FAIL;
}
}
parserInitialized_ = true; /* indicate xerces has been
successfully initialized */
if( pDOMParser_ != NULL ) {
delete pDOMParser_;
}
pDOMParser_ = new XercesDOMParser; /* create a DOM parser instance */
/* set xerces options */
pDOMParser_->setDoNamespaces( true ); /* enable namespace processing */
pDOMParser_->setDoSchema( true ); /* enable schema processing */
pDOMParser_->setValidationScheme( XercesDOMParser::Val_Always ); /* parser always validates */
pDOMParser_->setValidationSchemaFullChecking( true ); /* enable full schema checking */
auto_ptr< LocalFileInputSource > srcFile; /* XML source file loader */
try {
srcFile.reset( new LocalFileInputSource( xmlFile.c_str() ) );
} catch( const XMLException &e ) {
return Status::XML_SOURCE_LOAD_ERROR;
}
/* parse the file */
try {
pDOMParser_->parse( *srcFile );
} catch( const XMLException &e ) {
return Status::XML_SOURCE_PARSE_ERROR;
} catch( const DOMException &e ) {
return Status::XML_SOURCE_PARSE_DOM_ERROR;
}
return Status::OK;
}
The documentation for LocalFileInputSource says the constructor will throw an XMLException if the path doesn't resolve to a file. However, I can call this method with any arbitrary string and it executes to the end without any exceptions being raised. What am I doing wrong?
Also, the documentation for XercesDOMParser::parse() says a SAXException is one of the types of exceptions that it can throw. I find this confusing because from what I understand DOM and SAX parsers are 2 different animals, so why would the DOM parser throw a SAX exception?
See ErrorHandler documentation.
You must declare and define a class that inherits from ErrorHandler and implements its virtual methods (or you can extend the HandlerBase class).
Then you must call setErrorHandler on your parser instance passing an instance of your error handler, i.e. pDOMParser_->setErrorHandler(your_handler_instance).
Example usage from Xerces-C++ trunk samples: rows 231-233 of SAXPrint.cpp.
Update: example of custom error handler below.
#include <iostream>
#include <xercesc/sax/HandlerBase.hpp>
XERCES_CPP_NAMESPACE_USE
class CustomErrorHandler : public HandlerBase
{
public:
CustomErrorHandler() {}
void error(const SAXParseException& e)
{
handler(e);
}
void fatalError(const SAXParseException& e)
{
handler(e);
}
void warning(const SAXParseException& e)
{
handler(e);
}
private:
void handler(const SAXParseException& e)
{
char* message = XMLString::transcode(e.getMessage());
cerr << "line " << e.getLineNumber()
<< ", column " << e.getColumnNumber()
<< " -> " << message << "\n\n";
XMLString::release(&message);
}
};
I don't think that the documentation says what you think it does, it says it will; throw:
XMLException If the path is relative
and doesn't properly resolve to a
file.
Your task, should you choose to accept it, is to find out what "relative" means. I'm afraid I I haven't used Xerces for years (though it is quite competent) - I prefer to use small, simple SAX parsers to build my own models rather than use a DOM, and can't remember how the filename stuff works.
And I think that the reason that you might get SAX exceptions is that Xerces uses SAX to build its DOM.
The 2.8 Doc (you have linked) says,
XMLException If the path is relative and doesn't properly resolve to a file
are you actually using a relative path?
maybe this used to be the case for some platform specific cases, but I can't see where this is raised in Xercese 2.7 (code I happen to have).
Looking at LocalFileFormatTarget it can throw an exception for 'CouldNotOpenFile', but it isn't documented as raising an exception.
What version of xerces are you using?
Opening the file for reading/parsing looks like it might raise an exception for the missing file of type 'CouldNotReadFromFile'. But that could be caught up with the error handling as Vanni is talking about.
I know this is old, but yes indeed I found that XercesDOMParser throws a SAXParseException if the file is not found. No custom error handler needed, just catch that exception.