/* * * Copyright (C) 2017-2020, OFFIS e.V. * All rights reserved. See COPYRIGHT file for details. * * This software and supporting documentation were developed by * * OFFIS e.V. * R&D Division Health * Escherweg 2 * D-26121 Oldenburg, Germany * * * Module: dcmdata * * Author: Sebastian Grallert * * Purpose: Providing basic JSON formatting functionalities * */ #ifndef DCJSON_H #define DCJSON_H #include "dcmtk/config/osconfig.h" // make sure OS specific configuration is included first #include "dcmtk/ofstd/ofdefine.h" #include "dcmtk/ofstd/ofstring.h" #include "dcmtk/dcmdata/dctagkey.h" /** Class for handling JSON format options. * Base class to implement custom formatting. * Purpose: * - individual output formatting * - normalization of DecimalString and IntegerString e.g.\ normalization of leading zeros * - escaping of special JSON control characters * - outputting the correct indention and symbols for "Value", "BulkDataURI", etc. * *

Usage Example:

* @code{.cpp} * #include "dcmtk/dcmdata/dcjson.h" * // ... * DcmFileFormat fileformat; * if(fileformat.loadFile("test.dcm").good()) * { * // print the DICOM file in JSON format * // using the pretty format (muti-line with indention and other whitespace) * fileformat.writeJson(COUT, DcmJsonFormatPretty(OFTrue)); * * // using the compact (single line, without unneeded whitespace) format * fileformat.writeJson(COUT, DcmJsonFormatCompact(OFTrue)); * } * @endcode *

Implementing a custom formatter:

* @code{.cpp} * struct CustomJsonFormat : DcmJsonFormatPretty * { * CustomJsonFormat(const OFBool printMetaInfo = OFTrue) * : DcmJsonFormatPretty(printMetaInfo) * { * * } * * OFString OFJsonFormatExample::space() * { * // use tabstops instead of spaces for indention * return "\t"; * } * } * @endcode */ class DCMTK_DCMDATA_EXPORT DcmJsonFormat { public: /** A class to create small proxy objects that ease indention handling. * Each Indention object only contains a reference to the DcmJsonFormat object * that created it and its only purpose is to call the respective methods * of that object when one of its overloaded operators is used. */ class Indention { public: /** output current indention to an output stream. * @param out the output stream to use * @param indention the indention to print * @return out */ friend inline STD_NAMESPACE ostream& operator<<(STD_NAMESPACE ostream& out, const Indention& indention) { indention.printIndention(out); return out; } /** increases current indention. * @return *this */ inline Indention& operator++() { m_Format.increaseIndention(); return *this; } /** decreases current indention * @return *this */ inline Indention& operator--() { m_Format.decreaseIndention(); return *this; } private: /// allow DcmJsonFormat to use this class' private members friend class DcmJsonFormat; /** private constructor, used by DcmJsonFormat * @param format the format */ inline Indention(DcmJsonFormat& format) : m_Format(format) { } /** prints the current indention using the parent formatter * @param out the stream to print to */ inline void printIndention(STD_NAMESPACE ostream& out) const { m_Format.printIndention(out); } /// reference to the parent formatter object DcmJsonFormat& m_Format; }; /** Escapes all forbidden control characters in JSON * @param out output stream to which the escaped String is written * @param value String that should be escaped */ static void escapeControlCharacters(STD_NAMESPACE ostream &out, OFString const &value); /** Normalize Decimal String to specific JSON format. * remove leading zeros, except before dot. * @b Example: * @code{.txt} * 00.123 --> 0.123 * 023.12 --> 23.12 * -01.00 --> -1.00 * 0200 --> 200 * .12 --> 0.12 * 000.1 --> 0.1 * @endcode * @param value String that should be normalize */ static void normalizeDecimalString(OFString &value); /** Normalize Integer String to specific JSON format. * remove leading zeros, except before dot. * @b Example: * @code{.txt} * 000 --> 0 * 023 --> 23 * -01 --> -1 * 0200 --> 200 * @endcode * @param value String that should be normalize */ static void normalizeIntegerString(OFString &value); /** Prints either null if empty or the string value * (with all illegal characters escaped). * @param out output stream to which the Value prefix is written * @param value String that should be printed */ static void printString(STD_NAMESPACE ostream &out, const OFString &value); /** Prints either null if empty or a quoted string * (with leading and ending quotation marks and all * illegal characters escaped). * @param out output stream to which the Value prefix is written * @param value String that should be printed */ static void printValueString(STD_NAMESPACE ostream &out, const OFString &value); /** Print either null if empty or a Number as normalized IntegerString * @param out output stream to which the Value prefix is written * @param value String that should be printed */ static void printNumberInteger(STD_NAMESPACE ostream &out, OFString &value); /** Print either null if empty or a Number as normalized IntegerDecimal * @param out output stream to which the Value prefix is written * @param value String that should be printed */ static void printNumberDecimal(STD_NAMESPACE ostream &out, OFString &value); /** Constructor * @param printMetaInfo parameter that defines if meta information should be written */ inline DcmJsonFormat(const OFBool printMetaInfo) : printMetaheaderInformation(printMetaInfo) , enableJsonExtension(OFFalse) { } /** Virtual destructor, does nothing */ virtual ~DcmJsonFormat() {} /** Method to return line break(s) * @return line break(s). */ virtual OFString newline() = 0; /** Method to return whitespace(s) * @return whitespace(s). */ virtual OFString space() = 0; /** Method to return an indention proxy object for increasing, decreasing or printing indention * @return an indention proxy object. */ inline Indention indent() { return Indention(*this); } /** Check if an attribute should be exported as BulkDataURI. * Override this function to implement bulk data URI output. * @param tag the tag of the attribute being printed, for letting * the implementation decide how to handle it. * @param uri the resulting URI to output. * @return OFTrue if yes, OFFalse if no. * @details *

Usage Example:

* @code{.cpp} * struct BulkDataURIJsonFormat : DcmJsonFormatPretty * { * CustomJsonFormat(const OFBool printMetaInfo = OFTrue, * ... bulkDataURIDatabase) * : DcmJsonFormatPretty(printMetaInfo) * , TheDatabase(bulkDataURIDatabase) * { * * } * * virtual OFBool asBulkDataURI(const DcmTagKey& tag, OFString& uri) * { * ... result = TheDatabase.findBulkDataFor(tag); * if (result.found()) * { * uri = result.uri(); * return OFTrue; * } * return OFFalse; * } * * ... TheDatabase; * } * @endcode */ virtual OFBool asBulkDataURI(const DcmTagKey& tag, OFString& uri); /** Print the Prefix which for JSON Values needed * with indention and newlines as in the format Variable given. * @b Example: * @code{.txt} * ,"Value":[ * @endcode * @param out output stream to which the Value prefix is written */ virtual void printValuePrefix(STD_NAMESPACE ostream &out); /** Print the Suffix which for JSON Values needed * with indention and newlines as in the format Variable given. * @b Example: * @code{.txt} * ]\n * @endcode * @param out output stream to which the Value prefix is written */ virtual void printValueSuffix(STD_NAMESPACE ostream &out); /** Print the Prefix which for JSON BulkDataURI needed * with indention and newlines as in the format Variable given. * @b Example: * @code{.txt} * ,"BulkDataURI": * @endcode * @param out output stream to which the Value prefix is written */ virtual void printBulkDataURIPrefix(STD_NAMESPACE ostream &out); /** Print the Prefix which for JSON InlineBinary needed * with indention and newlines as the format specifies. * @b Example: * @code{.txt} * ,"InlineBinary": * @endcode * @param out output stream to which the Value prefix is written */ virtual void printInlineBinaryPrefix(STD_NAMESPACE ostream &out); /** Print the prefix for array elements (except the first one), with * indention and newlines as the format specifies. * @b Example: * @code{.txt} * Example,\n * Example... * @endcode * @param out output stream to which the Value prefix is written */ virtual void printNextArrayElementPrefix(STD_NAMESPACE ostream &out); /** return the flag indicating whether extended JSON number encoding is enabled. */ virtual OFBool getJsonExtensionEnabled() const { return enableJsonExtension; } /** set the flag indicating whether extended JSON number encoding is enabled. * @param enabled new value of the flag */ virtual void setJsonExtensionEnabled(OFBool enabled) { enableJsonExtension = enabled; } /** Option that defines if metaheader information should be printed. */ const OFBool printMetaheaderInformation; protected: /** Indent to the specific level. * @param out output stream to which the indention is written. */ virtual void printIndention(STD_NAMESPACE ostream& out) = 0; /** Used for increasing the indention level. */ virtual void increaseIndention() = 0; /** Used for decreasing the indention level. */ virtual void decreaseIndention() = 0; private: /** Option that defines if the inofficial JSON extension should be * permitted under which decimal numbers may have the values "-inf", * "inf" or "nan". Default is OFFalse, in which case such values * will lead to an error code being returned instead. */ OFBool enableJsonExtension; }; /** Subclass for handling JSON formatted output. * Standard class for formatted output. */ class DCMTK_DCMDATA_EXPORT DcmJsonFormatPretty : public DcmJsonFormat { private: /** Variable for the indention level of DcmJsonFormat */ unsigned m_IndentionLevel; public: /** DcmJsonFormatPretty constructor * @param printMetaInfo Enable/Disable including Metaheader in the output */ explicit DcmJsonFormatPretty(const OFBool printMetaInfo = OFTrue); /** Indent to the specific level. * @param out output stream to which the indention is written. */ void printIndention(STD_NAMESPACE ostream& out); /** Increase the indention level. */ void increaseIndention(); /** Decrease the indention level. */ void decreaseIndention(); /** Print a newline * @returns a newline */ OFString newline(); /** Print a space * @returns a space */ OFString space(); }; /** Subclass for handling JSON formatted output. * Standard class for non-formatted output. */ class DCMTK_DCMDATA_EXPORT DcmJsonFormatCompact : public DcmJsonFormat { public: /** DcmJsonFormatCompact constructor * @param printMetaInfo Enable/Disable including Metaheader in the output */ explicit DcmJsonFormatCompact(const OFBool printMetaInfo = OFTrue); /** Does nothing. * @param out output stream to which the indention is written. */ void printIndention(STD_NAMESPACE ostream& out); /** Does nothing. */ void increaseIndention(); /** Does nothing. */ void decreaseIndention(); /** Does nothing. * @returns a empty String. */ OFString newline(); /** Does nothing. * @returns a empty String. */ OFString space(); }; #endif /* DCJSON_H */