netcdf-c/nczarr_test/zisjson.c
Dennis Heimbigner 9f78be8bb8 Allow the read/write of JSON-valued Zarr attributes.
A number of other packages that read/write Zarr insert
attributes whose value is a dictionary containing specialized
information.  An example is the GDAL Driver convention (see
https://gdal.org/drivers/raster/zarr.html).

In order to handle such attributes, this PR enforces a special
convention. It applies to both pure Zarr an NCZarr format as
written by the netdf-c library.

The convention is as follows:

## Reading
Suppose an attribute is read from *.zattrs* and it has a JSON
value that is a a dictionary.  In this case, the JSON dictionary
is converted to a string value.  It then appears in the netcdf-c
API as if it is a character valued attribute of the same name,
and whose value is the "stringified" dictionary.

# Writing
Suppose an attribute is of type character and its *value* *looks like*
a JSON dictionary. In this case, it is parsed to JSON
and written as the value of the attribute in the NCZarr file.
Here the *value* is the concatenation of all the characters
in the attributes netcdf-c value.
The term "looks like" means that the *value*'s first character is
"{", its last value is "}", and it can be successfully parsed
by a JSON parser.

A test case, *nczarr_test/run_jsonconventions.sh* was also added.

## Misc. Unrelated Changes

1. Fix an error in nc_test4/tst_broken_files.c
2. Modify the internal JSON parser API.
3. Modify the nczarr_test/zisjson program is modified to support
   this convention.
2022-04-06 18:22:59 -06:00

152 lines
3.0 KiB
C

/*
* Copyright 2018, University Corporation for Atmospheric Research
* See netcdf/COPYRIGHT file for copying and redistribution conditions.
*/
/* Parse input to see if it looks like json.
Output 1 or 0.
*/
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "stdlib.h"
#include "stdio.h"
#include "string.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#if defined(_WIN32) && !defined(__MINGW32__)
#include "XGetopt.h"
#else
#include <getopt.h>
#endif
#include "netcdf.h"
#include "nclist.h"
#include "ncjson.h"
#define MAXREAD 8192
/* Command line options */
struct Jsonpptions {
int trace;
} jsonoptions;
static const char*
sortname(int thesort)
{
switch(thesort) {
default: break;
case NCJ_INT: return "NCJ_INT";
case NCJ_DOUBLE: return "NCJ_DOUBLE";
case NCJ_BOOLEAN: return "NCJ_BOOLEAN";
case NCJ_STRING: return "NCJ_STRING";
case NCJ_DICT: return "NCJ_DICT";
case NCJ_ARRAY: return "NCJ_ARRAY";
case NCJ_NULL: return "NCJ_NULL";
}
return "?";
}
static void
jsontrace(NCjson* json, int depth)
{
int i;
if(json == NULL) goto done;
printf("[%d] sort=%s",depth,sortname(NCJsort(json)));
switch(NCJsort(json)) {
case NCJ_INT:
case NCJ_DOUBLE:
case NCJ_BOOLEAN:
case NCJ_STRING:
printf(" string=|%s|\n",NCJstring(json));
break;
case NCJ_NULL:
printf("\n");
break;
case NCJ_ARRAY:
printf("\n");
for(i=0;i<NCJlength(json);i++)
jsontrace(NCJith(json,i),depth+1);
break;
case NCJ_DICT:
printf("\n");
for(i=0;i<NCJlength(json);i+=2) {
jsontrace(NCJith(json,i),depth+1);
jsontrace(NCJith(json,i+1),depth+1);
} break;
default: break;
}
done:
return;
}
int
main(int argc, char** argv)
{
int stat = NC_NOERR;
char text[MAXREAD+1];
NCjson* json = NULL;
int i, red, c;
FILE* f = NULL;
nc_initialize();
memset((void*)&jsonoptions,0,sizeof(jsonoptions));
while ((c = getopt(argc, argv, "t")) != EOF) {
switch(c) {
case 't': jsonoptions.trace = 1; break;
case '?':
fprintf(stderr,"unknown option\n");
exit(1);
}
}
/* get file argument */
argc -= optind;
argv += optind;
if (argc > 1) {
fprintf(stderr, "zisjson: only one input file argument permitted\n");
exit(1);
}
if (argc == 0)
f = stdin;
else {
/* use argv[0] as input */
f = fopen(argv[0],"r");
if(f == NULL) {fprintf(stderr,"No such file: %s\n",argv[1]); exit(1);}
}
/* Read json from stdin */
for(i=0;;i++) {
unsigned char c;
red = fread(&c, 1, 1, f);
if(red != 1) break;
if(i < MAXREAD) text[i] = (char)c;
}
if(i >= MAXREAD) {
fprintf(stderr,"Input too long\n");
exit(1);
}
text[i] = '\0';
if(i == 0) {
stat = NC_EEMPTY;
} else {
stat = NCJparse(text,0,&json);
if(!stat) {
if(jsonoptions.trace) jsontrace(json,0);
NCJreclaim(json);
}
}
printf("%d",(stat?0:1)); /* parse success|failure */
if(f != stdin) fclose(f);
return 0;
}