#include "JFile.h" #include "ZString.h" #include "Exception.h" namespace coreutils { // MFile and JString share a single virtual MString base (the diamond: // both "MFile : virtual public MString" and "JString : virtual public // MString"), and a virtual base is initialized only by the *most // derived* class's constructor - so JString's own "{}" default // initializer never runs here. Left alone, a JFile backed by a new or // empty file starts as a raw empty string instead of a valid empty JSON // object, and every subsequent locate()/set() call silently misbehaves // (no leading "{" for ifNext("{") to match, so writes end up inserted // at offset 0 with no braces or separators at all). Detect that case // here and seed valid JSON explicitly. JFile::JFile(ZString filename) : MFile(filename) { if(getLength() == 0) { *this << "{}"; } else { // MFile's own file-loading reads the raw bytes straight into the // shared MString buffer - it never goes through JString::operator=, // which is the only other place this class normally strips // whitespace before parsing (removeWhitespace()). Without this, a // JFile backed by a hand-written or pretty-printed JSON file (any // whitespace between tokens - indentation, newlines, spaces after // ':'/',') fails every locate()/exists()/get*() call, since // JString's parser expects compact JSON with no whitespace at all // between structural tokens. In-memory JSON built via operator= // never hit this because it already goes through the same // normalization - loading from disk just missed it. removeWhitespace(); } } }