1212
1313#undef FILLONCLOSE
1414
15+ /*mnemonics*/
16+ #define DICTOPEN '{'
17+ #define DICTCLOSE '}'
18+
1519/* Forward */
1620static int ncz_collect_dims (NC_FILE_INFO_T * file , NC_GRP_INFO_T * grp , NCjson * * jdimsp );
1721static int ncz_sync_var (NC_FILE_INFO_T * file , NC_VAR_INFO_T * var , int isclose );
1822
1923static int ncz_jsonize_atts (NCindex * attlist , NCjson * * jattrsp );
2024static int load_jatts (NCZMAP * map , NC_OBJ * container , int nczarrv1 , NCjson * * jattrsp , NClist * * atypes );
21- static int zconvert (nc_type typeid , size_t typelen , void * dst , NCjson * src );
25+ static int zconvert (nc_type typeid , size_t typelen , NCjson * src , void * dst );
2226static int computeattrinfo (const char * name , NClist * atypes , NCjson * values ,
2327 nc_type * typeidp , size_t * typelenp , size_t * lenp , void * * datap );
2428static int parse_group_content (NCjson * jcontent , NClist * dimdefs , NClist * varnames , NClist * subgrps );
@@ -37,6 +41,8 @@ static int computeattrdata(nc_type* typeidp, NCjson* values, size_t* typelenp, s
3741static int inferattrtype (NCjson * values , nc_type * typeidp );
3842static int mininttype (unsigned long long u64 , int negative );
3943static int computedimrefs (NC_FILE_INFO_T * file , NC_VAR_INFO_T * var , int purezarr , int xarray , int ndims , NClist * dimnames , size64_t * shapes , NC_DIM_INFO_T * * dims );
44+ static int read_dict (NCjson * jdict , NCjson * * jtextp );
45+ static int write_dict (size_t len , const void * data , NCjson * * jsonp );
4046
4147/**************************************************/
4248/**************************************************/
@@ -791,6 +797,7 @@ ncz_sync_atts(NC_FILE_INFO_T* file, NC_OBJ* container, NCindex* attlist, int isc
791797Note that this does not push to the file.
792798Also note that attributes of length 1 are stored as singletons, not arrays.
793799This is to be more consistent with pure zarr.
800+ Also implements the JSON dictionary convention.
794801@param attlist - [in] the attributes to dictify
795802@param jattrsp - [out] the json'ized att list
796803@return NC_NOERR
@@ -800,7 +807,7 @@ static int
800807ncz_jsonize_atts (NCindex * attlist , NCjson * * jattrsp )
801808{
802809 int stat = NC_NOERR ;
803- int i ;
810+ int i , isdict ;
804811 NCjson * jattrs = NULL ;
805812 NCjson * akey = NULL ;
806813 NCjson * jdata = NULL ;
@@ -810,9 +817,18 @@ ncz_jsonize_atts(NCindex* attlist, NCjson** jattrsp)
810817 /* Iterate over the attribute list */
811818 for (i = 0 ;i < ncindexsize (attlist );i ++ ) {
812819 NC_ATT_INFO_T * att = (NC_ATT_INFO_T * )ncindexith (attlist ,i );
820+ isdict = 0 ;
813821 /* Create the attribute dict value*/
814- if ((stat = NCZ_stringconvert (att -> nc_typeid ,att -> len ,att -> data ,& jdata )))
815- goto done ;
822+ if (att -> nc_typeid == NC_CHAR
823+ && ((char * )att -> data )[0 ] == DICTOPEN
824+ && ((char * )att -> data )[att -> len - 1 ] == DICTCLOSE ) {
825+ /* this is subject to the JSON dictionary convention? */
826+ if (write_dict (att -> len ,att -> data ,& jdata )== NC_NOERR ) isdict = 1 ;
827+ }
828+ if (!isdict ) {
829+ if ((stat = NCZ_stringconvert (att -> nc_typeid ,att -> len ,att -> data ,& jdata )))
830+ goto done ;
831+ }
816832 if ((stat = NCJinsert (jattrs ,att -> hdr .name ,jdata ))) goto done ;
817833 jdata = NULL ;
818834 }
@@ -933,7 +949,7 @@ load_jatts(NCZMAP* map, NC_OBJ* container, int nczarrv1, NCjson** jattrsp, NClis
933949
934950/* Convert a json value to actual data values of an attribute. */
935951static int
936- zconvert (nc_type typeid , size_t typelen , void * dst0 , NCjson * src )
952+ zconvert (nc_type typeid , size_t typelen , NCjson * src , void * dst0 )
937953{
938954 int stat = NC_NOERR ;
939955 int i ;
@@ -1019,19 +1035,28 @@ computeattrdata(nc_type* typeidp, NCjson* values, size_t* typelenp, size_t* lenp
10191035 void * data = NULL ;
10201036 size_t typelen ;
10211037 nc_type typeid = NC_NAT ;
1038+ NCjson * jtext = NULL ;
10221039 int reclaimvalues = 0 ;
10231040
10241041 /* Get assumed type */
10251042 if (typeidp ) typeid = * typeidp ;
10261043 if (typeid == NC_NAT ) if ((stat = inferattrtype (values ,& typeid ))) goto done ;
10271044 if (typeid == NC_NAT ) {stat = NC_EBADTYPE ; goto done ;}
10281045
1046+ if ((stat = NC4_inq_atomic_type (typeid , NULL , & typelen )))
1047+ goto done ;
1048+
10291049 /* Collect the length of the attribute; might be a singleton */
10301050 switch (NCJsort (values )) {
1031- case NCJ_DICT : stat = NC_ENCZARR ; goto done ;
10321051 case NCJ_ARRAY :
10331052 count = NCJlength (values );
10341053 break ;
1054+ case NCJ_DICT :
1055+ /* Apply the JSON dictionary convention and convert to string */
1056+ if ((stat = read_dict (values ,& jtext ))) goto done ;
1057+ values = jtext ; jtext = NULL ;
1058+ reclaimvalues = 1 ;
1059+ /* fall thru */
10351060 case NCJ_STRING : /* requires special handling as an array of characters; also look out for empty string */
10361061 if (typeid == NC_CHAR ) {
10371062 count = strlen (NCJstring (values ));
@@ -1044,18 +1069,16 @@ computeattrdata(nc_type* typeidp, NCjson* values, size_t* typelenp, size_t* lenp
10441069 break ;
10451070 }
10461071
1047- if (count > 0 ) {
1072+ if (count > 0 && data == NULL ) {
10481073 /* Allocate data space */
1049- if ((stat = NC4_inq_atomic_type (typeid , NULL , & typelen )))
1050- goto done ;
10511074 if (typeid == NC_CHAR )
10521075 data = malloc (typelen * (count + 1 ));
10531076 else
10541077 data = malloc (typelen * count );
10551078 if (data == NULL )
10561079 {stat = NC_ENOMEM ; goto done ;}
10571080 /* convert to target type */
1058- if ((stat = zconvert (typeid , typelen , data , values )))
1081+ if ((stat = zconvert (typeid , typelen , values , data )))
10591082 goto done ;
10601083 }
10611084 if (lenp ) * lenp = count ;
@@ -1094,7 +1117,9 @@ inferattrtype(NCjson* value, nc_type* typeidp)
10941117 case NCJ_NULL :
10951118 typeid = NC_CHAR ;
10961119 return NC_NOERR ;
1097- case NCJ_DICT : /* fall thru */
1120+ case NCJ_DICT :
1121+ typeid = NC_CHAR ;
1122+ goto done ;
10981123 case NCJ_UNDEF :
10991124 return NC_EINVAL ;
11001125 default : /* atomic */
@@ -2302,42 +2327,48 @@ computedimrefs(NC_FILE_INFO_T* file, NC_VAR_INFO_T* var, int purezarr, int xarra
23022327 return THROW (stat );
23032328}
23042329
2305- #if 0
2306- Not currently used
2307- Special compatibility case :
2308- if the value of the attribute is a dictionary ,
2309- or an array with non - atomic values , then
2310- then stringify it and pretend it is of char type .
2311- /* Return 1 if this json is not an
2312- atomic value or an array of atomic values.
2313- That is, it does not look like valid
2314- attribute data.
2330+ /**
2331+ Implement the JSON convention for dictionaries.
2332+
2333+ Reading: If the value of the attribute is a dictionary, then stringify
2334+ it as the value and make the attribute be of type "char".
2335+
2336+ Writing: if the attribute is of type char and looks like a JSON dictionary,
2337+ then parse it as JSON and use that as its value in .zattrs.
23152338*/
2339+
23162340static int
2317- iscomplexjson (NCjson * j )
2341+ read_dict (NCjson * jdict , NCjson * * jtextp )
23182342{
2319- int i ;
2320- switch (NCJsort (j )) {
2321- case NCJ_ARRAY :
2322- /* verify that the elements of the array are not complex */
2323- for (i = 0 ;i < NCJlength (j );i ++ ) {
2324- switch (NCJith (j ,NCJsort (i )))) {
2325- case NCJ_DICT :
2326- case NCJ_ARRAY :
2327- case NCJ_UNDEF :
2328- case NCJ_NULL :
2329- return 1 ;
2330- default : break ;
2331- }
2332- }
2333- return 0 ;
2334- case NCJ_DICT :
2335- case NCJ_UNDEF :
2336- case NCJ_NULL :
2337- break ;
2338- default :
2339- return 0 ;
2340- }
2341- return 1 ;
2343+ int stat = NC_NOERR ;
2344+ NCjson * jtext = NULL ;
2345+ char * text = NULL ;
2346+
2347+ if (jdict == NULL ) {stat = NC_EINVAL ; goto done ;}
2348+ if (NCJsort (jdict ) != NCJ_DICT ) {stat = NC_EINVAL ; goto done ;}
2349+ if (NCJunparse (jdict ,0 ,& text )) {stat = NC_EINVAL ; goto done ;}
2350+ if (NCJnewstring (NCJ_STRING ,text ,& jtext )) {stat = NC_EINVAL ; goto done ;}
2351+ * jtextp = jtext ; jtext = NULL ;
2352+ done :
2353+ NCJreclaim (jtext );
2354+ nullfree (text );
2355+ return stat ;
23422356}
2343- #endif
2357+
2358+ static int
2359+ write_dict (size_t len , const void * data , NCjson * * jsonp )
2360+ {
2361+ int stat = NC_NOERR ;
2362+ NCjson * jdict = NULL ;
2363+
2364+ assert (jsonp != NULL );
2365+ if (NCJparsen (len ,(char * )data ,0 ,& jdict ))
2366+ {stat = NC_EINVAL ; goto done ;}
2367+ if (NCJsort (jdict ) != NCJ_DICT )
2368+ {stat = NC_EINVAL ; goto done ;}
2369+ * jsonp = jdict ; jdict = NULL ;
2370+ done :
2371+ NCJreclaim (jdict );
2372+ return stat ;
2373+ }
2374+
0 commit comments