Coverage Report

Created: 2026-01-04 06:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/netcdf-c/libnczarr/zmetadata2.c
Line
Count
Source
1
/*********************************************************************
2
 *   Copyright 2018, UCAR/Unidata
3
 *   See netcdf/COPYRIGHT file for copying and redistribution conditions.
4
 *********************************************************************/
5
6
#include "zincludes.h"
7
8
0
#define  MINIMIM_CSL_REP_RAW "{\"metadata\":{},\"zarr_consolidated_format\":1}"
9
10
/// @brief Retrieve the group and variable names contained within a group specified by `key` on the storage. The order of the names may be arbitrary
11
/// @param zfile - The zarr file info structure
12
/// @param key - the key of the node - group
13
/// @param groups - NClist where names will be added
14
/// @param variables - NClist where names will be added
15
/// @return `NC_NOERR` if succeeding
16
int NCZMD_v2_list_nodes(NCZ_FILE_INFO_T *zfile, const char * key, NClist *groups, NClist *vars);
17
18
/// @brief Retrieve the group and variable names contained within a group specified by `key` on the consolidated representation. The order of the names may be arbitrary
19
/// @param zfile - The zarr file info structure
20
/// @param key - the key of the node - group
21
/// @param groups - NClist where names will be added
22
/// @param variables - NClist where names will be added
23
/// @return `NC_NOERR` if succeeding
24
int NCZMD_v2_csl_list_nodes(NCZ_FILE_INFO_T *zfile, const char * key, NClist *groups, NClist *vars);
25
26
/// @brief Retrieve the group names contained within a group specified by `key` on the storage. The order of the names may be arbitrary
27
/// @param zfile - The zarr file info structure
28
/// @param key - the key of the node - group
29
/// @param groups - NClist where names will be added
30
/// @return `NC_NOERR` if succeeding
31
int NCZMD_v2_list_groups(NCZ_FILE_INFO_T *zfile, const char * key, NClist *groups);
32
33
/// @brief Retrieve the group names contained within a group specified by `key` on the consolidated represention. The order of the names may be arbitrary
34
/// @param zfile - The zarr file info structure
35
/// @param key - the key of the node - group
36
/// @param groups - NClist where names will be added
37
/// @return `NC_NOERR` if succeeding
38
int NCZMD_v2_csl_list_groups(NCZ_FILE_INFO_T *zfile, const char * key, NClist *groups);
39
40
/// @brief Retrieve the variable names contained by a group specified by `key` on the storage. The order of the names may be arbitrary
41
/// @param zfile - The zarr file info structure
42
/// @param key - the key of the node - group
43
/// @param variables - NClist where names will be added
44
/// @return `NC_NOERR` if succeeding
45
int NCZMD_v2_list_variables(NCZ_FILE_INFO_T *zfile, const char * key, NClist * variables);
46
47
/// @brief Retrieve the variable names contained by a group specified by `key` on the consolidated representation. The order of the names may be arbitrary
48
/// @param zfile - The zarr file info structure
49
/// @param key - the key of the node - group
50
/// @param variables - NClist where names will be added
51
/// @return `NC_NOERR` if succeeding
52
int NCZMD_v2_csl_list_variables(NCZ_FILE_INFO_T *zfile, const char * key, NClist *groups);
53
54
/// @brief Retrieve JSON metadata of a given type for the specified `key` from the storage
55
/// @param zfile - The zarr file info structure
56
/// @param zobj - The type of metadata to set
57
/// @param key - the key of the node - group or array
58
/// @param jobj - JSON to be written
59
/// @return `NC_NOERR` if succeeding
60
int fetch_json_content_v2(NCZ_FILE_INFO_T *zfile, NCZMD_MetadataType zarr_obj_type, const char *key, NCjson **jobj);
61
62
/// @brief Retrieve JSON metadata of a given type for the specified `key` from the consolidate representation
63
/// @param zfile - The zarr file info structure
64
/// @param zobj - The type of metadata to set
65
/// @param key - the key of the node - group or array
66
/// @param jobj - JSON to be written
67
/// @return `NC_NOERR` if succeeding
68
int fetch_csl_json_content_v2(NCZ_FILE_INFO_T *zfile, NCZMD_MetadataType zarr_obj_type, const char *key, NCjson **jobj);
69
70
/// @brief Write JSON metadata of a given type for the specified `key` to the storage
71
/// @param zfile - The zarr file info structure
72
/// @param zobj - The type of metadata to set
73
/// @param key - the key of the node - group or array
74
/// @param jobj - JSON to be written
75
/// @return `NC_NOERR` if succeeding
76
int update_json_content_v2(NCZ_FILE_INFO_T *zfile, NCZMD_MetadataType zobj, const char *key, const NCjson *jobj);
77
78
/// @brief Updates the JSON metadata of a given type for the specified `key` to the consolidated representation
79
/// @param zfile - The zarr file info structure
80
/// @param zobj - The type of metadata to set
81
/// @param key - the key of the node - group or array
82
/// @param jobj - JSON to be written
83
/// @return `NC_NOERR` if succeeding
84
int update_csl_json_content_v2(NCZ_FILE_INFO_T *zfile, NCZMD_MetadataType zobj, const char *key, const NCjson *jobj);
85
86
/// @brief Place holder for non consolidated handler
87
/// @param json - Not used!
88
/// @return `NC_NOERR` always
89
int validate_consolidated_json_noop_v2(const NCjson *json);
90
91
///@brief Checks if `json` is a compliant to what .zmetadata expects
92
///   - non empty `{}` in "metadata"
93
///   - `zarr_consolidated_format` exists and is `1`
94
/// @param json corresponding to the full .zmetadata content
95
/// @return `NC_NOERR` if valid, `NC_EZARRMETA` otherwise
96
int validate_consolidated_json_v2(const NCjson *json);
97
98
static const NCZ_Metadata NCZ_md2_table = {
99
  ZARRFORMAT2,
100
  NCZ_METADATA_VERSION,
101
  ZARR_NOT_CONSOLIDATED,
102
  .jcsl = NULL,
103
104
  .list_nodes = NCZMD_v2_list_nodes,
105
  .list_groups = NCZMD_v2_list_groups,
106
  .list_variables = NCZMD_v2_list_variables,
107
108
  .fetch_json_content = fetch_json_content_v2,
109
  .update_json_content = update_json_content_v2,
110
    .validate_consolidated = validate_consolidated_json_noop_v2,
111
};
112
113
const NCZ_Metadata *NCZ_metadata_handler2 = &NCZ_md2_table;
114
115
static const NCZ_Metadata NCZ_csl_md2_table = {
116
  ZARRFORMAT2,
117
  NCZ_METADATA_VERSION,
118
  ZARR_CONSOLIDATED,
119
  .jcsl = NULL,
120
121
  .list_nodes = NCZMD_v2_csl_list_nodes,
122
  .list_groups = NCZMD_v2_csl_list_groups,
123
  .list_variables = NCZMD_v2_csl_list_variables,
124
125
  .fetch_json_content = fetch_csl_json_content_v2,
126
  .update_json_content = update_csl_json_content_v2,
127
    .validate_consolidated = validate_consolidated_json_v2,
128
};
129
130
const NCZ_Metadata *NCZ_csl_metadata_handler2 = &NCZ_csl_md2_table;
131
132
int NCZMD_v2_list_nodes(NCZ_FILE_INFO_T *zfile, const char * key, NClist *groups, NClist *variables)
133
0
{
134
0
  size_t i;
135
0
  int stat = NC_NOERR;
136
0
  char *subkey = NULL;
137
0
  char *zkey = NULL;
138
0
  NClist *matches = nclistnew();
139
140
0
  if ((stat = nczmap_search(zfile->map, key, matches)))
141
0
    goto done;
142
0
  for (i = 0; i < nclistlength(matches); i++)
143
0
  {
144
0
    const char *name = nclistget(matches, i);
145
0
    if (name[0] == NCZM_DOT)
146
0
      continue;
147
0
    if ((stat = nczm_concat(key, name, &subkey)))
148
0
      goto done;
149
0
    if ((stat = nczm_concat(subkey, Z2GROUP, &zkey)))
150
0
      goto done;
151
0
    if (NC_NOERR == nczmap_exists(zfile->map, zkey) && groups != NULL)
152
0
      nclistpush(groups, strdup(name));
153
154
0
    nullfree(zkey);
155
0
    zkey = NULL;
156
0
    if ((stat = nczm_concat(subkey, Z2ARRAY, &zkey)))
157
0
      goto done;
158
0
    if (NC_NOERR == nczmap_exists(zfile->map, zkey) && variables != NULL)
159
0
      nclistpush(variables, strdup(name));
160
0
    stat = NC_NOERR;
161
162
0
    nullfree(subkey);
163
0
    subkey = NULL;
164
0
    nullfree(zkey);
165
0
    zkey = NULL;
166
0
  }
167
168
0
done:
169
0
  nullfree(subkey);
170
0
  nullfree(zkey);
171
0
  nclistfreeall(matches);
172
0
  return stat;
173
0
}
174
175
int NCZMD_v2_csl_list_nodes(NCZ_FILE_INFO_T *zfile, const char * key, NClist *groups, NClist *variables)
176
0
{
177
0
  size_t i;
178
0
  int stat = NC_NOERR;
179
0
  char *subkey = NULL;
180
0
  char *zgroup = NULL;
181
0
  NClist *segments = nclistnew();
182
183
0
  const char *group = key + (key[0] == '/');
184
0
  size_t lgroup = strlen(group);
185
186
0
  const NCjson *jmetadata = NULL;
187
0
  NCJdictget(zfile->metadata.jcsl, "metadata", &jmetadata);
188
0
  for (i = 0; i < NCJdictlength(jmetadata); i++)
189
0
  {
190
0
    NCjson *jname = NCJdictkey(jmetadata, i);
191
0
    const char *fullname = NCJstring(jname);
192
0
    size_t lfullname = strlen(fullname);
193
0
    if (lfullname < lgroup ||
194
0
      strncmp(fullname, group, lgroup) ||
195
0
      (lgroup > 0 && fullname[lgroup] != NCZM_SEP[0]))
196
0
    {
197
0
      continue;
198
0
    }
199
200
0
    nclistclearall(segments);
201
0
    NC_split_delim(fullname + lgroup + (lgroup > 0), NCZM_SEP[0] ,segments);
202
0
    size_t slen = nclistlength(segments);
203
0
    if (slen != 2) {
204
0
      continue;
205
0
    }
206
207
0
    if (strncmp(Z2GROUP, nclistget(segments,1), sizeof(Z2GROUP)) == 0 && groups != NULL)
208
0
    {
209
0
      nclistpush(groups, strdup(nclistget(segments,0)));
210
0
    }
211
0
    else if (strncmp(Z2ARRAY, nclistget(segments,1), sizeof(Z2ARRAY)) == 0 && variables != NULL)
212
0
    {
213
0
      nclistpush(variables, strdup(nclistget(segments,0)));
214
0
    }
215
0
  }
216
0
  nullfree(subkey);
217
0
  nullfree(zgroup);
218
0
  nclistfreeall(segments);
219
0
  return stat;
220
0
}
221
222
int NCZMD_v2_list_groups(NCZ_FILE_INFO_T *zfile, const char * key, NClist *groups)
223
0
{
224
0
  return NCZMD_v2_list_nodes(zfile, key, groups, NULL);
225
0
}
226
227
int NCZMD_v2_csl_list_groups(NCZ_FILE_INFO_T *zfile, const char * key, NClist *groups)
228
0
{
229
0
  return NCZMD_v2_csl_list_nodes(zfile, key, groups, NULL);
230
0
}
231
232
int NCZMD_v2_list_variables(NCZ_FILE_INFO_T *zfile, const char * key, NClist *variables)
233
0
{
234
0
  return NCZMD_v2_list_nodes(zfile, key, NULL, variables);
235
0
}
236
237
int NCZMD_v2_csl_list_variables(NCZ_FILE_INFO_T *zfile, const char* key, NClist *variables)
238
0
{
239
0
  return NCZMD_v2_csl_list_nodes(zfile, key, NULL, variables);
240
0
}
241
242
0
static int zarr_obj_type2suffix(NCZMD_MetadataType zarr_obj_type, const char **suffix){
243
0
  switch (zarr_obj_type)
244
0
  {
245
0
    case NCZMD_GROUP:
246
0
      *suffix = Z2GROUP;
247
0
      break;
248
0
    case NCZMD_ATTRS:
249
0
      *suffix = Z2ATTRS;
250
0
      break;
251
0
    case NCZMD_ARRAY:
252
0
      *suffix = Z2ARRAY;
253
0
      break;
254
0
    default:
255
0
      return NC_EINVAL;
256
0
  }
257
0
  return NC_NOERR;
258
0
}
259
260
int fetch_json_content_v2(NCZ_FILE_INFO_T *zfile, NCZMD_MetadataType zobj, const char *prefix, NCjson **jobj)
261
0
{
262
0
  int stat = NC_NOERR;
263
0
  const char *suffix;
264
0
  char * key = NULL;
265
0
  if ((stat = zarr_obj_type2suffix(zobj, &suffix))
266
0
    || (stat = nczm_concat(prefix, suffix, &key))){
267
0
    goto done;
268
0
  }
269
270
0
  stat = NCZ_downloadjson(zfile->map, key, jobj);
271
0
done:
272
0
  nullfree(key);
273
0
  return stat;
274
0
}
275
276
int fetch_csl_json_content_v2(NCZ_FILE_INFO_T *zfile, NCZMD_MetadataType zobj_t, const char *prefix, NCjson **jobj)
277
0
{
278
0
  int stat = NC_NOERR;
279
0
  const NCjson *jtmp = NULL;
280
0
  const char *suffix;
281
0
  char * key = NULL;
282
0
  if ( (stat = zarr_obj_type2suffix(zobj_t, &suffix))
283
0
     ||(stat = nczm_concat(prefix, suffix, &key))){
284
0
    return stat;
285
0
  }
286
287
0
  if (NCJdictget(zfile->metadata.jcsl, "metadata", &jtmp) == 0
288
0
  && jtmp && NCJsort(jtmp) == NCJ_DICT)
289
0
  {
290
0
    NCjson *tmp = NULL;
291
0
    if ((stat = NCJdictget(jtmp, key + (key[0] == '/'), (const NCjson**)&tmp)))
292
0
      goto done;
293
0
    if (tmp)
294
0
      NCJclone(tmp, jobj);
295
0
  }
296
0
done:
297
0
  nullfree(key);
298
0
  return stat;
299
300
0
}
301
302
int update_csl_json_content_v2(NCZ_FILE_INFO_T *zfile, NCZMD_MetadataType zobj_t, const char *prefix, const NCjson *jobj)
303
0
{
304
0
  int stat = NC_NOERR;
305
306
0
  if ((stat=update_json_content_v2(zfile,zobj_t,prefix,jobj))){
307
0
    goto done;
308
0
  }
309
0
  if (zfile->metadata.jcsl == NULL &&
310
0
    (stat = NCJparse(MINIMIM_CSL_REP_RAW,0,&zfile->metadata.jcsl))){
311
0
    goto done;
312
0
  }
313
314
0
  NCjson * jrep = NULL;
315
0
  if ((stat = NCJdictget(zfile->metadata.jcsl,"metadata", (const NCjson**)&jrep)) || jrep == NULL) {
316
0
    goto done;
317
0
  }
318
319
0
  const char *suffix;
320
0
  char * key = NULL;
321
0
  if ((stat = zarr_obj_type2suffix(zobj_t, &suffix))
322
0
    || (stat = nczm_concat(prefix, suffix, &key))){
323
0
    goto done;
324
0
  }
325
0
  const char * mdkey= key[0] == '/'?key+1:key;
326
0
  NCjson * jval = NULL;
327
0
  NCJclone(jobj,&jval);
328
0
  NCJinsert(jrep, mdkey, jval);
329
0
done:
330
0
  free(key);
331
0
  return stat;
332
333
0
}
334
int update_json_content_v2(NCZ_FILE_INFO_T *zfile, NCZMD_MetadataType zobj, const char *prefix, const NCjson *jobj)
335
0
{
336
0
  int stat = NC_NOERR;
337
0
  const char *suffix;
338
0
  char * key = NULL;
339
0
  if ((stat = zarr_obj_type2suffix(zobj, &suffix))
340
0
    || (stat = nczm_concat(prefix, suffix, &key))){
341
0
    goto done;
342
0
  }
343
344
0
  stat = NCZ_uploadjson(zfile->map, key, jobj);
345
0
done:
346
0
  nullfree(key);
347
0
  return stat;
348
0
}
349
350
0
int validate_consolidated_json_noop_v2(const NCjson *json){
351
0
    NC_UNUSED(json);
352
0
    return NC_NOERR;
353
0
}
354
355
int validate_consolidated_json_v2(const NCjson *json)
356
0
{
357
0
    if (json == NULL || NCJsort(json) != NCJ_DICT || NCJdictlength(json) == 0)
358
0
        return NC_EZARRMETA;
359
360
0
    const NCjson *jtmp = NULL;
361
0
    NCJdictget(json, "metadata", &jtmp);
362
0
    if (jtmp == NULL || NCJsort(jtmp) != NCJ_DICT || NCJdictlength(jtmp) == 0)
363
0
        return NC_EZARRMETA;
364
365
0
    jtmp = NULL;
366
0
    struct NCJconst format = {0,0,0,0};
367
0
    NCJdictget(json, "zarr_consolidated_format", &jtmp);
368
0
    if (jtmp == NULL || NCJsort(jtmp) != NCJ_INT || NCJcvt(jtmp,NCJ_INT, &format ) || format.ival != 1)
369
0
        return NC_EZARRMETA;
370
371
0
    return NC_NOERR;
372
0
}