Hjson for C++

Overview

hjson-cpp

Build Status C++ license

Hjson Intro

{
  # specify rate in requests/second (because comments are helpful!)
  rate: 1000

  // prefer c-style comments?
  /* feeling old fashioned? */

  # did you notice that rate doesn't need quotes?
  hey: look ma, no quotes for strings either!

  # best of all
  notice: []
  anything: ?

  # yes, commas are optional!
}

To quickly get up and running with a new C++ application project using Hjson configuration files, use the hjson-cpp-example template repository.

For other platforms see hjson.github.io.

Compiling

The easiest way to use hjson-cpp is to simply include all of the files from the folders src and include into your own project. The only requirement is that your compiler fully supports C++11.

GCC 4.8 has the C++11 headers for regex, but unfortunately not a working implementation, so for GCC at least version 4.9 is required.

Cmake

The second easiest way to use hjson-cpp is to either add it as a subfolder to your own Cmake project, or to install the Hjson lib on your system by using Cmake. Works on Linux, Windows and MacOS. Your mileage may vary on other platforms. Cmake version 3.10 or newer is required.

Cmake subfolder

Instead of building a lib, you can choose to include Hjson as a subfolder in your own Cmake project. That way, Hjson will be built together with your own project, with the same settings. In Visual Studio that also means the Hjson source code will be visible in a project in your own solution. Example CMakeLists.txt for your own project, if your executable is called myapp:

add_executable(myapp main.cpp)

add_subdirectory(../hjson-cpp ${CMAKE_BINARY_DIR}/hjson)
target_link_libraries(myapp hjson)

Cmake options

A list of Hjson Cmake options and their default values:

BUILD_SHARED_LIBS=OFF
BUILD_WITH_STATIC_CRT=  # Can be set to Yes or No. Only used on Windows.
CMAKE_BUILD_TYPE=  # Set to Debug for debug symbols, or Release for optimization.
CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS=ON  # Needed for shared libs on Windows. Introduced in Cmake 3.4.
HJSON_ENABLE_INSTALL=OFF
HJSON_ENABLE_TEST=OFF
HJSON_ENABLE_PERFTEST=OFF
HJSON_NUMBER_PARSER=StringStream  # Possible values are StringStream, StrToD and CharConv.
HJSON_VERSIONED_INSTALL=OFF  # Use version suffix on header and lib folders.

Linux lib

  1. First create a Makefile using Cmake.
$ cd hjson-cpp
$ mkdir build
$ cd build
$ cmake .. -DHJSON_ENABLE_TEST=ON -DHJSON_ENABLE_INSTALL=ON -DCMAKE_BUILD_TYPE=Release
  1. Then you can optionally run the tests.
$ make runtest
  1. Install the include files and lib to make them accessible system wide (optional).
$ sudo make install
  1. If you haven't done either step 2 or step 3, you must at least compile the code into a library by calling make.
$ make

Windows lib

The Cmake GUI is the most convenient way to generate a Visual Studio solution. Make sure that you tick the boxes for HJSON_ENABLE_TEST and HJSON_ENABLE_INSTALL if you want to run tests or make the Hjson lib accessible system wide.

After generating the solution and opening it in Visual Studio you can run the tests by right-clicking the project runtest and selecting Build. The test results are shown in the Output window (the same window that shows the build result).

In order to make the Hjson lib accessible system wide you must run Visual Studio as an administrator. In Windows 7 you can do that by right-clicking on the Visual Studio icon in the start menu and selecting Run as an administrator. Then open the Hjson solution, right-click the INSTALL project and select Build. Make sure to do that for both the Debug and Release targets.

Linking

The hjson lib can now be used in your own Cmake projects, for example like this if your application is called myapp:

add_executable(myapp main.cpp)

find_package(hjson REQUIRED)
target_link_libraries(myapp hjson)

On Windows it's important that you compiled or installed both Debug and Release Hjson libraries before Cmake-generating your own project. Otherwise the target type you didn't compile/install will not be available in your own project.

If you did not install Hjson system wide, you can still use it like in the example above if you specify the location of the Hjson build when running Cmake for your own project. Example:

$ cmake .. -Dhjson_DIR=../hjson-cpp/build

Usage in C++

Functions

The most important functions in the Hjson namespace are:

std::string Marshal(const Value& v, const EncoderOptions& options = EncoderOptions());

void MarshalToFile(const Value& v, const std::string& path,
  const EncoderOptions& options = EncoderOptions());

Value Unmarshal(const std::string& data,
  const DecoderOptions& options = DecoderOptions());

Value UnmarshalFromFile(const std::string& path,
  const DecoderOptions& options = DecoderOptions());

Value Merge(const Value& base, const Value& ext);

Marshal is the output-function, transforming an Hjson::Value tree (represented by its root node) to a string that can be written to a file.

MarshalToFile writes the output directly to a file instead of returning a string.

Unmarshal is the input-function, transforming a string to a Hjson::Value tree. The string is expected to be UTF8 encoded. Other encodings might work too, but have not been tested. The function comes in three flavors: char pointer with or without the dataSize parameter, or std::string. For a char pointer without dataSize parameter the data parameter must be null-terminated (like all normal strings). All of the unmarshal functions throw an Hjson::syntax_error exception if the input string is not fully valid Hjson syntax.

UnmarshalFromFile reads directly from a file instead of taking a string as input.

Merge returns an Hjson::Value tree that is a cloned combination of the input Hjson::Value trees base and ext, with values from ext used whenever both base and ext has a value for some specific position in the tree. The function is convenient when implementing an application with a default configuration (base) that can be overridden by input parameters (ext).

Stream operator

An Hjson::Value can be inserted into a stream, for example like this:

Hjson::Value myValue = 3.0;
std::cout << myValue;

The stream operator marshals the Hjson::Value using standard options, so this code will produce the exact same result, but uses more RAM since the full output is temporarily stored in a string instead of being written directly to the stream:

Hjson::Value myValue = 3.0;
std::cout << Hjson::Marshal(myValue);

If you want to use custom encoding options they can be communicated like this:

Hjson::Value myValue = 3.0;
Hjson::EncoderOptions encOpt;
encOpt.omitRootBraces = true;
std::cout << Hjson::StreamEncoder(myValue, encOpt);

Likewise for reading from a stream. Hjson will consume the entire stream from its current position, and throws an Hjson::syntax_error exception if not all of the stream (from its current position) is valid Hjson syntax.

Hjson::Value myValue;
std::cin >> myValue;
Hjson::Value myValue;
Hjson::DecoderOptions decOpt;
decOpt.comments = false;
std::cin >> Hjson::StreamDecoder(myValue, decOpt);

Hjson::Value

Input strings are unmarshalled into a tree representation where each node in the tree is an object of the type Hjson::Value. The class Hjson::Value mimics the behavior of Javascript in that you can assign any type of primitive value to it without casting. Existing Hjson::Value objects can change type when given a new assignment. Examples:

Hjson::Value myValue(true);
Hjson::Value myValue2 = 3.0;
myValue2 = "A text.";

These are the possible types for an Hjson::Value:

Undefined
Null
Bool
Double
Int64
String
Vector
Map

The default constructor creates an Hjson::Value of the type Hjson::Type::Undefined.

An Hjson::Value can behave both like a vector (array) and like a map (Object in Javascript):

Hjson::Value map;
map["down1"]["down2"]["down3"] = "three levels deep!";
map["down1"]["number"] = 7;

Hjson::Value arr;
arr.push_back("first");
std::string myString = arr[0];

If you try to access a map element that doesn't exist, an Hjson::Value of type Hjson::Type::Undefined is returned. But if you try to access a vector element that doesn't exist, an Hjson::index_out_of_bounds exception is thrown.

In order to make it possible to check for the existence of a specific key in a map without creating an empty element in the map with that key, a temporary object of type Hjson::MapProxy is returned from the string bracket operators:

MapProxy operator[](const std::string&);
MapProxy operator[](const char*);

The Hjson::MapProxy desctructor creates or updates an element in the map if needed. Therefore the Hjson::MapProxy copy and move constructors are private, so that objects of that class do not stay alive longer than a single line of code. The downside of that is that you cannot store the returned value in an auto declared variable.

Hjson::Value map;

// This statement won't compile.
auto badValue = map["key"];

// This statement will compile just fine.
Hjson::Value goodValue = map["key"];

Because of Hjson::MapProxy, you cannot get a reference to a map element from the string bracket operator. You can however get such a reference from the integer bracket operator, or from the function Hjson::Value::at(const std::string& key). Both the integer bracket operator and the at function throw an Hjson::index_out_of_bounds exception if the element could not be found.

Hjson::Value map;
map["myKey"] = "myValue";

auto use_reference = [](Hjson::Value& input) {
};

// This statement won't compile in gcc or clang. Visual Studio will compile
// and use a reference to the MapProxy temporary object.
use_reference(map["myKey"]);

// This statement will compile just fine.
use_reference(map.at("myKey"));

Number representations

The C++ implementation of Hjson can both read and write 64-bit integers. No special care is needed, you can simply assign the value.

Example:

Hjson::Value myValue = 9223372036854775807;
assert(myValue == 9223372036854775807);

All integers are stored with 64-bit precision. An Hjson::Value containing an integer will be of the type Hjson::Type::Int64. The only other way that a number is stored in an Hjson::Value is in the form of a double precision floating point representation, which can handle up to 52 bits of integer precision. An Hjson::Value containing a floating point value will be of the type Hjson::Type::Double.

An Hjson::Value that has been unmarshalled from a string that contains a decimal point (for example the string "1.0"), or a string containing a number that is bigger or smaller than what can be represented by an std::int64_t variable (bigger than 9223372036854775807 or smaller than -9223372036854775808) will be stored as a double precision floating point number internally in the Hjson::Value.

Any Hjson::Value of type Hjson::Type::Double will be represented by a string containing a decimal point when marshalled (for example "1.0"), so that the string can be unmarshalled back into an Hjson::Type::Double, i.e. no information is lost in the marshall-unmarshall cycle.

The function Hjson::Value::is_numeric() returns true if the Hjson::Value is of type Hjson::Type::Double or Hjson::Type::Int64.

Avoiding type mismatch errors

When static_cast<>() is used on an Hjson::Value, an Hjson::type_mismatch error is thrown if the Hjson::Value is not of a compatible type. For example, if you do static_cast (myVal) then myVal must be of the type Hjson::Type::String, otherwise an Hjson::type_mismatch error is thrown.

So if you use static or implicit casting, errors can be thrown depending on the content of the input Hjson file. Maybe the Hjson file contains a collection of first and last names in quoteless lowercase strings and Christopher Null is one of the persons in the collection... The unquoted string null is stored in an Hjson::Value of type Hjson::Type::Null instead of Hjson::Type::String as the other names.

To avoid errors being thrown when casting, instead use these Hjson::Value member functions that will return the best possible representation of the value regardless of Hjson::Type:

double Value::to_double() const;
std::int64_t Value::to_int64() const;
std::string Value::to_string() const;

For example, if myVal is of type Hjson::Type::Null then myVal.to_string() returns the string "null".

Operators

This table shows all operators defined for Hjson::Value, and the Hjson::Type they require. If an operator is used on an Hjson::Value of a type for which that operator is not valid, the exception Hjson::type_mismatch is thrown.

Undefined Null Bool Double Int64 String Vector Map
= X X X X X X X X
== X X X X X X X X
!= X X X X X X X X
+ X X X
- X X
++ X X
-- X X
+= X X X
-= X X
< X X X
> X X X
<= X X X
>= X X X
* X X
/ X X
*= X X
/= X X
% X
%= X
[int] X X X
[string] X X

The equality operator (==) returns true if the two Hjson::Value objects are both of type Hjson::Type::Undefined or Hjson::Type::Null.

When comparing Hjson::Value objects of type Hjson::Type::Vector or Hjson::Type::Map, the equality operator (==) returns true if both objects reference the same underlying vector or map (i.e. the same behavior as when comparing pointers).

Order of map elements

Iterators for an Hjson::Value of type Hjson::Type::Map are always ordered by the keys in alphabetic order. But when editing a configuration file you might instead want the output to have the same order of elements as the file you read for input. That is the default ordering in the output from Hjson::Marshal(), thanks to true being the default value of the option preserveInsertionOrder in Hjson::EncoderOptions.

The elements in an Hjson::Value of type Hjson::Type::Map can be accessed directly using the bracket operator with either the string key or the insertion index as input parameter.

Hjson::Value val1;
val1["zeta"] = 1;
assert(val1[0] == 1);
val1[0] = 99;
assert(val1["zeta"] == 99);

The key for a given insertion index can be viewed using the function Hjson::Value::key(int index).

Hjson::Value val1;
val1["zeta"] = 1;
assert(val1.key(0) == "zeta");

The insertion order can be changed using the function Hjson::Value::move(int from, int to). If the input parameter from is lower than the input parameter to, the value will end up at index to - 1.

Hjson::Value val1;
val1["zeta"] = 1;
val1["y"] = 2;
val1.move(0, 2);
assert(val1.key(1) == "zeta");
assert(val1[0] == 2);

The insertion order is kept when cloning or merging Hjson::Value maps.

Comments

The Hjson unmarshal functions will by default store any comments in the resulting Hjson::Value tree, so that you can easily create an app that updates existing Hjson documents without losing the comments. In this example, any comments in the Hjson file are kept:

Hjson::Value root = Hjson::UnmarshalFromFile(szPath);
root["myKey"] = "aNewValue";
Hjson::MarshalToFile(root, szPath);

The Hjson::Value assignment operator does not assign new comments unless the receiving Hjson::Value is of type Hjson::Type::Undefined. The reason for that is that comments should not be lost when assigning a new value, as in the example here above. If you actually do want to replace both the value and the existing comments, use the function Hjson::Value::assign_with_comments():

// Changes the value but does not change any comments in root["myKey"], unless
// root["myKey"] was undefined before this assignment.
root["myKey"] = otherValue;

// Changes the value and also copies all comments from otherValue into root["myKey"].
root["myKey"].assign_with_comments(otherValue);

There are four types of comments: before, key, inside and after. If a comment is found, all chars (including line feeds and white spaces) between the values and/or separators are included in the string that becomes stored as a comment in an Hjson::Value.

# This is a *before* comment to the object that starts on the next line.
{
  # This is a *before* comment to value1.
  // This is still the same *before* comment to value1.
  key1: /* This is a *key* comment to value1. */ "value1" // This is an *after* comment to value1.
  /* This is a *before* comment to value2. */
  key2:
  // This is a *key* comment to value2.
  value2 /* This is an *after* comment to value2.
  key3: {
    // This is an *inside* comment.
  }
  key4: value4
  // This is an *after* comment to value4. Would have been a *before* comment
  // to value5 if this map contained a fifth value.
}
// This is an *after* comment to the root object.

An inside comment is shown right after { or [ in a map or vector. The unmarshal functions will only assign a comment as an inside comment if the map or vector is empty. Otherwise such a comment will be assigned to the before comment of the first element in the map or vector.

A key comment is shown between the key and the value if the value is an element in a map. If the value is not an element in a map, the key comment is shown between the before comment and the value.

After unmarshalling (with comments) the example here above, some of the comment strings would look like this:

root["key1"].get_comment_before() == "\n  # This is a *before* comment to value1.\n  // This is still the same *before* comment to value1.\n  ";

root.get_comment_after() == "\n// This is an *after* comment to the root object.";

The Hjson::Value::set_comment_X functions do not analyze the strings they get as input, so you will change the meaning of the Hjson output if you are not careful when using them. For example, a comment starting with // or # must end with a line feed or else the marshal functions will place the value on the same line as the comment, thus making the value a part of the comment.

If you want to keep blank lines and other formatting in an Hjson document even if there are no comments, set the option whitespaceAsComments to true in DecoderOptions. Then the output from the marshal functions will look exactly like the input to the unmarshal functions, except possibly changes in root braces, quotation and comma separators. When whitespaceAsComments is true, the option comments is ignored (treated as true).

Performance

Hjson is not much optimized for speed. But if you require fast(-ish) execution, escpecially in a multithreaded application, you can experiment with different values for the Cmake option HJSON_NUMBER_PARSER. The default value StringStream uses C++ string streams with the locale classic imbued to ensure that dots are used as decimal separators rather than commas.

The value StrToD gives better performance, especially in multi threaded applications, but will use whatever locale the application is using. If the current locale uses commas as decimal separator Hjson will umarshal floating point numbers into strings, and will use commas in floating point numbers in the marshal output, which means that other parsers will treat that value as a string.

Setting HJSON_NUMBER_PARSER to CharConv gives the best performance, and uses dots as comma separator regardless of the application locale. Using CharConv will automatically cause the code to be compiled using the C++17 standard (or a newer standard if required by your project). Unfortunately neither GCC 10.1 or Clang 10.0 implement the required feature of C++17 (std::from_chars() for double), but GCC 11 will have it. It does work in Visual Studio 17 and later.

Another way to increase performance and reduce memory usage is to disable reading and writing of comments. Set the option comments to false in DecoderOptions and EncoderOptions. In this example, any comments in the Hjson file are ignored:

Hjson::DecoderOptions decOpt;
decOpt.comments = false;
Hjson::Value root = Hjson::UnmarshalFromFile(szPath, decOpt);
Hjson::EncoderOptions encOpt;
encOpt.comments = false;
Hjson::MarshalToFile(root, szPath, encOpt);

Example code

(dat["array"][0])); // To encode to Hjson with default options: Hjson::Value sampleMap; sampleMap["apple"] = 5; sampleMap["lettuce"] = 7; std::string hjson = Hjson::Marshal(sampleMap); printf("%s\n", hjson.c_str()); } ">
#include <hjson.h>


int main() {

  // Now let's look at decoding Hjson data into Hjson::Value.
  std::string sampleText = R"(
{
  # specify rate in requests/second
  rate: 1000
  array:
  [
    foo
    bar
  ]
}
)";

  // Decode. Throws Hjson::syntax_error if the string is not fully valid Hjson.
  Hjson::Value dat = Hjson::Unmarshal(sampleText.c_str(), sampleText.size());

  // Values can be assigned directly without casting.
  int rate = dat["rate"];
  printf("%d\n", rate);

  // Sometimes it's difficult for the compiler to know
  // what primitive type to convert the Hjson::Value to.
  // Then an explicit cast can be used.
  printf("%s\n", static_cast<const char*>(dat["array"][0]));

  // To encode to Hjson with default options:
  Hjson::Value sampleMap;
  sampleMap["apple"] = 5;
  sampleMap["lettuce"] = 7;
  std::string hjson = Hjson::Marshal(sampleMap);
  printf("%s\n", hjson.c_str());
}

Iterating through the elements of an Hjson::Value of type Hjson::Type::Vector:

for (int index = 0; index < int(arr.size()); ++index) {
  std::cout << arr[index] << std::endl;
}

Iterating through the elements of an Hjson::Value of type Hjson::Type::Map in alphabetical order:

first << " value: " << it->second << std::endl; } ">
for (auto it = map.begin(); it != map.end(); ++it) {
  std::cout << "key: " << it->first << "  value: " << it->second << std::endl;
}

Having a default configuration:

#include <hjson.h>
#include <cstdio>


static const char *_szDefaultConfig = R"(
{
  imageSource: NO DEFAULT
  showImages: true
  writeImages: true
  printFrameIndex: false
  printFrameRate: true
}
)";


Hjson::Value GetConfig(const char *szConfigPath) {
  Hjson::Value defaultConfig = Hjson::Unmarshal(_szDefaultConfig);

  Hjson::Value inputConfig;
  try {
    inputConfig = Hjson::UnmarshalFromFile(szConfigPath);
  } catch(const std::exception& e) {
    std::fprintf(stderr, "Error in config: %s\n\n", e.what());
    std::fprintf(stdout, "Default config:\n");
    std::fprintf(stdout, _szDefaultConfig);

    return Hjson::Value();
  }

  return Hjson::Merge(defaultConfig, inputConfig);
}

For a full multi-platform example application using Hjson configuration files, see the hjson-cpp-example template repository.

History

see releases

Issues
  • how to separate int values like `123` from floating point values like `123.0`

    how to separate int values like `123` from floating point values like `123.0`

    How should I separate values decoded from 123 (as an int64_t) from values decoded from 123.0 (as a double)?

    I miss a bool Hjson::Value::is_int64() const member function.

    (This is for http://refpersys.org/ BTW)

    Regards

    -- Basile Starynkevitch, Bourg La Reine, France http://starynkevitch.net/Basile/ [email protected]

    opened by bstarynk 18
  • Preserve commentary

    Preserve commentary

    I've implemented the commentary feature mostly as discussed in https://github.com/hjson/hjson-cpp/issues/6.

    Following additional comments:

    • To represent comments inside empty objects / arrays and multi-line comments after the last member in objects / arrays, I had to add an additional comment_inside
    • Commentary at special places like
    // regular comment
    mykey /* special comment */ : // other special comment
    {
       subkey = true
    }
    

    will be reordered and output will look like this

    // regular comment
    /* special comment */
    // other special comment
    mykey: 
    {
       subkey = true
    }
    

    In hjson-c# it is omitted. I didn't want to omit the commentary, but figured that their is no need to keep the special comments in place.

    Feel free to comment on my changes or propose further improvements. I have tested quite a bit, but if you have the possibility to test it in a different environment or with your own hjson-example-files I would appreciate it.

    opened by JanPlitzkow 17
  • Order is not preserved.

    Order is not preserved.

    First of all. thank you for making this. hjson is vastly more fun to work with due to no "" all over. Anyway, hjson-cpp seems to sort the hjson elements when i do Value dat = Hjson::Unmarshal(hjsonStrInput); std::string hjsonOut = Hjson::Marshal(dat);

    I used it for an editor so it is very confusing that stuff moves around. Is there any way to keep the actual order of the elements? I used hjson for a templates system and the order is kinda important as alphabetically will mess up the natural grouping.

    opened by Mr-Jonas 7
  • handing of 64 bits integers missing

    handing of 64 bits integers missing

    It seems that it is not possible to code reliably (on 64 bits systems like Linux/x86-64) something like:

    std::int64_t ii = 1000000*1000000; // don't fit in an int
    Hjson::Value hval(ii);
    

    and of course get the same value later at parsing time.

    Basile Starynkevitch working on RefPerSys

    opened by bstarynk 6
  • Library loses commentary

    Library loses commentary

    Hello together, if I use Hjson::Unmarshal and directly Hjson::Marshal on the output, existing commentary will be lost / deleted in resulting output. Is this intended behaviour? In hjson-cs I'm able to preserve commentary by using LoadWsc and saving with keepWsc == true. Do I miss something or is this impossible with hjson-cpp? Greatings, Jan

    opened by JanPlitzkow 6
  • toJson()

    toJson()

    Hi,

    It is great to have an hjson implementation in C++, thank you! I was wondering if there is any plan to implement a toJson() feature which would allow us to convert hjson content to json.

    opened by damianorenfer 6
  • stringstream() performance in multi-thread

    stringstream() performance in multi-thread

    Hi, this hjson is very useful, I appreciated for your work. In my project I need to do unMarshal in multi-thread, but they are blocking, I found stringstream() in below two functions is not thread-safety, so I hope this will be helpful for those guys use hjson in multi-threads.

    static bool _parseFloat(double *pNumber, const std::string &str) { std::stringstream ss(str);

    // Make sure we expect dot (not comma) as decimal point. ss.imbue(std::locale::classic());

    ss >> *pNumber;

    return ss.eof() && !ss.fail() && !std::isinf(*pNumber) && !std::isnan(*pNumber); } static bool _parseInt(std::int64_t *pNumber, const std::string &str) { std::stringstream ss(str);

    ss >> *pNumber;

    return ss.eof() && !ss.fail(); }

    opened by hongguangxu 4
  • missing output operator

    missing output operator

    I am missing some std::ostream& operator << (std::ostream&, HJson::Value); operator to be able to code in a C++ friendly way std::cout << hjv after having filled some HJson::Value hjv; (at least for debugging purposes).

    A trivial (but not very efficient) implementation might be

    std::ostream& operator << (std::ostream&out, HJson::Value hjv) {
      out << HJson::MarshalJson(hjv);
      return out;
    }
    
    opened by bstarynk 3
  • Issues when unmarshalling arrays containing 'null' values

    Issues when unmarshalling arrays containing 'null' values

    Found different issues with null values in arrays - some times elements are missing and in other cases the parser bails to a non-existing syntax error. Error behaviour is kind of undeterministic, so I prepared a small test program which hopefully allows to reproduce it.

    Source Code

    The source code contains infos on compiler flags and architecture as well.

    opened by homacs 2
  • Exception Handling in Unmarshall

    Exception Handling in Unmarshall

    When reading and parsing a hjson-file without curly brackets in the beginning, ill formatted text will not throw an exception due to ignoring it.

    This behaviour is internally correct, so you will identify ill formatted files in your code correctly, but you don't pass it to the outer layer. The attached example will not print the error and silently continues.

    // hjson_decode: 495
    // Braces for the root object are optional
    static Value _rootValue(Parser *p) {
     //[...]
    
      // assume we have a root object without braces
      try {
        res = _readObject(p, true);
        if (!_hasTrailing(p)) {
          return res;
        }
      } catch(syntax_error e) {} // This is problematic
    
      // test if we are dealing with a single JSON value instead (true/false/null/num/"")
      _resetAt(p);
      res = _readValue(p);
      if (!_hasTrailing(p)) {
        return res;
      }
    
      throw syntax_error(_errAt(p, "Syntax error, found trailing characters"));
    }
    

    You can test this using this file:

    Global:
    {
       MyGroup:
        {
            Key1: 1000		// Comment 1
    		Key2: 2000		// Comment 2
    		Key3:"Tests		// This line is not correct
    		Key4: 1234
        }
    }
    

    My suggestion would be to rethrow the error. Why are you ignoring it?

    opened by maldag 2
  • give written instructions to get a debug-friendly HjonCPP library on Linux

    give written instructions to get a debug-friendly HjonCPP library on Linux

    I am not familiar at all with cmake on Linux (and honestly, I dislike it: it is hiding too much things). I much prefer omake or ninja to cmake.

    Could you please add a few lines in the README.md about how to compile the HJson CPP library to get debug friendly information. On Linux with g++ or clang++ that would mean passing both -g and -O1 to the C++ compiler (it is possible, and worthwhile, to have debugging symbols and a little optimization). Of course you won't strip the library.

    BTW, I also miss a shared library on Linux, that is a libhjsoncpp.so. See Drepper's paper How to write shared libraries for details, and the old Program Library HowTo

    Thanks a lot.

    opened by bstarynk 2
Releases(2.2)
  • 2.2(Apr 14, 2021)

    Changed behavior:

    • UnmarshalFromFile() will now ignore the last line feed in a file if the file ends with a comment. Before this change, a read-write cycle of a file with comments would always add one more line feed at the end of the file if the file ended with a comment.
    • The output from Merge() of two maps now uses the key order from the second Hjson::Value argument because the second argument is typically from an input file written by a user, and we don't want to keep changing the order that the user had decided.

    Bug fixes:

    • Lower (second level or deeper) level maps now keep their comments in the output from Merge().
    • Value::clone() now keep all comments.
    Source code(tar.gz)
    Source code(zip)
  • 2.1(Nov 17, 2020)

  • 2.0(Nov 14, 2020)

    Major release containing several breaking changes.

    Biggest change: can now read and write comments.

    • enum class for Hjson::Value types
    • changed default options
    • assignment and arithmetic operators for all primitive C++ types
    • read and write comments
    • convenience file functions
    • MarshalWithOptions() replaced by Marshal() overload
    • DefaultOptions() replaced by brace-or-equal-initializers in EncoderOptions
    Source code(tar.gz)
    Source code(zip)
  • 1.6.1(Sep 16, 2020)

  • 1.6(Aug 28, 2020)

    Added option omitRootBraces for MarshalWithOptions(). The default value is false, so the default behavior has not changed.

    Fixed problem with insertion order being lost when cloning or merging values.

    Source code(tar.gz)
    Source code(zip)
  • 1.5(Jul 3, 2020)

  • 1.4.1(Feb 13, 2020)

  • 1.4(Jan 18, 2020)

    Marshal() now includes a decimal point in the string representation of any number that is stored using a floating point representation (for example "1.0").

    Added functions is_int64() and Unmarshal(const std::string&).

    Added stream insertion operator for Hjson::Value.

    Source code(tar.gz)
    Source code(zip)
  • 1.3(Nov 20, 2019)

    Support for 64-bit precision integers.

    Default installation folder for the lib file in POSIX is now /usr/local/lib instead of /usr/local/lib/hjson.

    Added option preserveInsertionOrder for MarshalWithOptions(). The default value is false, but that might change to true in release 2.0.

    Source code(tar.gz)
    Source code(zip)
  • 1.2.1(Oct 14, 2018)

  • 1.2(Dec 26, 2017)

  • 1.1(Oct 18, 2017)

    New function called "Merge" which can be used to easily override just a few values of a default configuration.

    Also a new member function on the Value class, called "clone".

    Source code(tar.gz)
    Source code(zip)
  • 1.0.1(Sep 6, 2017)

    Changed behavior: Now throws Hjson::index_out_of_bounds when trying to access a vector-element on an Hjson::Value object of type Hjson::Value::UNDEFINED.

    Source code(tar.gz)
    Source code(zip)
Owner
Hjson
A user interface for JSON.
Hjson