#include "gdcmJSON.h"
#include "gdcmGlobal.h"
#include "gdcmDicts.h"
#include "gdcmBase64.h"
#include "gdcmSystem.h"
#ifdef GDCM_USE_SYSTEM_JSON
#include <json.h>
#endif
#ifdef GDCM_HAVE_JSON_OBJECT_OBJECT_GET_EX
static inline json_object * json_object_object_get_old(json_object * obj, const char * name) {
json_object * sub;
return json_object_object_get_ex(obj, name, & sub) ? sub : NULL;
}
#else
#define json_object_object_get_old json_object_object_get
#endif
namespace gdcm
{
#ifdef GDCM_USE_SYSTEM_JSON
static inline void wstrim(std::string& str)
{
str.erase(0, str.find_first_not_of(' '));
str.erase(str.find_last_not_of(' ')+1);
}
static inline bool CanContainBackslash( const VR::VRType vrtype )
{
gdcm_assert( VR::IsASCII( vrtype ) );
switch( vrtype )
{
case VR::AE: case VR::CS: case VR::DA: case VR::DS: case VR::DT: case VR::IS: case VR::LO: case VR::PN: case VR::SH: case VR::TM: case VR::UI: gdcm_assert( !(vrtype & VR::VR_VM1) );
return true;
default:
;
}
return false;
}
#endif
class JSONInternal
{
public:
JSONInternal()= default;
bool PrettyPrint{false};
bool PreferKeyword{false};
};
JSON::JSON()
{
Internals = new JSONInternal;
}
JSON::~JSON()
{
delete Internals;
}
void JSON::SetPrettyPrint(bool onoff)
{
Internals->PrettyPrint = onoff;
}
bool JSON::GetPrettyPrint() const
{
return Internals->PrettyPrint;
}
void JSON::PrettyPrintOn()
{
Internals->PrettyPrint = true;
}
void JSON::PrettyPrintOff()
{
Internals->PrettyPrint = false;
}
#ifdef GDCM_USE_SYSTEM_JSON
static void DataElementToJSONArray( const VR::VRType vr, const DataElement & de, json_object *my_array )
{
if( de.IsEmpty() )
{
if( vr == VR::PN )
{
json_object *my_object_comp = json_object_new_object();
json_object_array_add(my_array, my_object_comp );
}
return;
}
gdcm_assert( !de.IsEmpty() );
const bool checkbackslash = CanContainBackslash( vr );
const ByteValue * bv = de.GetByteValue();
const char * value = bv->GetPointer();
size_t len = bv->GetLength();
if( vr == VR::UI )
{
const std::string strui( value, len );
const size_t lenuid = strlen( strui.c_str() ); json_object_array_add(my_array, json_object_new_string_len(strui.c_str(), lenuid));
}
else if( vr == VR::PN )
{
const char *str1 = value;
while( str1[len-1] == ' ' )
{
len--;
}
gdcm_assert( str1 );
std::stringstream ss;
static const char *Keys[] = {
"Alphabetic",
"Ideographic",
"Phonetic",
};
while (1)
{
gdcm_assert( str1 && (size_t)(str1 - value) <= len );
const char * sep = strchr(str1, '\\');
const size_t llen = (sep != NULL) ? (sep - str1) : (value + len - str1);
const std::string component(str1, llen);
const char *str2 = component.c_str();
gdcm_assert( str2 );
const size_t len2 = component.size();
gdcm_assert( len2 == llen );
int idx = 0;
json_object *my_object_comp = json_object_new_object();
while (1)
{
gdcm_assert( str2 && (size_t)(str2 - component.c_str() ) <= len2 );
const char * sep2 = strchr(str2, '=');
const size_t llen2 = (sep2 != NULL) ? (sep2 - str2) : (component.c_str() + len2 - str2);
const std::string group(str2, llen2);
const char *thekey = Keys[idx++];
json_object_object_add(my_object_comp, thekey,
json_object_new_string_len( group.c_str(), group.size() ) );
if (sep2 == NULL) break;
str2 = sep2 + 1;
}
json_object_array_add(my_array, my_object_comp);
if (sep == NULL) break;
str1 = sep + 1;
gdcm_assert( checkbackslash );
}
}
else if( vr == VR::DS || vr == VR::IS )
{
const char *str1 = value;
gdcm_assert( str1 );
VRToType<VR::IS>::Type vris;
VRToType<VR::DS>::Type vrds;
while (1)
{
std::stringstream ss;
gdcm_assert( str1 && (size_t)(str1 - value) <= len );
const char * sep = strchr(str1, '\\');
const size_t llen = (sep != NULL) ? (sep - str1) : (value + len - str1);
switch( vr )
{
case VR::IS:
ss.str( std::string(str1, llen) );
ss >> vris;
json_object_array_add(my_array, json_object_new_int(vris)); break;
case VR::DS:
ss.str( std::string(str1, llen) );
ss >> vrds;
json_object_array_add(my_array, json_object_new_double(vrds));
break;
default:
gdcm_assert( 0 ); }
if (sep == NULL) break;
str1 = sep + 1;
gdcm_assert( checkbackslash );
}
}
else if( checkbackslash )
{
const char *str1 = value;
gdcm_assert( str1 );
while (1)
{
gdcm_assert( str1 && (size_t)(str1 - value) <= len );
const char * sep = strchr(str1, '\\');
const size_t llen = (sep != NULL) ? (sep - str1) : (value + len - str1);
json_object_array_add(my_array, json_object_new_string_len(str1, llen));
if (sep == NULL) break;
str1 = sep + 1;
}
}
else {
json_object_array_add(my_array, json_object_new_string_len(value, len));
}
}
static void ProcessNestedDataSet( const DataSet & ds, json_object *my_object, const bool preferkeyword )
{
const Global& g = GlobalInstance;
const Dicts &dicts = g.GetDicts();
const Dict &d = dicts.GetPublicDict(); (void)d;
std::vector<char> buffer;
for( DataSet::ConstIterator it = ds.Begin();
it != ds.End(); ++it )
{
const DataElement &de = *it;
VR::VRType vr = de.GetVR();
const Tag& t = de.GetTag();
if( t.IsGroupLength() ) continue; std::string strowner;
const char *owner = 0;
if( t.IsPrivate() && !t.IsPrivateCreator() )
{
strowner = ds.GetPrivateCreator(t);
owner = strowner.c_str();
}
const DictEntry &entry = dicts.GetDictEntry(t,owner);
const std::string & str_tag = t.PrintAsContinuousUpperCaseString();
const bool issequence = vr == VR::SQ || de.IsUndefinedLength();
const bool isprivatecreator = t.IsPrivateCreator();
if( issequence ) vr = VR::SQ;
else if( isprivatecreator ) vr = VR::LO; else if( vr == VR::INVALID ) vr = VR::UN;
const char * vr_str = VR::GetVRString(vr);
gdcm_assert( VR::GetVRTypeFromFile(vr_str) != VR::INVALID );
json_object *my_object_cur;
my_object_cur = json_object_new_object();
json_object *my_array;
my_array = json_object_new_array();
json_object_object_add(my_object_cur, "VR",
json_object_new_string_len( vr_str, 2 ) );
if( owner )
{
json_object_object_add(my_object_cur, "PrivateCreator",
json_object_new_string( owner ) );
}
if( vr == VR::SQ )
{
SmartPointer<SequenceOfItems> sqi;
sqi = de.GetValueAsSQ();
if( sqi )
{
int nitems = sqi->GetNumberOfItems();
for(int i = 1; i <= nitems; ++i)
{
const Item &item = sqi->GetItem( i );
const DataSet &nested = item.GetNestedDataSet();
json_object *my_object_sq;
my_object_sq = json_object_new_object();
ProcessNestedDataSet( nested, my_object_sq, preferkeyword );
json_object_array_add(my_array, my_object_sq );
}
}
else if( const SequenceOfFragments *sqf = de.GetSequenceOfFragments() )
{
json_object_array_add(my_array, NULL ); gdcm_assert( 0 );
}
else
{
gdcm_assert( de.IsEmpty() );
}
int numel = json_object_array_length ( my_array );
if( numel )
json_object_object_add(my_object_cur, "Value", my_array );
}
else if( VR::IsASCII( vr ) )
{
DataElementToJSONArray( vr, de, my_array );
int numel = json_object_array_length ( my_array );
if( numel )
{
if( vr == VR::PN )
{
json_object_object_add(my_object_cur, "Value", my_array );
}
else
json_object_object_add(my_object_cur, "Value", my_array );
}
}
else
{
const char *wheretostore = "Value";
switch( vr )
{
case VR::FD:
{
Element<VR::FD,VM::VM1_n> el;
el.Set( de.GetValue() );
int ellen = el.GetLength();
for( int i = 0; i < ellen; ++i )
{
json_object_array_add(my_array, json_object_new_double( el.GetValue( i ) ));
}
}
break;
case VR::FL:
{
Element<VR::FL,VM::VM1_n> el;
el.Set( de.GetValue() );
int ellen = el.GetLength();
for( int i = 0; i < ellen; ++i )
{
json_object_array_add(my_array, json_object_new_double( el.GetValue( i ) ));
}
}
break;
case VR::SS:
{
Element<VR::SS,VM::VM1_n> el;
el.Set( de.GetValue() );
int ellen = el.GetLength();
for( int i = 0; i < ellen; ++i )
{
json_object_array_add(my_array, json_object_new_int( el.GetValue( i ) ));
}
}
break;
case VR::US:
{
Element<VR::US,VM::VM1_n> el;
el.Set( de.GetValue() );
int ellen = el.GetLength();
for( int i = 0; i < ellen; ++i )
{
json_object_array_add(my_array, json_object_new_int( el.GetValue( i ) ));
}
}
break;
case VR::SL:
{
Element<VR::SL,VM::VM1_n> el;
el.Set( de.GetValue() );
int ellen = el.GetLength();
for( int i = 0; i < ellen; ++i )
{
json_object_array_add(my_array, json_object_new_int( el.GetValue( i ) ));
}
}
break;
case VR::UL:
{
Element<VR::UL,VM::VM1_n> el;
el.Set( de.GetValue() );
int ellen = el.GetLength();
for( int i = 0; i < ellen; ++i )
{
json_object_array_add(my_array, json_object_new_int( el.GetValue( i ) ));
}
}
break;
case VR::AT:
{
Element<VR::AT,VM::VM1_n> el;
el.Set( de.GetValue() );
int ellen = el.GetLength();
for( int i = 0; i < ellen; ++i )
{
const std::string atstr = el.GetValue( i ).PrintAsContinuousUpperCaseString();
json_object_array_add(my_array, json_object_new_string( atstr.c_str() ));
}
}
break;
case VR::UN:
case VR::INVALID:
case VR::OD:
case VR::OF:
case VR::OB:
case VR::OW:
{
gdcm_assert( !de.IsUndefinedLength() ); const ByteValue * bv = de.GetByteValue();
wheretostore = "InlineBinary";
if( bv )
{
const char *src = bv->GetPointer();
const size_t len = bv->GetLength();
gdcm_assert( len % 2 == 0 );
const size_t len64 = Base64::GetEncodeLength(src, len);
buffer.resize( len64 );
const size_t ret = Base64::Encode( &buffer[0], len64, src, len );
gdcm_assert( ret != 0 );
json_object_array_add(my_array, json_object_new_string_len(&buffer[0], len64));
}
}
break;
default:
gdcm_assert( 0 ); }
json_object_object_add(my_object_cur, wheretostore, my_array );
}
{
json_object_object_add(my_object, str_tag.c_str(), my_object_cur );
}
}
}
#endif
bool JSON::Code(DataSet const & ds, std::ostream & os)
{
#ifdef GDCM_USE_SYSTEM_JSON
json_object *my_object;
my_object = json_object_new_object();
ProcessNestedDataSet( ds, my_object, Internals->PreferKeyword );
const char* str = NULL;
if( Internals->PrettyPrint )
{
#ifdef JSON_C_VERSION
str = json_object_to_json_string_ext(my_object, JSON_C_TO_STRING_SPACED | JSON_C_TO_STRING_PRETTY );
#else
str = json_object_to_json_string( my_object );
#endif
}
else
{
str = json_object_to_json_string( my_object );
}
os << str;
json_object_put(my_object); return true;
#else
(void)ds;
(void)os;
return false;
#endif
}
#ifdef GDCM_USE_SYSTEM_JSON
static inline bool CheckTagKeywordConsistency( const char *name, const Tag & thetag )
{
gdcm_assert( name );
bool istag = *name >= '0' && *name <= '9'; if( istag )
{
gdcm_assert( strlen(name) == 8 );
Tag t;
t.ReadFromContinuousString( name );
return t == thetag;
}
const Global& g = GlobalInstance;
const Dicts &dicts = g.GetDicts();
const Dict &d = dicts.GetPublicDict();
const char * keyword = d.GetKeywordFromTag(thetag);
if( !keyword )
{
gdcmDebugMacro( "Unknown Keyword: " << name );
return true;
}
gdcm_assert( strcmp( name, keyword ) == 0 );
return strcmp( name, keyword ) == 0;
}
#endif
#ifdef GDCM_USE_SYSTEM_JSON
#ifdef JSON_C_VERSION
static void ProcessJSONElement( const char *tag_str, json_object * obj, DataElement & de )
{
json_type jtype = json_object_get_type( obj );
gdcm_assert( jtype == json_type_object );
json_object * jvr = json_object_object_get_old(obj, "VR");
const char * vr_str = json_object_get_string ( jvr );
de.GetTag().ReadFromContinuousString( tag_str );
const char * pc_str = 0;
if( de.GetTag().IsPrivate() && !de.GetTag().IsPrivateCreator() )
{
json_object * jprivatecreator = json_object_object_get_old(obj, "PrivateCreator");
pc_str = json_object_get_string ( jprivatecreator );
gdcm_assert( pc_str );
}
VR::VRType vrtype = VR::GetVRTypeFromFile( vr_str );
gdcm_assert( vrtype != VR::INVALID );
gdcm_assert( vrtype != VR::VR_END );
de.SetVR( vrtype );
if( vrtype == VR::SQ )
{
json_object * jvalue = json_object_object_get_old(obj, "Value");
json_type jvaluetype = json_object_get_type( jvalue );
gdcm_assert( jvaluetype != json_type_null && jvaluetype == json_type_array );
#ifndef NDEBUG
json_object * jseq = json_object_object_get_old(obj, "Sequence");
json_type jsqtype = json_object_get_type( jseq );
gdcm_assert( jsqtype == json_type_null );
#endif
if( jvaluetype == json_type_array )
{
SmartPointer<SequenceOfItems> sq = new SequenceOfItems;
sq->SetLengthToUndefined();
int sqlen = json_object_array_length ( jvalue );
for( int itemidx = 0; itemidx < sqlen; ++itemidx )
{
json_object * jitem = json_object_array_get_idx ( jvalue, itemidx );
json_type jitemtype = json_object_get_type( jitem );
gdcm_assert( jitemtype == json_type_object );
Item item;
item.SetVLToUndefined();
DataSet &nds = item.GetNestedDataSet();
#ifdef JSON_C_VERSION
json_object_iterator it;
json_object_iterator itEnd;
it = json_object_iter_begin(jitem);
itEnd = json_object_iter_end(jitem);
while (!json_object_iter_equal(&it, &itEnd))
{
const char *name = json_object_iter_peek_name(&it);
gdcm_assert( name );
json_object * value = json_object_iter_peek_value (&it);
DataElement lde;
ProcessJSONElement( name, value, lde );
nds.Insert( lde );
json_object_iter_next(&it);
}
#endif
sq->AddItem(item);
}
de.SetValue(*sq);
de.SetVLToUndefined();
}
}
else if( VR::IsASCII( vrtype ) )
{
json_object * jvalue = json_object_object_get_old(obj, "Value");
#ifndef NDEBUG
json_object * jpn = json_object_object_get_old(obj, "PersonName");
json_type jpntype = json_object_get_type( jpn );
gdcm_assert( jpntype == json_type_null );
#endif
json_type jvaluetype = json_object_get_type( jvalue );
gdcm_assert( jvaluetype == json_type_null || jvaluetype == json_type_array );
if( jvaluetype == json_type_array )
{
const int valuelen = json_object_array_length ( jvalue );
std::string str;
for( int validx = 0; validx < valuelen; ++validx )
{
if( validx ) str += '\\';
json_object * value = json_object_array_get_idx ( jvalue, validx );
json_type valuetype = json_object_get_type( value );
if( value )
{
gdcm_assert( valuetype != json_type_null );
std::string value_str;
std::stringstream ss;
VRToType<VR::IS>::Type vris;
VRToType<VR::DS>::Type vrds;
switch( vrtype )
{
case VR::PN:
{
json_object * jopn[3];
jopn[0] = json_object_object_get_old(value, "Alphabetic");
jopn[1]= json_object_object_get_old(value, "Ideographic");
jopn[2]= json_object_object_get_old(value, "Phonetic");
for( int i = 0; i < 3; ++i )
{
const char *tmp = json_object_get_string ( jopn[i] );
if( tmp )
{
if( i ) value_str += '=';
value_str += tmp;
}
}
}
break;
case VR::IS:
vris = json_object_get_int( value );
ss << vris;
value_str = ss.str();
break;
case VR::DS:
vrds = json_object_get_double( value );
ss << vrds;
value_str = ss.str();
break;
default:
value_str = json_object_get_string ( value );
}
str += value_str;
}
else
{
gdcm_assert( valuelen == 1 );
gdcm_assert( valuetype == json_type_null );
}
}
if( str.size() % 2 )
{
if( vrtype == VR::UI )
str.push_back( 0 );
else
str.push_back( ' ' );
}
de.SetByteValue( &str[0], str.size() );
}
#ifndef NDEBUG
else if( jpntype == json_type_array )
{
gdcm_assert( 0 );
}
#endif
}
else
{
json_object * jvaluebin = json_object_object_get_old(obj, "InlineBinary");
json_type jvaluebintype = json_object_get_type( jvaluebin );
json_object * jvalue = json_object_object_get_old(obj, "Value");
json_type jvaluetype = json_object_get_type( jvalue );
gdcm_assert( jvaluetype == json_type_array || jvaluetype == json_type_null );
if( jvaluetype == json_type_array )
{
DataElement locde;
const int valuelen = json_object_array_length ( jvalue );
const int vrsizeof = vrtype == VR::INVALID ? 0 : de.GetVR().GetSizeof();
switch( vrtype )
{
case VR::FD:
{
Element<VR::FD,VM::VM1_n> el;
el.SetLength( valuelen * vrsizeof );
for( int validx = 0; validx < valuelen; ++validx )
{
json_object * value = json_object_array_get_idx ( jvalue, validx );
gdcm_assert( json_object_get_type( value ) == json_type_double );
const double v = json_object_get_double ( value );
el.SetValue(v, validx);
}
locde = el.GetAsDataElement();
}
break;
case VR::FL:
{
Element<VR::FL,VM::VM1_n> el;
el.SetLength( valuelen * vrsizeof );
for( int validx = 0; validx < valuelen; ++validx )
{
json_object * value = json_object_array_get_idx ( jvalue, validx );
gdcm_assert( json_object_get_type( value ) == json_type_double );
const double v = json_object_get_double ( value );
el.SetValue(v, validx);
}
locde = el.GetAsDataElement();
}
break;
case VR::SS:
{
Element<VR::SS,VM::VM1_n> el;
el.SetLength( valuelen * vrsizeof );
for( int validx = 0; validx < valuelen; ++validx )
{
json_object * value = json_object_array_get_idx ( jvalue, validx );
gdcm_assert( json_object_get_type( value ) == json_type_int );
const int v = json_object_get_int( value );
el.SetValue(v, validx);
}
locde = el.GetAsDataElement();
}
break;
case VR::US:
{
Element<VR::US,VM::VM1_n> el;
el.SetLength( valuelen * vrsizeof );
for( int validx = 0; validx < valuelen; ++validx )
{
json_object * value = json_object_array_get_idx ( jvalue, validx );
gdcm_assert( json_object_get_type( value ) == json_type_int );
const int v = json_object_get_int( value );
el.SetValue(v, validx);
}
locde = el.GetAsDataElement();
}
break;
case VR::SL:
{
Element<VR::SL,VM::VM1_n> el;
el.SetLength( valuelen * vrsizeof );
for( int validx = 0; validx < valuelen; ++validx )
{
json_object * value = json_object_array_get_idx ( jvalue, validx );
gdcm_assert( json_object_get_type( value ) == json_type_int );
const int v = json_object_get_int( value );
el.SetValue(v, validx);
}
locde = el.GetAsDataElement();
}
break;
case VR::UL:
{
Element<VR::UL,VM::VM1_n> el;
el.SetLength( valuelen * vrsizeof );
for( int validx = 0; validx < valuelen; ++validx )
{
json_object * value = json_object_array_get_idx ( jvalue, validx );
gdcm_assert( json_object_get_type( value ) == json_type_int );
const int v = json_object_get_int( value );
el.SetValue(v, validx);
}
locde = el.GetAsDataElement();
}
break;
case VR::AT:
{
Element<VR::AT,VM::VM1_n> el;
el.SetLength( valuelen * vrsizeof );
for( int validx = 0; validx < valuelen; ++validx )
{
json_object * value = json_object_array_get_idx ( jvalue, validx );
gdcm_assert( json_object_get_type( value ) == json_type_string );
const char *atstr = json_object_get_string( value );
Tag t;
t.ReadFromContinuousString( atstr );
el.SetValue(t, validx);
}
locde = el.GetAsDataElement();
}
break;
default:
gdcm_assert( 0 );
}
if( !locde.IsEmpty() )
de.SetValue( locde.GetValue() );
}
else if( jvaluebintype == json_type_array )
{
DataElement locde;
const int valuelen = json_object_array_length ( jvaluebin );
switch( vrtype )
{
case VR::UN:
case VR::INVALID:
case VR::OB:
case VR::OD:
case VR::OF:
case VR::OW:
{
gdcm_assert( valuelen == 1 || valuelen == 0 );
if( valuelen )
{
json_object * value = json_object_array_get_idx ( jvaluebin, 0 );
json_type valuetype = json_object_get_type( value );
if( value )
{
gdcm_assert( valuetype != json_type_null );
const char * value_str = json_object_get_string ( value );
gdcm_assert( value_str );
const size_t len64 = strlen( value_str );
const size_t len = Base64::GetDecodeLength( value_str, len64 );
std::vector<char> buffer;
buffer.resize( len );
const size_t ret = Base64::Decode( &buffer[0], len,
value_str, len64 );
gdcm_assert( ret != 0 );
locde.SetByteValue( &buffer[0], len );
}
else
{
gdcm_assert( valuelen == 1 );
gdcm_assert( valuetype == json_type_null );
}
}
}
break;
default:
gdcm_assert( 0 );
}
if( !locde.IsEmpty() )
de.SetValue( locde.GetValue() );
}
else
{
gdcm_assert( jvaluebintype == json_type_null && jvaluetype == json_type_null );
}
}
}
#endif
#endif
bool JSON::Decode(std::istream & is, DataSet & ds)
{
#ifdef GDCM_USE_SYSTEM_JSON
#ifdef JSON_C_VERSION
json_object *jobj = NULL;
const char *mystring = NULL;
int stringlen = 0;
enum json_tokener_error jerr;
std::string str;
json_tokener * tok = json_tokener_new ();
do
{
std::getline( is, str );
mystring = str.c_str();
stringlen = str.size();
jobj = json_tokener_parse_ex(tok, mystring, stringlen);
} while ((jerr = json_tokener_get_error(tok)) == json_tokener_continue );
if (jerr != json_tokener_success)
{
fprintf(stderr, "Error: %s\n", json_tokener_error_desc(jerr));
gdcm_assert( 0 );
}
if (tok->char_offset < stringlen) {
}
json_tokener_free( tok );
#else
std::stringstream ss;
std::string str;
while( std::getline( is, str ) )
{
ss << str;
}
const std::string & wholestr = ss.str();
json_object *obj;
obj = json_tokener_parse( wholestr.c_str() );
#endif
#ifdef JSON_C_VERSION
json_object_iterator it;
json_object_iterator itEnd;
it = json_object_iter_begin(jobj);
itEnd = json_object_iter_end(jobj);
while (!json_object_iter_equal(&it, &itEnd))
{
const char *name = json_object_iter_peek_name(&it);
gdcm_assert( name );
json_object * value = json_object_iter_peek_value (&it);
DataElement de;
ProcessJSONElement( name, value, de );
ds.Insert( de );
json_object_iter_next(&it);
}
return true;
#else
gdcmErrorMacro( "Version too old" );
return false;
#endif
#else
(void)is;
(void)ds;
return false;
#endif
}
}