I was testing the RapidJSON library earlier today to see if I could parse a document with nested values, and for some reason I couldn't come up with a solution to the errors I was getting. I searched around Google and Stack Overflow for an hour or two and couldn't find a fix. Here is the code along with the errors:
main.cpp:
#include <iostream>
#include <SFML/Graphics.hpp>
#include "rapidjson/document.h"
#include "include.hpp"
int main() {
unsigned int input = 1;
tile output;
output = LoadTile("../locations.json", input);
std::cout << output.x << std::endl;
return 0;
}
load.cpp
#include <iostream>
#include "rapidjson/document.h"
#include "rapidjson/filereadstream.h"
#include "include.hpp"
using namespace rapidjson;
tile LoadTile(std::string fileName, unsigned int number) {
FILE* file = fopen(fileName.c_str(), "r");
char buffer[2048];
FileReadStream stream(file, buffer, 2048);
Document doc;
doc.ParseStream(stream);
tile output;
Value& tileNumber = doc[number];
if(!tileNumber.IsObject()) {
output.overflow = true;
output.x = 0;
output.y = 0;
output.type = "\0";
}else{
output.x = tileNumber[0]["x"].GetInt();
output.y = tileNumber[0]["y"].GetInt();
output.type = tileNumber[0]["type"].GetString();
}
return output;
}
include.hpp:
#include <iostream>
#include <SFML/Graphics.hpp>
#include "rapidjson/document.h"
struct tile {
int x;
int y;
std::string type;
bool overflow = false;
};
tile LoadTile(std::string fileName, unsigned int number);
CMakeLists.txt:
cmake_minimum_required(VERSION 2.6)
project(test)
set(EXECUTABLE_NAME "test")
add_executable(${EXECUTABLE_NAME} main.cpp load.cpp include.hpp)
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake_modules" ${CMAKE_MODULE_PATH})
install(TARGETS ${EXECUTABLE_NAME} DESTINATION bin})
locations.json:
{
1:[
{"x":32},
{"y":32},
{"type":"water_c"}
]
}
Errors:
test: /home/.../rapidjson/document.h:1547:rapidjson::GenericValue<Encoding, Allocator>::operator[](rapidjson::SizeType) [with Encoding = rapidjson::UTF8<>; Allocator = rapidjson::MemoryPoolAllocator<>; rapidjson::SizeType = unsigned int]: Assertion `IsArray()' failed.
Aborted (core dumped)
I know it's not the JSON formatting, I've tried everything. Unless there's something really wrong with it. I'm running this on Xubuntu 16.10. Thanks to anyone that can help.
Your JSON is invalid. In JSON, keys must be strings, written with double quotes. More details here.
I suggest using JSONLint to validate JSON strings.
The valid JSON looks like this (1 in double quotes):
{
"1": [{
"x": 32
}, {
"y": 32
}, {
"type": "water_c"
}]
}
Related
I am looking for some function or a way that would return HMAC SHA256 hash in C++ using secret key. I have seen documentation of Crypto++ and OpenSSL but it does not accept an extra parameter of secret key for computation. Can someone help me by providing some info, code snippets or links.
You can use POCO library
Sample code:
class SHA256Engine : public Poco::Crypto::DigestEngine
{
public:
enum
{
BLOCK_SIZE = 64,
DIGEST_SIZE = 32
};
SHA256Engine()
: DigestEngine("SHA256")
{
}
};
Poco::HMACEngine<SHA256Engine> hmac{secretKey};
hmac.update(string);
std::cout << "HMACE hex:" << Poco::DigestEngine::digestToHex(hmac.digest()) << std::endl;// lookout difest() calls reset ;)
Sample integration with POCO using cmake install:
mkdir build_poco/
cd build_poco/ && cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=./install ../poco/
CMakeLists.txt
CMAKE_MINIMUM_REQUIRED(VERSION 3.8)
PROJECT(SamplePoco)
SET(CMAKE_CXX_STANDARD 14)
SET(SOURCE_FILES
src/main.cpp
)
SET(_IMPORT_PREFIX lib/build_poco/install)
INCLUDE(lib/build_poco/install/lib/cmake/Poco/PocoFoundationTargets.cmake)
INCLUDE(lib/build_poco/install/lib/cmake/Poco/PocoNetTargets.cmake)
INCLUDE(lib/build_poco/install/lib/cmake/Poco/PocoJSONTargets.cmake)
INCLUDE(lib/build_poco/install/lib/cmake/Poco/PocoXMLTargets.cmake)
INCLUDE(lib/build_poco/install/lib/cmake/Poco/PocoCryptoTargets.cmake)
INCLUDE(lib/build_poco/install/lib/cmake/Poco/PocoUtilTargets.cmake)
INCLUDE(lib/build_poco/install/lib/cmake/Poco/PocoNetSSLTargets.cmake)
ADD_EXECUTABLE(SamplePoco ${SOURCE_FILES})
TARGET_LINK_LIBRARIES(SamplePoco
Poco::Foundation
Poco::Crypto
Poco::Util
Poco::JSON
Poco::NetSSL
)
TARGET_INCLUDE_DIRECTORIES(SamplePoco PUBLIC src/)
Sample implementation used here: https://github.com/gelldur/abucoins-api-cpp
Following is a sample of function to generate SHA256-HMAC using Crypto++
#include <string>
#include <string_view>
#include <cryptopp/filters.h>
using CryptoPP::StringSink;
using CryptoPP::StringSource;
using CryptoPP::HashFilter;
#include <cryptopp/hmac.h>
using CryptoPP::HMAC;
#include <cryptopp/sha.h>
using CryptoPP::SHA256;
std::string CalcHmacSHA256(std::string_view decodedSecretKey, std::string_view request)
{
// Calculate HMAC
HMAC<SHA256> hmac(reinterpret_cast<CryptoPP::byte const*>(decodedSecretKey.data()), decodedSecretKey.size());
std::string calculated_hmac;
auto sink = std::make_unique<StringSink>(calculated_hmac);
auto filter = std::make_unique<HashFilter>(hmac, sink.get());
sink.release();
StringSource(reinterpret_cast<CryptoPP::byte const*>(request.data()), request.size(), true, filter.get()); // StringSource
filter.release();
return calculated_hmac;
}
#include <iostream>
int main() {
std::cout << CalcHmacSHA256("key", "data");
}
The source is CME iLink2 specification
For consistency, following is a sample of function to generate SHA256-HMAC using OpenSSL
#include <openssl/sha.h>
#include <openssl/hmac.h>
#include <string>
#include <string_view>
#include <array>
std::string CalcHmacSHA256(std::string_view decodedKey, std::string_view msg)
{
std::array<unsigned char, EVP_MAX_MD_SIZE> hash;
unsigned int hashLen;
HMAC(
EVP_sha256(),
decodedKey.data(),
static_cast<int>(decodedKey.size()),
reinterpret_cast<unsigned char const*>(msg.data()),
static_cast<int>(msg.size()),
hash.data(),
&hashLen
);
return std::string{reinterpret_cast<char const*>(hash.data()), hashLen};
}
For the record, I like Crypto++ better as in case of Crypto++ generated binary is smaller. The drawback is that Crypto++ does not have a CMake module.
OpenSSL docs for HMAC, clearly state the requirement of a 'key' as part of context initialization.
int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, int key_len,
const EVP_MD *md, ENGINE *impl);
HMAC() computes the message authentication code of the n bytes at d
using the hash function evp_md and the key key which is key_len bytes
long.
You can use cpp-cryptlite to generate HMAC SHA256 hash, Following is the code snippet:
std::string src_str = "abcdefg";
std::string secret_key = "xxxxxx"; // this value is an example
boost::uint8_t digest[32]; // cryptlite::sha256::HASH_SIZE
cryptlite::hmac<cryptlite::sha256>::calc(src_str, secret_key, digest);
// and digest is the output hash
I had to modify #DmytroOvdiienko's answer a bit to get hexadecimal output:
#include <iomanip>
...
std::string CalcHmacSHA256(std::string_view decodedKey, std::string_view msg)
{
std::array<unsigned char, EVP_MAX_MD_SIZE> hash;
unsigned int hashLen;
HMAC(
EVP_sha256(),
decodedKey.data(),
static_cast<int>(decodedKey.size()),
reinterpret_cast<unsigned char const*>(msg.data()),
static_cast<int>(msg.size()),
hash.data(),
&hashLen
);
std::stringstream out;
for (unsigned int i=0; i < hashLen; i++) {
out << std::setfill('0') << std::setw(2) << std::right << std::hex << (int)hash.data()[i];
}
return out.str();
}
int main(int, char**) {
std::string key = "ESiFg448MqOmhQyxbt6HEHHPnAA1OE8nX0o9ANIVMIvWLISQS0MivDrkZvnBxMEI";
std::string msg = "foo";
std::string_view key_view{key};
std::string_view msg_view{msg};
std::cout << CalcHmacSHA256(key_view, msg_view) << std::endl;
}
The <iomanip>, setfill, setw, right are needed to make sure single-digit hex values are prefixed with a 0. An alternative is to use boost:
#include <boost/format.hpp>
...
out << boost::format("%02x") % (int)hash.data()[i];
I am having trouble with this library... My code works fine, the parsers/creator works too, but an err appears, I don't know why:
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
#include <boost/thread.hpp>
#include <string>
#include <exception>
#include <set>
#include <iostream>
#include "journal.h"
unsigned short port = 2013;
unsigned short maxConnec = 250;
unsigned short fPort() {return port;}
unsigned short fMaxConnec() {return maxConnec;}
bool load(const std::string &file)
{
using boost::property_tree::ptree;
ptree objectXML;
std::cout << "bbb";
read_xml(file, objectXML);
std::cout << "aaa";
if (file.length() == 0) // By the way, no way to do that better ? "if file doesn't exist..."
{
return 0;
}
else
{
port = objectXML.get<unsigned short>("configuration.server.port");
maxConnec = objectXML.get<unsigned short>("configuration.server.maxConnections");
return 1;
}
}
bool save(const std::string &file)
{
try
{
using boost::property_tree::ptree;
ptree objectXML;
objetXML.put("configuration.server.port", port);
objetXML.put("configuration.server.maxConnections", maxConnec);
write_xml(file, objectXML, std::locale(), boost::property_tree::xml_writer_make_settings<ptree::key_type>(' ', 4));
return 1;
}
catch (std::exception e)
{
return 0;
}
}
void generate()
{
std::string file = "configuration.xml";
try{
if (!load(fichier))
{
save(file);
}
}
catch (std::exception &e)
{
load(file);
}
}
Get a bad path, I totally don't know why because when I try to read data I can and it gets the data in configuration.xml even if I change it...
The ptree_bad_path exception is raised from the throwing version of get and signals that "configuration.server.port" or "configuration.server.maxConnections" path to the XML element doesn't exist.
The error isn't related to the configuration.xml file path.
So you should check the element name or, for optional elements, use the default-value / optional-value version of get.
I want to:
write a vtkMultiBlockDataSet, containing a vtkStringArray, to a
file
load it
add some more Blocks
write it again to a file
You can get a simplified code from here.
The program produces segfaults, but only if the writers are set to binary mode, and only if the data exceeds a certain size. In ASCII mode, everything is fine.
This might be related.
Can you confirm that behaviour? What am I doing wrong? And if it is a bug, how can I work around?
Thanks very much for any help.
EDIT: I directly add the example code (the same as from the given link above) here:
#include <vtkSmartPointer.h>
#include <vtkPolyData.h>
#include <vtkPointData.h>
#include <vtkMultiBlockDataSet.h>
#include <vtkXMLMultiBlockDataWriter.h>
#include <vtkXMLMultiBlockDataReader.h>
#include <vtkStringArray.h>
#include <sys/stat.h>
#include <sstream>
int main(int, char *[])
{
/**
* notes:
* -> it works with ascii writer configuration (BINARY=0) for any M,N.
* -> with binary writer configuration (BINARY=1), it segfaults for higher M,N
* -> {N=100,M=1} works. {N=100,M=10} fails. {N=1000,M=1} fails.
*/
const unsigned int N = 1000; // number of points
const unsigned int M = 1; // number of characters in the string
const bool BINARY = 1; // 0=ascii, 1=binary
std::string filename = "output/test_output.vtm";
std::stringstream mystring;
struct stat buffer;
vtkSmartPointer<vtkPoints> points =
vtkSmartPointer<vtkPoints>::New();
vtkSmartPointer<vtkStringArray> stringAttribute =
vtkSmartPointer<vtkStringArray>::New();
vtkSmartPointer<vtkPolyData> mypolydata =
vtkSmartPointer<vtkPolyData>::New();
vtkSmartPointer<vtkMultiBlockDataSet> multiBDS =
vtkSmartPointer<vtkMultiBlockDataSet>::New ();
vtkSmartPointer<vtkXMLMultiBlockDataWriter> writer1 =
vtkSmartPointer<vtkXMLMultiBlockDataWriter>::New();
vtkSmartPointer<vtkMultiBlockDataSet> multiBDS_read =
vtkSmartPointer<vtkMultiBlockDataSet>::New ();
vtkSmartPointer<vtkXMLMultiBlockDataReader> reader =
vtkSmartPointer<vtkXMLMultiBlockDataReader>::New();
vtkSmartPointer<vtkXMLMultiBlockDataWriter> writer2 =
vtkSmartPointer<vtkXMLMultiBlockDataWriter>::New();
stringAttribute->SetNumberOfComponents(1);
reader->SetFileName(filename.c_str());
writer1->SetFileName(filename.c_str());
writer2->SetFileName(filename.c_str());
if (BINARY) {
writer1->SetDataModeToBinary(); //segfault
writer2->SetDataModeToBinary(); // segfault
}
else {
writer1->SetDataModeToAscii(); // works
writer2->SetDataModeToAscii(); // works
}
//create output folder and clear content:
std::string outfolder = "output/";
mkdir(outfolder.c_str(), 0777);
system("exec rm -r output/*");
// create some points:
for (int k=0; k<N; ++k) {
points->InsertNextPoint(0.0, 0.0, 0.0);
}
// create some string attributes:
for (int k=0; k<N; ++k) {
for (int i=0; i<M; ++i) {
mystring << "x";
}
stringAttribute->InsertNextValue(mystring.str().c_str());
}
// assemble and write to file:
mypolydata->SetPoints(points);
mypolydata->GetPointData()->AddArray(stringAttribute);
multiBDS->SetBlock(0,mypolydata);
writer1->SetInput(multiBDS);
writer1->Write();
//now read the file again:
if (stat (filename.c_str(), &buffer) == 0) {
reader->Update();
multiBDS_read->ShallowCopy(reader->GetOutput());
}
else {
std::cout<<"file not found."<<std::endl;
}
// assemble and write again:
//system("exec rm -r output/*"); // remove original file; not necessary
multiBDS_read->SetBlock(multiBDS->GetNumberOfBlocks(),mypolydata);
writer2->SetInput(multiBDS_read);
writer2->Write();
return EXIT_SUCCESS;
}
If you use cmake, please use the following CMakeLists.txt:
cmake_minimum_required(VERSION 2.8)
PROJECT(vtk_weird_segfault)
find_package(VTK REQUIRED)
include(${VTK_USE_FILE})
add_executable(vtk_weird_segfault MACOSX_BUNDLE vtk_weird_segfault)
if(VTK_LIBRARIES)
target_link_libraries(vtk_weird_segfault ${VTK_LIBRARIES})
else()
target_link_libraries(vtk_weird_segfault vtkHybrid vtkWidgets)
endif()
I try to serialize to a binary archive then load this archive using the code show below. The issue I have is that when loading the file, I get an "input stream error".
#include "project.h"
// Std
#include <fstream>
// Boost
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/algorithm/string.hpp>
// Qt
#include <QtGui/QMessageBox>
#include <QFileInfo>
#include <QDir>
BOOST_CLASS_VERSION(Tools::CommentModel, 1)
using namespace std;
namespace Sawe {
template<class Archive>
void runSerialization(Archive& ar, Project*& project, QString path)
{
const unsigned magicConst=65553;
unsigned magic = magicConst;
ar & BOOST_SERIALIZATION_NVP(magic);
if (magic != magicConst)
throw std::ios_base::failure("Wrong project type");
ar & BOOST_SERIALIZATION_NVP(project);
}
bool Project::
save()
{
if (project_filename_.empty()) {
return saveAs();
}
try
{
std::ofstream ofs(project_filename_.c_str());
assert(ofs.good());
boost::archive::binary_oarchive xml(ofs);
Project* p = this;
runSerialization(xml, p, project_filename_.c_str());
p->is_modified_ = false;
}
catch (const std::exception& x)
{
QString msg = "Error: " + QString::fromStdString(vartype(x)) +
"\nDetails: " + QString::fromLocal8Bit(x.what());
QMessageBox::warning( 0, "Can't save file", msg );
TaskInfo("======================\nCan't save file\n%s\n======================", msg.toStdString().c_str());
}
return true;
}
#endif
pProject Project::
openProject(std::string project_file)
{
std::ifstream ifs(project_file.c_str());
boost::archive::binary_iarchive xml(ifs);
Project* new_project = 0;
runSerialization(xml, new_project, project_file.c_str());
new_project->project_filename_ = project_file;
new_project->updateWindowTitle();
new_project->is_modified_ = false;
pProject project( new_project );
return project;
}
}
Any idea ?
Thanks in advance for your help!
Cheers
I had the same problem, when i added the binary flag to the fstream ctors everything worked.
I'm porting a small C++ console application from windows to linux, GCC 4.3.2. When compiling I get strange error that I'm unable to solve.
Labels.cpp: In function ‘void DumpSymbols()’:
Labels.cpp:68: error: invalid conversion from ‘int’ to ‘std::_Ios_Openmode’
Labels.cpp:68: error: initializing argument 2 of ‘std::basic_ofstream<_CharT, _Traits>::basic_ofstream(const char*, std::_Ios_Openmode) [with _CharT = char, _Traits = std::char_traits<char>]’
Labels.cpp:
#include <string>
#include <fstream>
#include <iostream>
#include "stdafx.h"
using namespace std;
#include "Opcodes.h"
#include "Labels.h"
Label LABELS[1024];
int labelcounter = 0;
int OffsetCounter = 0;
void AddLabel(string name, int line)
{
LABELS[labelcounter].name = name;
LABELS[labelcounter].line = line;
LABELS[labelcounter].offset = OffsetCounter;
printf("Adding label: %s[0x%X]\n", name.c_str(), OffsetCounter);
labelcounter++;
}
bool IsLabel(string name)
{
for(int i=0;i<labelcounter;i++)
{
if (LABELS[i].name.compare(name) == 0)
{
return true;
}
}
return false;
}
int GetOffset(string lbl)
{
for(int i=0;i<labelcounter;i++)
{
if (LABELS[i].name.compare(lbl) == 0)
{
printf("Refers to label '%s':0x%X\n", lbl.c_str(), LABELS[i].offset);
return LABELS[i].offset;
}
}
return -1;
}
void DumpSymbols()
{
ofstream mapfile("symbols.map", ios::out|ios::beg); //this line causes error
//mapfile.write(
char numbuf1[32];
itoa(labelcounter, numbuf1, 10);
mapfile.write((string(numbuf1) + "\n").c_str(), strlen(numbuf1)+1);
for(int i=0;i<labelcounter;i++)
{
string dump;
char numbuf[32];
itoa(LABELS[i].offset, numbuf, 10);
dump = string(LABELS[i].name) + "\t" + string(numbuf) + "\n";
mapfile.write(dump.c_str(), strlen(dump.c_str()));
}
}
stdafx.h:
#pragma once
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <cstdlib>
Thanks.
Just remove "|ios::beg":
ofstream mapfile("symbols.map", ios::out);
It's type is ios_base::seekdir, which is not an opening mode; it's for seeking to a position. You'll automatically be at the beginning anyway.
Is ios::beg really a valid value for the mode parameter of the ofstream constructor?
According to http://www.cplusplus.com/reference/iostream/ofstream/ofstream.html it's not.
I guess what happened is that you accidentally borrowed it from a call to ofstream::seekg (where it is a valid parameter) to enforce that the writing will start from the beginning of the file rather than the end of it.
If you are trying to force the file to be completely replaced if it already existed, try using ios::trunc instead of ios::beg.