nodenetcdf 4.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/File.cpp ADDED
@@ -0,0 +1,170 @@
1
+ #include "File.h"
2
+ #include "Group.h"
3
+ #include "Variable.h"
4
+ #include "nodenetcdfjs.h"
5
+ #include <netcdf.h>
6
+ #include <string>
7
+
8
+
9
+ namespace nodenetcdfjs
10
+ {
11
+
12
+ v8::Persistent<v8::Function> File::constructor;
13
+
14
+ File::File(int id_) noexcept
15
+ : id(id_)
16
+ , closed(false)
17
+ {
18
+ }
19
+
20
+ File::~File()
21
+ {
22
+ if (!closed)
23
+ {
24
+ int retval = nc_close(id);
25
+ if (retval != NC_NOERR)
26
+ {
27
+ throw_netcdf_error(v8::Isolate::GetCurrent(), retval);
28
+ }
29
+ }
30
+ }
31
+
32
+ void File::Init(v8::Local<v8::Object> exports)
33
+ {
34
+ v8::Isolate *isolate = exports->GetIsolate();
35
+ v8::Local<v8::FunctionTemplate> tpl = v8::FunctionTemplate::New(isolate, New);
36
+ tpl->SetClassName(v8::String::NewFromUtf8(isolate, "File", v8::NewStringType::kNormal).ToLocalChecked());
37
+ tpl->InstanceTemplate()->SetInternalFieldCount(1);
38
+ NODE_SET_PROTOTYPE_METHOD(tpl, "sync", File::Sync);
39
+ NODE_SET_PROTOTYPE_METHOD(tpl, "close", File::Close);
40
+ NODE_SET_PROTOTYPE_METHOD(tpl, "inspect", File::Inspect);
41
+ constructor.Reset(isolate, tpl->GetFunction(isolate->GetCurrentContext()).ToLocalChecked());
42
+ exports->Set(isolate->GetCurrentContext(),
43
+ v8::String::NewFromUtf8(isolate, "File", v8::NewStringType::kNormal).ToLocalChecked(),
44
+ tpl->GetFunction(isolate->GetCurrentContext()).ToLocalChecked());
45
+ }
46
+
47
+ void File::New(const v8::FunctionCallbackInfo<v8::Value> &args)
48
+ {
49
+ v8::Isolate *isolate = args.GetIsolate();
50
+
51
+ if (args.Length() < 2)
52
+ {
53
+ isolate->ThrowException(v8::Exception::TypeError(
54
+ v8::String::NewFromUtf8(isolate, "Wrong number of arguments", v8::NewStringType::kNormal)
55
+ .ToLocalChecked()));
56
+ return;
57
+ }
58
+
59
+ if (args.IsConstructCall())
60
+ {
61
+ const std::string filename =
62
+ *v8::String::Utf8Value(isolate, args[0]->ToString(isolate->GetCurrentContext()).ToLocalChecked());
63
+ const std::string mode_arg =
64
+ *v8::String::Utf8Value(isolate, args[1]->ToString(isolate->GetCurrentContext()).ToLocalChecked());
65
+
66
+ int format = NC_NETCDF4;
67
+ int id = -1;
68
+
69
+ if (args.Length() > 2)
70
+ {
71
+ const std::string format_arg =
72
+ *v8::String::Utf8Value(isolate, args[2]->ToString(isolate->GetCurrentContext()).ToLocalChecked());
73
+
74
+ if (format_arg == "classic")
75
+ {
76
+ format = 0;
77
+ }
78
+ else if (format_arg == "classic64")
79
+ {
80
+ format = NC_64BIT_OFFSET;
81
+ }
82
+ else if (format_arg == "nodenetcdf")
83
+ {
84
+ format = NC_NETCDF4;
85
+ }
86
+ else if (format_arg == "nodenetcdfclassic")
87
+ {
88
+ format = NC_NETCDF4 | NC_CLASSIC_MODEL;
89
+ }
90
+ else
91
+ {
92
+ isolate->ThrowException(v8::Exception::TypeError(
93
+ v8::String::NewFromUtf8(isolate, "Unknown file format", v8::NewStringType::kNormal)
94
+ .ToLocalChecked()));
95
+ return;
96
+ }
97
+ }
98
+
99
+ int retval = NC_NOERR;
100
+ if (mode_arg == "r")
101
+ {
102
+ retval = nc_open(filename.c_str(), NC_NOWRITE, &id);
103
+ }
104
+ else if (mode_arg == "w")
105
+ {
106
+ retval = nc_open(filename.c_str(), NC_WRITE, &id);
107
+ }
108
+ else if (mode_arg == "c")
109
+ {
110
+ retval = nc_create(filename.c_str(), format | NC_NOCLOBBER, &id);
111
+ }
112
+ else if (mode_arg == "c!")
113
+ {
114
+ retval = nc_create(filename.c_str(), format | NC_CLOBBER, &id);
115
+ }
116
+ else
117
+ {
118
+ isolate->ThrowException(v8::Exception::TypeError(
119
+ v8::String::NewFromUtf8(isolate, "Unknown file mode", v8::NewStringType::kNormal).ToLocalChecked()));
120
+ return;
121
+ }
122
+ if (retval != NC_NOERR)
123
+ {
124
+ throw_netcdf_error(isolate, retval);
125
+ return;
126
+ }
127
+ auto *obj = new File(id);
128
+ obj->Wrap(args.This());
129
+ args.This()->Set(isolate->GetCurrentContext(),
130
+ v8::String::NewFromUtf8(isolate, "root", v8::NewStringType::kNormal).ToLocalChecked(),
131
+ (new Group(id))->handle());
132
+ args.GetReturnValue().Set(args.This());
133
+ }
134
+ else
135
+ {
136
+ const int argc = 1;
137
+ v8::Local<v8::Value> argv[argc] = {args[0]};
138
+ v8::Local<v8::Function> cons = v8::Local<v8::Function>::New(isolate, constructor);
139
+ args.GetReturnValue().Set(cons->NewInstance(isolate->GetCurrentContext(), argc, argv).ToLocalChecked());
140
+ }
141
+ }
142
+
143
+ void File::Sync(const v8::FunctionCallbackInfo<v8::Value> &args)
144
+ {
145
+ File *obj = node::ObjectWrap::Unwrap<File>(args.Holder());
146
+ int retval = nc_sync(obj->id);
147
+ if (retval != NC_NOERR)
148
+ {
149
+ throw_netcdf_error(args.GetIsolate(), retval);
150
+ }
151
+ }
152
+
153
+ void File::Close(const v8::FunctionCallbackInfo<v8::Value> &args)
154
+ {
155
+ File *obj = node::ObjectWrap::Unwrap<File>(args.Holder());
156
+ int retval = nc_close(obj->id);
157
+ if (retval != NC_NOERR)
158
+ {
159
+ throw_netcdf_error(args.GetIsolate(), retval);
160
+ }
161
+ obj->closed = true;
162
+ }
163
+
164
+ void File::Inspect(const v8::FunctionCallbackInfo<v8::Value> &args)
165
+ {
166
+ v8::Isolate *isolate = args.GetIsolate();
167
+ args.GetReturnValue().Set(
168
+ v8::String::NewFromUtf8(isolate, "[object File]", v8::NewStringType::kNormal).ToLocalChecked());
169
+ }
170
+ } // namespace nodenetcdfjs
package/src/File.h ADDED
@@ -0,0 +1,42 @@
1
+ #ifndef NODENETCDFJS_FILE_H
2
+ #define NODENETCDFJS_FILE_H
3
+
4
+ #include <node.h>
5
+ #include <node_object_wrap.h>
6
+
7
+ namespace nodenetcdfjs
8
+ {
9
+
10
+ class Group;
11
+
12
+ class File : public node::ObjectWrap
13
+ {
14
+ public:
15
+ static void Init(v8::Local<v8::Object> exports);
16
+
17
+ private:
18
+ explicit File(int id_) noexcept;
19
+ ~File() override;
20
+
21
+ // Delete copy and move operations for safety
22
+ File(const File &) = delete;
23
+ File &operator=(const File &) = delete;
24
+ File(File &&) = delete;
25
+ File &operator=(File &&) = delete;
26
+
27
+ [[nodiscard]] bool open(const char *filename, int mode, int format) noexcept;
28
+
29
+ static void New(const v8::FunctionCallbackInfo<v8::Value> &args);
30
+ static void Close(const v8::FunctionCallbackInfo<v8::Value> &args);
31
+ static void Sync(const v8::FunctionCallbackInfo<v8::Value> &args);
32
+ static void Inspect(const v8::FunctionCallbackInfo<v8::Value> &args);
33
+
34
+ static v8::Persistent<v8::Function> constructor;
35
+
36
+ int id{-1};
37
+ bool closed{false};
38
+ };
39
+
40
+ } // namespace nodenetcdfjs
41
+
42
+ #endif
package/src/Group.cpp ADDED
@@ -0,0 +1,483 @@
1
+ #include "Group.h"
2
+ #include "Attribute.h"
3
+ #include "Dimension.h"
4
+ #include "Variable.h"
5
+ #include "nodenetcdfjs.h"
6
+ #include <netcdf.h>
7
+
8
+
9
+ namespace nodenetcdfjs
10
+ {
11
+
12
+ v8::Persistent<v8::Function> Group::constructor;
13
+
14
+ Group::Group(int id_) noexcept
15
+ : id(id_)
16
+ {
17
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
18
+ v8::Local<v8::Object> obj =
19
+ v8::Local<v8::Function>::New(isolate, constructor)->NewInstance(isolate->GetCurrentContext()).ToLocalChecked();
20
+ Wrap(obj);
21
+ }
22
+
23
+ void Group::Init(v8::Local<v8::Object> exports)
24
+ {
25
+ v8::Isolate *isolate = exports->GetIsolate();
26
+ v8::Local<v8::FunctionTemplate> tpl = v8::FunctionTemplate::New(isolate);
27
+ tpl->SetClassName(v8::String::NewFromUtf8(isolate, "Group", v8::NewStringType::kNormal).ToLocalChecked());
28
+ tpl->InstanceTemplate()->SetInternalFieldCount(1);
29
+ NODE_SET_PROTOTYPE_METHOD(tpl, "addVariable", Group::AddVariable);
30
+ NODE_SET_PROTOTYPE_METHOD(tpl, "addDimension", Group::AddDimension);
31
+ NODE_SET_PROTOTYPE_METHOD(tpl, "addSubgroup", Group::AddSubgroup);
32
+ NODE_SET_PROTOTYPE_METHOD(tpl, "addAttribute", Group::AddAttribute);
33
+ NODE_SET_PROTOTYPE_METHOD(tpl, "inspect", Group::Inspect);
34
+ tpl->InstanceTemplate()->SetAccessor(
35
+ v8::String::NewFromUtf8(isolate, "id", v8::NewStringType::kNormal).ToLocalChecked(), Group::GetId);
36
+ tpl->InstanceTemplate()->SetAccessor(
37
+ v8::String::NewFromUtf8(isolate, "variables", v8::NewStringType::kNormal).ToLocalChecked(),
38
+ Group::GetVariables);
39
+ tpl->InstanceTemplate()->SetAccessor(
40
+ v8::String::NewFromUtf8(isolate, "dimensions", v8::NewStringType::kNormal).ToLocalChecked(),
41
+ Group::GetDimensions);
42
+ tpl->InstanceTemplate()->SetAccessor(
43
+ v8::String::NewFromUtf8(isolate, "unlimited", v8::NewStringType::kNormal).ToLocalChecked(),
44
+ Group::GetUnlimited);
45
+ tpl->InstanceTemplate()->SetAccessor(
46
+ v8::String::NewFromUtf8(isolate, "attributes", v8::NewStringType::kNormal).ToLocalChecked(),
47
+ Group::GetAttributes);
48
+ tpl->InstanceTemplate()->SetAccessor(
49
+ v8::String::NewFromUtf8(isolate, "subgroups", v8::NewStringType::kNormal).ToLocalChecked(),
50
+ Group::GetSubgroups);
51
+ tpl->InstanceTemplate()->SetAccessor(
52
+ v8::String::NewFromUtf8(isolate, "name", v8::NewStringType::kNormal).ToLocalChecked(), Group::GetName);
53
+ tpl->InstanceTemplate()->SetAccessor(
54
+ v8::String::NewFromUtf8(isolate, "fullname", v8::NewStringType::kNormal).ToLocalChecked(), Group::GetFullname);
55
+ constructor.Reset(isolate, tpl->GetFunction(isolate->GetCurrentContext()).ToLocalChecked());
56
+ }
57
+
58
+ bool Group::get_name(char *name) const noexcept
59
+ {
60
+ const int retval = nc_inq_grpname(id, name);
61
+ if (retval != NC_NOERR)
62
+ {
63
+ throw_netcdf_error(v8::Isolate::GetCurrent(), retval);
64
+ return false;
65
+ }
66
+ return true;
67
+ }
68
+
69
+ void Group::AddAttribute(const v8::FunctionCallbackInfo<v8::Value> &args)
70
+ {
71
+ v8::Isolate *isolate = args.GetIsolate();
72
+ auto *obj = node::ObjectWrap::Unwrap<Group>(args.Holder());
73
+
74
+ if (args.Length() < 3)
75
+ {
76
+ isolate->ThrowException(v8::Exception::TypeError(
77
+ v8::String::NewFromUtf8(isolate, "Wrong number of arguments", v8::NewStringType::kNormal)
78
+ .ToLocalChecked()));
79
+ return;
80
+ }
81
+
82
+ const std::string type_str = *v8::String::Utf8Value(isolate, args[1]);
83
+ const int type = get_type(type_str);
84
+
85
+ if (type == NC_NAT)
86
+ {
87
+ isolate->ThrowException(v8::Exception::TypeError(
88
+ v8::String::NewFromUtf8(isolate, "Unknown variable type", v8::NewStringType::kNormal).ToLocalChecked()));
89
+ return;
90
+ }
91
+
92
+ auto *res = new Attribute(*v8::String::Utf8Value(isolate, args[0]), NC_GLOBAL, obj->id, type);
93
+ res->set_value(args[2]);
94
+ args.GetReturnValue().Set(res->handle());
95
+ }
96
+
97
+ void Group::AddSubgroup(const v8::FunctionCallbackInfo<v8::Value> &args)
98
+ {
99
+ v8::Isolate *isolate = args.GetIsolate();
100
+ auto *obj = node::ObjectWrap::Unwrap<Group>(args.Holder());
101
+
102
+ if (args.Length() < 1)
103
+ {
104
+ isolate->ThrowException(v8::Exception::TypeError(
105
+ v8::String::NewFromUtf8(isolate, "Wrong number of arguments", v8::NewStringType::kNormal)
106
+ .ToLocalChecked()));
107
+ return;
108
+ }
109
+
110
+ int new_id = -1;
111
+ const int retval = nc_def_grp(obj->id, *v8::String::Utf8Value(isolate, args[0]), &new_id);
112
+
113
+ if (retval != NC_NOERR)
114
+ {
115
+ throw_netcdf_error(isolate, retval);
116
+ return;
117
+ }
118
+
119
+ auto *res = new Group(new_id);
120
+ args.GetReturnValue().Set(res->handle());
121
+ }
122
+
123
+ void Group::AddDimension(const v8::FunctionCallbackInfo<v8::Value> &args)
124
+ {
125
+ v8::Isolate *isolate = args.GetIsolate();
126
+ auto *obj = node::ObjectWrap::Unwrap<Group>(args.Holder());
127
+
128
+ if (args.Length() < 2)
129
+ {
130
+ isolate->ThrowException(v8::Exception::TypeError(
131
+ v8::String::NewFromUtf8(isolate, "Wrong number of arguments", v8::NewStringType::kNormal)
132
+ .ToLocalChecked()));
133
+ return;
134
+ }
135
+
136
+ int len;
137
+ if (const std::string len_str = *v8::String::Utf8Value(isolate, args[1]); len_str == "unlimited")
138
+ {
139
+ len = NC_UNLIMITED;
140
+ }
141
+ else
142
+ {
143
+ if (!args[1]->IsUint32())
144
+ {
145
+ isolate->ThrowException(v8::Exception::TypeError(
146
+ v8::String::NewFromUtf8(isolate, "Expecting a positive integer", v8::NewStringType::kNormal)
147
+ .ToLocalChecked()));
148
+ return;
149
+ }
150
+ len = args[1]->Uint32Value(isolate->GetCurrentContext()).ToChecked();
151
+ }
152
+
153
+ int new_id = -1;
154
+ const int retval = nc_def_dim(obj->id, *v8::String::Utf8Value(isolate, args[0]), len, &new_id);
155
+
156
+ if (retval != NC_NOERR)
157
+ {
158
+ throw_netcdf_error(isolate, retval);
159
+ return;
160
+ }
161
+
162
+ auto *res = new Dimension(new_id, obj->id);
163
+ args.GetReturnValue().Set(res->handle());
164
+ }
165
+
166
+ void Group::AddVariable(const v8::FunctionCallbackInfo<v8::Value> &args)
167
+ {
168
+ v8::Isolate *isolate = args.GetIsolate();
169
+ auto *obj = node::ObjectWrap::Unwrap<Group>(args.Holder());
170
+
171
+ if (args.Length() < 3)
172
+ {
173
+ isolate->ThrowException(v8::Exception::TypeError(
174
+ v8::String::NewFromUtf8(isolate, "Wrong number of arguments", v8::NewStringType::kNormal)
175
+ .ToLocalChecked()));
176
+ return;
177
+ }
178
+
179
+ const std::string type_str = *v8::String::Utf8Value(isolate, args[1]);
180
+ const int type = get_type(type_str);
181
+
182
+ if (type == NC_NAT)
183
+ {
184
+ isolate->ThrowException(v8::Exception::TypeError(
185
+ v8::String::NewFromUtf8(isolate, "Unknown variable type", v8::NewStringType::kNormal).ToLocalChecked()));
186
+ return;
187
+ }
188
+
189
+ if (type == NC_STRING)
190
+ {
191
+ isolate->ThrowException(v8::Exception::TypeError(
192
+ v8::String::NewFromUtf8(isolate, "Unsupported variable type", v8::NewStringType::kNormal)
193
+ .ToLocalChecked()));
194
+ return;
195
+ }
196
+
197
+ if (!args[2]->IsArray())
198
+ {
199
+ isolate->ThrowException(v8::Exception::TypeError(
200
+ v8::String::NewFromUtf8(isolate, "Expecting an array", v8::NewStringType::kNormal).ToLocalChecked()));
201
+ return;
202
+ }
203
+
204
+ v8::Local<v8::Object> array = args[2]->ToObject(isolate->GetCurrentContext()).ToLocalChecked();
205
+ const size_t ndims =
206
+ array
207
+ ->Get(isolate->GetCurrentContext(),
208
+ v8::String::NewFromUtf8(isolate, "length", v8::NewStringType::kNormal).ToLocalChecked())
209
+ .ToLocalChecked()
210
+ ->Uint32Value(isolate->GetCurrentContext())
211
+ .ToChecked();
212
+
213
+ // Use vector for automatic memory management
214
+ std::vector<int> dimids(ndims);
215
+ for (size_t i = 0; i < ndims; i++)
216
+ {
217
+ dimids[i] = array->Get(isolate->GetCurrentContext(), i)
218
+ .ToLocalChecked()
219
+ ->Int32Value(isolate->GetCurrentContext())
220
+ .ToChecked();
221
+ }
222
+
223
+ int new_id = -1;
224
+ const int retval = nc_def_var(obj->id, *v8::String::Utf8Value(isolate, args[0]), type, static_cast<int>(ndims),
225
+ dimids.data(), &new_id);
226
+
227
+ if (retval != NC_NOERR)
228
+ {
229
+ throw_netcdf_error(isolate, retval);
230
+ return;
231
+ }
232
+
233
+ auto *res = new Variable(new_id, obj->id);
234
+ args.GetReturnValue().Set(res->handle());
235
+ }
236
+
237
+ void Group::GetId(v8::Local<v8::String> property, const v8::PropertyCallbackInfo<v8::Value> &info)
238
+ {
239
+ v8::Isolate *isolate = info.GetIsolate();
240
+ const auto *obj = node::ObjectWrap::Unwrap<Group>(info.Holder());
241
+ info.GetReturnValue().Set(v8::Integer::New(isolate, obj->id));
242
+ }
243
+
244
+ void Group::GetVariables(v8::Local<v8::String> property, const v8::PropertyCallbackInfo<v8::Value> &info)
245
+ {
246
+ v8::Isolate *isolate = info.GetIsolate();
247
+ const auto *obj = node::ObjectWrap::Unwrap<Group>(info.Holder());
248
+
249
+ int nvars = 0;
250
+ int retval = nc_inq_varids(obj->id, &nvars, nullptr);
251
+ if (retval != NC_NOERR)
252
+ {
253
+ throw_netcdf_error(isolate, retval);
254
+ return;
255
+ }
256
+
257
+ std::vector<int> var_ids(nvars);
258
+ retval = nc_inq_varids(obj->id, nullptr, var_ids.data());
259
+ if (retval != NC_NOERR)
260
+ {
261
+ throw_netcdf_error(isolate, retval);
262
+ return;
263
+ }
264
+
265
+ v8::Local<v8::Object> result = v8::Object::New(isolate);
266
+ std::array<char, NC_MAX_NAME + 1> name{};
267
+
268
+ for (int i = 0; i < nvars; ++i)
269
+ {
270
+ auto *v = new Variable(var_ids[i], obj->id);
271
+ if (v->get_name(name.data()))
272
+ {
273
+ result->Set(isolate->GetCurrentContext(),
274
+ v8::String::NewFromUtf8(isolate, name.data(), v8::NewStringType::kNormal).ToLocalChecked(),
275
+ v->handle());
276
+ }
277
+ else
278
+ {
279
+ return;
280
+ }
281
+ }
282
+ info.GetReturnValue().Set(result);
283
+ }
284
+
285
+ void Group::GetDimensions(v8::Local<v8::String> property, const v8::PropertyCallbackInfo<v8::Value> &info)
286
+ {
287
+ v8::Isolate *isolate = info.GetIsolate();
288
+ const auto *obj = node::ObjectWrap::Unwrap<Group>(info.Holder());
289
+
290
+ int ndims = 0;
291
+ int retval = nc_inq_dimids(obj->id, &ndims, nullptr, 0);
292
+ if (retval != NC_NOERR)
293
+ {
294
+ throw_netcdf_error(isolate, retval);
295
+ return;
296
+ }
297
+
298
+ std::vector<int> dim_ids(ndims);
299
+ retval = nc_inq_dimids(obj->id, nullptr, dim_ids.data(), 0);
300
+ if (retval != NC_NOERR)
301
+ {
302
+ throw_netcdf_error(isolate, retval);
303
+ return;
304
+ }
305
+
306
+ v8::Local<v8::Object> result = v8::Object::New(isolate);
307
+ std::array<char, NC_MAX_NAME + 1> name{};
308
+
309
+ for (int i = 0; i < ndims; ++i)
310
+ {
311
+ auto *d = new Dimension(dim_ids[i], obj->id);
312
+ if (d->get_name(name.data()))
313
+ {
314
+ // Suppress warning about unused return value
315
+ (void)result->Set(
316
+ isolate->GetCurrentContext(),
317
+ v8::String::NewFromUtf8(isolate, name.data(), v8::NewStringType::kNormal).ToLocalChecked(),
318
+ d->handle());
319
+ }
320
+ else
321
+ return;
322
+ }
323
+ info.GetReturnValue().Set(result);
324
+ }
325
+
326
+ void Group::GetUnlimited(v8::Local<v8::String> property, const v8::PropertyCallbackInfo<v8::Value> &info)
327
+ {
328
+ v8::Isolate *isolate = info.GetIsolate();
329
+ const auto *obj = node::ObjectWrap::Unwrap<Group>(info.Holder());
330
+
331
+ int ndims = 0;
332
+ int retval = nc_inq_unlimdims(obj->id, &ndims, nullptr);
333
+ if (retval != NC_NOERR)
334
+ {
335
+ throw_netcdf_error(isolate, retval);
336
+ return;
337
+ }
338
+
339
+ std::vector<int> dim_ids(ndims);
340
+ retval = nc_inq_unlimdims(obj->id, nullptr, dim_ids.data());
341
+ if (retval != NC_NOERR)
342
+ {
343
+ throw_netcdf_error(isolate, retval);
344
+ return;
345
+ }
346
+
347
+ v8::Local<v8::Object> result = v8::Object::New(isolate);
348
+ std::array<char, NC_MAX_NAME + 1> name{};
349
+
350
+ for (int i = 0; i < ndims; ++i)
351
+ {
352
+ auto *d = new Dimension(dim_ids[i], obj->id);
353
+ if (d->get_name(name.data()))
354
+ {
355
+ // Suppress warning about unused return value
356
+ (void)result->Set(isolate->GetCurrentContext(),
357
+ v8::String::NewFromUtf8(isolate, name.data(), v8::NewStringType::kNormal).ToLocalChecked(),
358
+ d->handle());
359
+ }
360
+ else return;
361
+ }
362
+ info.GetReturnValue().Set(result);
363
+ }
364
+
365
+ void Group::GetAttributes(v8::Local<v8::String> property, const v8::PropertyCallbackInfo<v8::Value> &info)
366
+ {
367
+ v8::Isolate *isolate = info.GetIsolate();
368
+ const auto *obj = node::ObjectWrap::Unwrap<Group>(info.Holder());
369
+
370
+ int natts = 0;
371
+ int retval = nc_inq_natts(obj->id, &natts);
372
+ if (retval != NC_NOERR)
373
+ {
374
+ throw_netcdf_error(isolate, retval);
375
+ return;
376
+ }
377
+
378
+ v8::Local<v8::Object> result = v8::Object::New(isolate);
379
+ std::array<char, NC_MAX_NAME + 1> name{};
380
+
381
+ for (int i = 0; i < natts; i++)
382
+ {
383
+ retval = nc_inq_attname(obj->id, NC_GLOBAL, i, name.data());
384
+ if (retval != NC_NOERR)
385
+ {
386
+ throw_netcdf_error(isolate, retval);
387
+ return;
388
+ }
389
+ auto *a = new Attribute(name.data(), NC_GLOBAL, obj->id);
390
+ result->Set(isolate->GetCurrentContext(),
391
+ v8::String::NewFromUtf8(isolate, name.data(), v8::NewStringType::kNormal).ToLocalChecked(),
392
+ a->handle());
393
+ }
394
+ info.GetReturnValue().Set(result);
395
+ }
396
+
397
+ void Group::GetSubgroups(v8::Local<v8::String> property, const v8::PropertyCallbackInfo<v8::Value> &info)
398
+ {
399
+ v8::Isolate *isolate = info.GetIsolate();
400
+ const auto *obj = node::ObjectWrap::Unwrap<Group>(info.Holder());
401
+
402
+ int ngrps = 0;
403
+ int retval = nc_inq_grps(obj->id, &ngrps, nullptr);
404
+ if (retval != NC_NOERR)
405
+ {
406
+ throw_netcdf_error(isolate, retval);
407
+ return;
408
+ }
409
+
410
+ std::vector<int> grp_ids(ngrps);
411
+ retval = nc_inq_grps(obj->id, nullptr, grp_ids.data());
412
+ if (retval != NC_NOERR)
413
+ {
414
+ throw_netcdf_error(isolate, retval);
415
+ return;
416
+ }
417
+
418
+ v8::Local<v8::Object> result = v8::Object::New(isolate);
419
+ std::array<char, NC_MAX_NAME + 1> name{};
420
+
421
+ for (int i = 0; i < ngrps; ++i)
422
+ {
423
+ auto *g = new Group(grp_ids[i]);
424
+ if (g->get_name(name.data()))
425
+ {
426
+ // Suppress warning about unused return value
427
+ (void)result->Set(isolate->GetCurrentContext(),
428
+ v8::String::NewFromUtf8(isolate, name.data(), v8::NewStringType::kNormal).ToLocalChecked(),
429
+ g->handle());
430
+ }
431
+ else
432
+ {
433
+ return;
434
+ }
435
+ }
436
+ info.GetReturnValue().Set(result);
437
+ }
438
+
439
+ void Group::GetName(v8::Local<v8::String> property, const v8::PropertyCallbackInfo<v8::Value> &info)
440
+ {
441
+ v8::Isolate *isolate = info.GetIsolate();
442
+ const auto *obj = node::ObjectWrap::Unwrap<Group>(info.Holder());
443
+
444
+ std::array<char, NC_MAX_NAME + 1> name{};
445
+ if (obj->get_name(name.data()))
446
+ {
447
+ info.GetReturnValue().Set(
448
+ v8::String::NewFromUtf8(isolate, name.data(), v8::NewStringType::kNormal).ToLocalChecked());
449
+ }
450
+ }
451
+
452
+ void Group::GetFullname(v8::Local<v8::String> property, const v8::PropertyCallbackInfo<v8::Value> &info)
453
+ {
454
+ v8::Isolate *isolate = info.GetIsolate();
455
+ const auto *obj = node::ObjectWrap::Unwrap<Group>(info.Holder());
456
+
457
+ size_t len = 0;
458
+ int retval = nc_inq_grpname_len(obj->id, &len);
459
+ if (retval != NC_NOERR)
460
+ {
461
+ throw_netcdf_error(isolate, retval);
462
+ return;
463
+ }
464
+
465
+ std::vector<char> name(len + 1, '\0');
466
+ retval = nc_inq_grpname_full(obj->id, nullptr, name.data());
467
+ if (retval != NC_NOERR)
468
+ {
469
+ throw_netcdf_error(isolate, retval);
470
+ return;
471
+ }
472
+
473
+ info.GetReturnValue().Set(
474
+ v8::String::NewFromUtf8(isolate, name.data(), v8::NewStringType::kNormal).ToLocalChecked());
475
+ }
476
+
477
+ void Group::Inspect(const v8::FunctionCallbackInfo<v8::Value> &args)
478
+ {
479
+ v8::Isolate *isolate = args.GetIsolate();
480
+ args.GetReturnValue().Set(
481
+ v8::String::NewFromUtf8(isolate, "[object Group]", v8::NewStringType::kNormal).ToLocalChecked());
482
+ }
483
+ } // namespace nodenetcdfjs