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/.clang-format +13 -0
- package/.github/workflows/nodejs.yml +97 -0
- package/LICENSE +13 -0
- package/README.md +330 -0
- package/binding.gyp +95 -0
- package/package.json +35 -0
- package/scripts/copy-deps.js +57 -0
- package/scripts/setup-vcpkg.js +93 -0
- package/scripts/verify-build-deps.js +61 -0
- package/src/Attribute.cpp +334 -0
- package/src/Attribute.h +46 -0
- package/src/Dimension.cpp +105 -0
- package/src/Dimension.h +40 -0
- package/src/File.cpp +170 -0
- package/src/File.h +42 -0
- package/src/Group.cpp +483 -0
- package/src/Group.h +49 -0
- package/src/Variable.cpp +1352 -0
- package/src/Variable.h +88 -0
- package/src/nodenetcdfjs.cpp +24 -0
- package/src/nodenetcdfjs.h +37 -0
- package/test/attribute.js +36 -0
- package/test/dimension.js +18 -0
- package/test/file.js +19 -0
- package/test/group.js +57 -0
- package/test/test_hgroups.nc +0 -0
- package/test/testrh.nc +0 -0
- package/test/variable.js +16 -0
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
const { execSync } = require('child_process');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const os = require('os');
|
|
5
|
+
|
|
6
|
+
// Allow users to skip vcpkg setup if they prefer system libraries
|
|
7
|
+
if (process.env.SKIP_VCPKG_SETUP === '1') {
|
|
8
|
+
console.log('SKIP_VCPKG_SETUP is set, skipping vcpkg setup');
|
|
9
|
+
console.log('Make sure NetCDF libraries are installed on your system');
|
|
10
|
+
process.exit(0);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const platform = os.platform();
|
|
14
|
+
|
|
15
|
+
console.log('Setting up vcpkg and NetCDF dependencies...');
|
|
16
|
+
|
|
17
|
+
// Determine vcpkg triplet based on platform
|
|
18
|
+
let triplet;
|
|
19
|
+
if (platform === 'win32') {
|
|
20
|
+
triplet = 'x64-windows';
|
|
21
|
+
} else if (platform === 'linux') {
|
|
22
|
+
triplet = 'x64-linux';
|
|
23
|
+
} else if (platform === 'darwin') {
|
|
24
|
+
triplet = 'arm64-osx';
|
|
25
|
+
} else {
|
|
26
|
+
console.error(`Unsupported platform: ${platform}`);
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function runCommand(cmd, options = {}) {
|
|
31
|
+
console.log(`Running: ${cmd}`);
|
|
32
|
+
try {
|
|
33
|
+
execSync(cmd, {
|
|
34
|
+
stdio: 'inherit',
|
|
35
|
+
...options
|
|
36
|
+
});
|
|
37
|
+
} catch (error) {
|
|
38
|
+
console.error(`Failed to run command: ${cmd}`);
|
|
39
|
+
throw error;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Check if vcpkg directory exists
|
|
44
|
+
if (!fs.existsSync('vcpkg')) {
|
|
45
|
+
console.log('vcpkg not found, cloning repository...');
|
|
46
|
+
runCommand('git clone https://github.com/microsoft/vcpkg.git');
|
|
47
|
+
} else {
|
|
48
|
+
console.log('vcpkg directory already exists');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Bootstrap vcpkg
|
|
52
|
+
const vcpkgExecutable = platform === 'win32' ? 'vcpkg.exe' : 'vcpkg';
|
|
53
|
+
const vcpkgPath = path.join('vcpkg', vcpkgExecutable);
|
|
54
|
+
|
|
55
|
+
if (!fs.existsSync(vcpkgPath)) {
|
|
56
|
+
console.log('Bootstrapping vcpkg...');
|
|
57
|
+
if (platform === 'win32') {
|
|
58
|
+
runCommand('.\\vcpkg\\bootstrap-vcpkg.bat', { shell: true });
|
|
59
|
+
} else {
|
|
60
|
+
runCommand('./vcpkg/bootstrap-vcpkg.sh', { shell: true });
|
|
61
|
+
}
|
|
62
|
+
} else {
|
|
63
|
+
console.log('vcpkg already bootstrapped');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Install nodenetcdf using vcpkg
|
|
67
|
+
console.log(`Installing netcdf-c for ${triplet}...`);
|
|
68
|
+
try {
|
|
69
|
+
runCommand(`${vcpkgPath} install netcdf-c:${triplet}`);
|
|
70
|
+
console.log('NetCDF dependencies installed successfully!');
|
|
71
|
+
} catch (error) {
|
|
72
|
+
console.error('Failed to install netcdf-c');
|
|
73
|
+
console.error('You may need to install build tools for your platform:');
|
|
74
|
+
console.error('- Windows: Visual Studio Build Tools');
|
|
75
|
+
console.error('- Linux: build-essential, cmake');
|
|
76
|
+
console.error('- macOS: Xcode Command Line Tools');
|
|
77
|
+
process.exit(1);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
console.log('vcpkg setup complete!');
|
|
81
|
+
|
|
82
|
+
// Verify that netcdf.h is actually available
|
|
83
|
+
const vcpkgInstalledDir = path.join('vcpkg', 'installed', triplet);
|
|
84
|
+
const includeDir = path.join(vcpkgInstalledDir, 'include');
|
|
85
|
+
const netcdfHeader = path.join(includeDir, 'netcdf.h');
|
|
86
|
+
|
|
87
|
+
if (fs.existsSync(netcdfHeader)) {
|
|
88
|
+
console.log(`✓ Verified netcdf.h exists at: ${netcdfHeader}`);
|
|
89
|
+
} else {
|
|
90
|
+
console.error(`✗ ERROR: netcdf.h not found at: ${netcdfHeader}`);
|
|
91
|
+
console.error('vcpkg installation may have failed or be incomplete');
|
|
92
|
+
process.exit(1);
|
|
93
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const os = require('os');
|
|
4
|
+
|
|
5
|
+
// Determine the platform-specific vcpkg directory
|
|
6
|
+
const platform = os.platform();
|
|
7
|
+
let triplet;
|
|
8
|
+
|
|
9
|
+
if (platform === 'win32') {
|
|
10
|
+
triplet = 'x64-windows';
|
|
11
|
+
} else if (platform === 'linux') {
|
|
12
|
+
triplet = 'x64-linux';
|
|
13
|
+
} else if (platform === 'darwin') {
|
|
14
|
+
triplet = 'arm64-osx';
|
|
15
|
+
} else {
|
|
16
|
+
console.error(`Unsupported platform: ${platform}`);
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
console.log('Verifying build dependencies...');
|
|
21
|
+
|
|
22
|
+
// Check if vcpkg installed directory exists
|
|
23
|
+
const vcpkgInstalledDir = path.join('vcpkg', 'installed', triplet);
|
|
24
|
+
if (!fs.existsSync(vcpkgInstalledDir)) {
|
|
25
|
+
console.error(`✗ ERROR: vcpkg installation directory not found: ${vcpkgInstalledDir}`);
|
|
26
|
+
console.error('Please run: npm run preinstall');
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Verify netcdf.h exists
|
|
31
|
+
const includeDir = path.join(vcpkgInstalledDir, 'include');
|
|
32
|
+
const netcdfHeader = path.join(includeDir, 'netcdf.h');
|
|
33
|
+
|
|
34
|
+
if (!fs.existsSync(netcdfHeader)) {
|
|
35
|
+
console.error(`✗ ERROR: netcdf.h not found at: ${netcdfHeader}`);
|
|
36
|
+
console.error('vcpkg installation may be incomplete');
|
|
37
|
+
console.error('Please run: npm run preinstall');
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
console.log(`✓ Found netcdf.h at: ${netcdfHeader}`);
|
|
42
|
+
|
|
43
|
+
// Verify library files exist
|
|
44
|
+
const libDir = path.join(vcpkgInstalledDir, 'lib');
|
|
45
|
+
let requiredLib;
|
|
46
|
+
|
|
47
|
+
if (platform === 'win32') {
|
|
48
|
+
requiredLib = path.join(libDir, 'netcdf.lib');
|
|
49
|
+
} else {
|
|
50
|
+
requiredLib = path.join(libDir, 'libnetcdf.a');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (!fs.existsSync(requiredLib)) {
|
|
54
|
+
console.error(`✗ ERROR: NetCDF library not found at: ${requiredLib}`);
|
|
55
|
+
console.error('vcpkg installation may be incomplete');
|
|
56
|
+
console.error('Please run: npm run preinstall');
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
console.log(`✓ Found NetCDF library at: ${requiredLib}`);
|
|
61
|
+
console.log(`✓ Build dependencies verified for ${triplet}`);
|
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
#include "Attribute.h"
|
|
2
|
+
#include "nodenetcdfjs.h"
|
|
3
|
+
#include <inttypes.h>
|
|
4
|
+
#include <iostream>
|
|
5
|
+
#include <netcdf.h>
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
namespace nodenetcdfjs
|
|
9
|
+
{
|
|
10
|
+
|
|
11
|
+
v8::Persistent<v8::Function> Attribute::constructor;
|
|
12
|
+
|
|
13
|
+
Attribute::Attribute(const char *name_, int var_id_, int parent_id_) noexcept
|
|
14
|
+
: name(name_)
|
|
15
|
+
, var_id(var_id_)
|
|
16
|
+
, parent_id(parent_id_)
|
|
17
|
+
{
|
|
18
|
+
v8::Isolate *isolate = v8::Isolate::GetCurrent();
|
|
19
|
+
v8::Local<v8::Object> obj =
|
|
20
|
+
v8::Local<v8::Function>::New(isolate, constructor)->NewInstance(isolate->GetCurrentContext()).ToLocalChecked();
|
|
21
|
+
Wrap(obj);
|
|
22
|
+
const int retval = nc_inq_atttype(parent_id, var_id_, name_, &type);
|
|
23
|
+
if (retval != NC_NOERR)
|
|
24
|
+
{
|
|
25
|
+
throw_netcdf_error(isolate, retval);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
Attribute::Attribute(const char *name_, int var_id_, int parent_id_, int type_) noexcept
|
|
30
|
+
: name(name_)
|
|
31
|
+
, var_id(var_id_)
|
|
32
|
+
, parent_id(parent_id_)
|
|
33
|
+
, type(type_)
|
|
34
|
+
{
|
|
35
|
+
v8::Isolate *isolate = v8::Isolate::GetCurrent();
|
|
36
|
+
v8::Local<v8::Object> obj =
|
|
37
|
+
v8::Local<v8::Function>::New(isolate, constructor)->NewInstance(isolate->GetCurrentContext()).ToLocalChecked();
|
|
38
|
+
Wrap(obj);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
void Attribute::Init(v8::Local<v8::Object> exports)
|
|
42
|
+
{
|
|
43
|
+
v8::Isolate *isolate = exports->GetIsolate();
|
|
44
|
+
v8::Local<v8::FunctionTemplate> tpl = v8::FunctionTemplate::New(isolate);
|
|
45
|
+
tpl->SetClassName(v8::String::NewFromUtf8(isolate, "Attribute", v8::NewStringType::kNormal).ToLocalChecked());
|
|
46
|
+
tpl->InstanceTemplate()->SetInternalFieldCount(1);
|
|
47
|
+
NODE_SET_PROTOTYPE_METHOD(tpl, "delete", Attribute::Delete);
|
|
48
|
+
NODE_SET_PROTOTYPE_METHOD(tpl, "inspect", Attribute::Inspect);
|
|
49
|
+
tpl->InstanceTemplate()->SetAccessor(
|
|
50
|
+
v8::String::NewFromUtf8(isolate, "name", v8::NewStringType::kNormal).ToLocalChecked(), Attribute::GetName,
|
|
51
|
+
Attribute::SetName);
|
|
52
|
+
tpl->InstanceTemplate()->SetAccessor(
|
|
53
|
+
v8::String::NewFromUtf8(isolate, "value", v8::NewStringType::kNormal).ToLocalChecked(), Attribute::GetValue,
|
|
54
|
+
Attribute::SetValue);
|
|
55
|
+
constructor.Reset(isolate, tpl->GetFunction(isolate->GetCurrentContext()).ToLocalChecked());
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
void Attribute::GetName(v8::Local<v8::String> property, const v8::PropertyCallbackInfo<v8::Value> &info)
|
|
59
|
+
{
|
|
60
|
+
v8::Isolate *isolate = info.GetIsolate();
|
|
61
|
+
const auto *obj = node::ObjectWrap::Unwrap<Attribute>(info.Holder());
|
|
62
|
+
info.GetReturnValue().Set(
|
|
63
|
+
v8::String::NewFromUtf8(isolate, obj->name.c_str(), v8::NewStringType::kNormal).ToLocalChecked());
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
void Attribute::SetName(v8::Local<v8::String> property, v8::Local<v8::Value> val,
|
|
67
|
+
const v8::PropertyCallbackInfo<void> &info)
|
|
68
|
+
{
|
|
69
|
+
v8::Isolate *isolate = v8::Isolate::GetCurrent();
|
|
70
|
+
auto *obj = node::ObjectWrap::Unwrap<Attribute>(info.Holder());
|
|
71
|
+
|
|
72
|
+
const v8::String::Utf8Value new_name_(isolate, val->ToString(isolate->GetCurrentContext()).ToLocalChecked());
|
|
73
|
+
const int retval = nc_rename_att(obj->parent_id, obj->var_id, obj->name.c_str(), *new_name_);
|
|
74
|
+
|
|
75
|
+
if (retval != NC_NOERR)
|
|
76
|
+
{
|
|
77
|
+
throw_netcdf_error(isolate, retval);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
obj->name = *new_name_;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
void Attribute::GetValue(v8::Local<v8::String> property, const v8::PropertyCallbackInfo<v8::Value> &info)
|
|
84
|
+
{
|
|
85
|
+
v8::Isolate *isolate = info.GetIsolate();
|
|
86
|
+
const auto *obj = node::ObjectWrap::Unwrap<Attribute>(info.Holder());
|
|
87
|
+
|
|
88
|
+
if ((obj->type < NC_BYTE || obj->type > NC_UINT64) && obj->type != NC_STRING)
|
|
89
|
+
{
|
|
90
|
+
isolate->ThrowException(v8::Exception::TypeError(
|
|
91
|
+
v8::String::NewFromUtf8(isolate, "Variable type not supported yet", v8::NewStringType::kNormal)
|
|
92
|
+
.ToLocalChecked()));
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
size_t len = 0;
|
|
97
|
+
int retval = nc_inq_attlen(obj->parent_id, obj->var_id, obj->name.c_str(), &len);
|
|
98
|
+
if (retval != NC_NOERR)
|
|
99
|
+
{
|
|
100
|
+
throw_netcdf_error(isolate, retval);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
switch (obj->type)
|
|
105
|
+
{
|
|
106
|
+
case NC_BYTE: {
|
|
107
|
+
std::vector<int8_t> v(len);
|
|
108
|
+
retval = nc_get_att(obj->parent_id, obj->var_id, obj->name.c_str(), v.data());
|
|
109
|
+
if (len == 1)
|
|
110
|
+
{
|
|
111
|
+
info.GetReturnValue().Set(v8::Integer::New(isolate, v[0]));
|
|
112
|
+
}
|
|
113
|
+
else
|
|
114
|
+
{
|
|
115
|
+
v8::Local<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, len * sizeof(int8_t));
|
|
116
|
+
memcpy(buffer->GetBackingStore()->Data(), v.data(), len * sizeof(int8_t));
|
|
117
|
+
info.GetReturnValue().Set(v8::Int8Array::New(buffer, 0, len));
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
break;
|
|
121
|
+
case NC_SHORT: {
|
|
122
|
+
std::vector<int16_t> v(len);
|
|
123
|
+
retval = nc_get_att(obj->parent_id, obj->var_id, obj->name.c_str(), v.data());
|
|
124
|
+
if (len == 1)
|
|
125
|
+
{
|
|
126
|
+
info.GetReturnValue().Set(v8::Integer::New(isolate, v[0]));
|
|
127
|
+
}
|
|
128
|
+
else
|
|
129
|
+
{
|
|
130
|
+
v8::Local<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, len * sizeof(int16_t));
|
|
131
|
+
memcpy(buffer->GetBackingStore()->Data(), v.data(), len * sizeof(int16_t));
|
|
132
|
+
info.GetReturnValue().Set(v8::Int16Array::New(buffer, 0, len));
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
break;
|
|
136
|
+
case NC_INT: {
|
|
137
|
+
std::vector<int32_t> v(len);
|
|
138
|
+
retval = nc_get_att(obj->parent_id, obj->var_id, obj->name.c_str(), v.data());
|
|
139
|
+
if (len == 1)
|
|
140
|
+
{
|
|
141
|
+
info.GetReturnValue().Set(v8::Integer::New(isolate, v[0]));
|
|
142
|
+
}
|
|
143
|
+
else
|
|
144
|
+
{
|
|
145
|
+
v8::Local<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, len * sizeof(int32_t));
|
|
146
|
+
memcpy(buffer->GetBackingStore()->Data(), v.data(), len * sizeof(int32_t));
|
|
147
|
+
info.GetReturnValue().Set(v8::Int32Array::New(buffer, 0, len));
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
break;
|
|
151
|
+
case NC_FLOAT: {
|
|
152
|
+
std::vector<float> v(len);
|
|
153
|
+
retval = nc_get_att(obj->parent_id, obj->var_id, obj->name.c_str(), v.data());
|
|
154
|
+
if (len == 1)
|
|
155
|
+
{
|
|
156
|
+
info.GetReturnValue().Set(v8::Number::New(isolate, v[0]));
|
|
157
|
+
}
|
|
158
|
+
else
|
|
159
|
+
{
|
|
160
|
+
v8::Local<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, len * sizeof(float));
|
|
161
|
+
memcpy(buffer->GetBackingStore()->Data(), v.data(), len * sizeof(float));
|
|
162
|
+
info.GetReturnValue().Set(v8::Float32Array::New(buffer, 0, len));
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
break;
|
|
166
|
+
case NC_DOUBLE: {
|
|
167
|
+
std::vector<double> v(len);
|
|
168
|
+
retval = nc_get_att(obj->parent_id, obj->var_id, obj->name.c_str(), v.data());
|
|
169
|
+
if (len == 1)
|
|
170
|
+
{
|
|
171
|
+
info.GetReturnValue().Set(v8::Number::New(isolate, v[0]));
|
|
172
|
+
}
|
|
173
|
+
else
|
|
174
|
+
{
|
|
175
|
+
v8::Local<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, len * sizeof(double));
|
|
176
|
+
memcpy(buffer->GetBackingStore()->Data(), v.data(), len * sizeof(double));
|
|
177
|
+
info.GetReturnValue().Set(v8::Float64Array::New(buffer, 0, len));
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
break;
|
|
181
|
+
case NC_UBYTE: {
|
|
182
|
+
std::vector<uint8_t> v(len);
|
|
183
|
+
retval = nc_get_att(obj->parent_id, obj->var_id, obj->name.c_str(), v.data());
|
|
184
|
+
if (len == 1)
|
|
185
|
+
{
|
|
186
|
+
info.GetReturnValue().Set(v8::Integer::New(isolate, v[0]));
|
|
187
|
+
}
|
|
188
|
+
else
|
|
189
|
+
{
|
|
190
|
+
v8::Local<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, len * sizeof(uint8_t));
|
|
191
|
+
memcpy(buffer->GetBackingStore()->Data(), v.data(), len * sizeof(uint8_t));
|
|
192
|
+
info.GetReturnValue().Set(v8::Uint8Array::New(buffer, 0, len));
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
break;
|
|
196
|
+
case NC_USHORT: {
|
|
197
|
+
std::vector<uint16_t> v(len);
|
|
198
|
+
retval = nc_get_att(obj->parent_id, obj->var_id, obj->name.c_str(), v.data());
|
|
199
|
+
if (len == 1)
|
|
200
|
+
{
|
|
201
|
+
info.GetReturnValue().Set(v8::Integer::New(isolate, v[0]));
|
|
202
|
+
}
|
|
203
|
+
else
|
|
204
|
+
{
|
|
205
|
+
v8::Local<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, len * sizeof(uint16_t));
|
|
206
|
+
memcpy(buffer->GetBackingStore()->Data(), v.data(), len * sizeof(uint16_t));
|
|
207
|
+
info.GetReturnValue().Set(v8::Uint16Array::New(buffer, 0, len));
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
break;
|
|
211
|
+
case NC_UINT: {
|
|
212
|
+
std::vector<uint32_t> v(len);
|
|
213
|
+
retval = nc_get_att(obj->parent_id, obj->var_id, obj->name.c_str(), v.data());
|
|
214
|
+
if (len == 1)
|
|
215
|
+
{
|
|
216
|
+
info.GetReturnValue().Set(v8::Integer::NewFromUnsigned(isolate, v[0]));
|
|
217
|
+
}
|
|
218
|
+
else
|
|
219
|
+
{
|
|
220
|
+
v8::Local<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, len * sizeof(uint32_t));
|
|
221
|
+
memcpy(buffer->GetBackingStore()->Data(), v.data(), len * sizeof(uint32_t));
|
|
222
|
+
info.GetReturnValue().Set(v8::Uint32Array::New(buffer, 0, len));
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
break;
|
|
226
|
+
case NC_INT64: {
|
|
227
|
+
std::vector<int64_t> v(len);
|
|
228
|
+
retval = nc_get_att(obj->parent_id, obj->var_id, obj->name.c_str(), v.data());
|
|
229
|
+
if (len == 1)
|
|
230
|
+
{
|
|
231
|
+
info.GetReturnValue().Set(v8::Integer::New(isolate, static_cast<int32_t>(v[0])));
|
|
232
|
+
}
|
|
233
|
+
else
|
|
234
|
+
{
|
|
235
|
+
v8::Local<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, len * sizeof(int64_t));
|
|
236
|
+
memcpy(buffer->GetBackingStore()->Data(), v.data(), len * sizeof(int64_t));
|
|
237
|
+
info.GetReturnValue().Set(v8::Int32Array::New(buffer, 0, len));
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
break;
|
|
241
|
+
case NC_UINT64: {
|
|
242
|
+
std::vector<uint64_t> v(len);
|
|
243
|
+
retval = nc_get_att(obj->parent_id, obj->var_id, obj->name.c_str(), v.data());
|
|
244
|
+
if (len == 1)
|
|
245
|
+
{
|
|
246
|
+
info.GetReturnValue().Set(v8::Integer::NewFromUnsigned(isolate, static_cast<uint32_t>(v[0])));
|
|
247
|
+
}
|
|
248
|
+
else
|
|
249
|
+
{
|
|
250
|
+
v8::Local<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, len * sizeof(uint64_t));
|
|
251
|
+
memcpy(buffer->GetBackingStore()->Data(), v.data(), len * sizeof(uint64_t));
|
|
252
|
+
info.GetReturnValue().Set(v8::Uint32Array::New(buffer, 0, len));
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
break;
|
|
256
|
+
case NC_CHAR:
|
|
257
|
+
case NC_STRING: {
|
|
258
|
+
std::vector<char> v(len + 1, '\0');
|
|
259
|
+
retval = nc_get_att_text(obj->parent_id, obj->var_id, obj->name.c_str(), v.data());
|
|
260
|
+
info.GetReturnValue().Set(
|
|
261
|
+
v8::String::NewFromUtf8(isolate, v.data(), v8::NewStringType::kNormal).ToLocalChecked());
|
|
262
|
+
}
|
|
263
|
+
break;
|
|
264
|
+
}
|
|
265
|
+
if (retval != NC_NOERR)
|
|
266
|
+
{
|
|
267
|
+
throw_netcdf_error(isolate, retval);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
void Attribute::SetValue(v8::Local<v8::String> property, v8::Local<v8::Value> val,
|
|
272
|
+
const v8::PropertyCallbackInfo<void> &info)
|
|
273
|
+
{
|
|
274
|
+
auto *obj = node::ObjectWrap::Unwrap<Attribute>(info.Holder());
|
|
275
|
+
obj->set_value(val);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
void Attribute::set_value(const v8::Local<v8::Value> &val)
|
|
279
|
+
{
|
|
280
|
+
v8::Isolate *isolate = v8::Isolate::GetCurrent();
|
|
281
|
+
if ((type < NC_BYTE || type > NC_UINT) && type != NC_STRING)
|
|
282
|
+
{
|
|
283
|
+
isolate->ThrowException(v8::Exception::TypeError(
|
|
284
|
+
v8::String::NewFromUtf8(isolate, "Variable type not supported yet", v8::NewStringType::kNormal)
|
|
285
|
+
.ToLocalChecked()));
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
int retval = NC_NOERR;
|
|
290
|
+
if (val->IsUint32())
|
|
291
|
+
{
|
|
292
|
+
const uint32_t v = val->Uint32Value(isolate->GetCurrentContext()).ToChecked();
|
|
293
|
+
retval = nc_put_att(parent_id, var_id, name.c_str(), NC_UINT, 1, &v);
|
|
294
|
+
}
|
|
295
|
+
else if (val->IsInt32())
|
|
296
|
+
{
|
|
297
|
+
const int32_t v = val->Int32Value(isolate->GetCurrentContext()).ToChecked();
|
|
298
|
+
retval = nc_put_att(parent_id, var_id, name.c_str(), NC_INT, 1, &v);
|
|
299
|
+
}
|
|
300
|
+
else if (val->IsNumber())
|
|
301
|
+
{
|
|
302
|
+
const double v = val->NumberValue(isolate->GetCurrentContext()).ToChecked();
|
|
303
|
+
retval = nc_put_att(parent_id, var_id, name.c_str(), NC_DOUBLE, 1, &v);
|
|
304
|
+
}
|
|
305
|
+
else
|
|
306
|
+
{
|
|
307
|
+
const std::string v =
|
|
308
|
+
*v8::String::Utf8Value(isolate, val->ToString(isolate->GetCurrentContext()).ToLocalChecked());
|
|
309
|
+
retval = nc_put_att_text(parent_id, var_id, name.c_str(), v.length(), v.c_str());
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
if (retval != NC_NOERR)
|
|
313
|
+
{
|
|
314
|
+
throw_netcdf_error(isolate, retval);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
void Attribute::Delete(const v8::FunctionCallbackInfo<v8::Value> &args)
|
|
319
|
+
{
|
|
320
|
+
auto *obj = node::ObjectWrap::Unwrap<Attribute>(args.Holder());
|
|
321
|
+
const int retval = nc_del_att(obj->parent_id, obj->var_id, obj->name.c_str());
|
|
322
|
+
if (retval != NC_NOERR)
|
|
323
|
+
{
|
|
324
|
+
throw_netcdf_error(args.GetIsolate(), retval);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
void Attribute::Inspect(const v8::FunctionCallbackInfo<v8::Value> &args)
|
|
329
|
+
{
|
|
330
|
+
v8::Isolate *isolate = args.GetIsolate();
|
|
331
|
+
args.GetReturnValue().Set(
|
|
332
|
+
v8::String::NewFromUtf8(isolate, "[object Attribute]", v8::NewStringType::kNormal).ToLocalChecked());
|
|
333
|
+
}
|
|
334
|
+
} // namespace nodenetcdfjs
|
package/src/Attribute.h
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#ifndef NODENETCDFJS_ATTRIBUTE_H
|
|
2
|
+
#define NODENETCDFJS_ATTRIBUTE_H
|
|
3
|
+
|
|
4
|
+
#include <node.h>
|
|
5
|
+
#include <node_object_wrap.h>
|
|
6
|
+
#include <string>
|
|
7
|
+
|
|
8
|
+
namespace nodenetcdfjs
|
|
9
|
+
{
|
|
10
|
+
|
|
11
|
+
class Attribute : public node::ObjectWrap
|
|
12
|
+
{
|
|
13
|
+
public:
|
|
14
|
+
static void Init(v8::Local<v8::Object> exports);
|
|
15
|
+
Attribute(const char *name_, int var_id_, int parent_id_) noexcept;
|
|
16
|
+
Attribute(const char *name_, int var_id_, int parent_id_, int type_) noexcept;
|
|
17
|
+
|
|
18
|
+
void set_value(const v8::Local<v8::Value> &val);
|
|
19
|
+
|
|
20
|
+
private:
|
|
21
|
+
// Delete copy and move operations for safety
|
|
22
|
+
Attribute(const Attribute &) = delete;
|
|
23
|
+
Attribute &operator=(const Attribute &) = delete;
|
|
24
|
+
Attribute(Attribute &&) = delete;
|
|
25
|
+
Attribute &operator=(Attribute &&) = delete;
|
|
26
|
+
|
|
27
|
+
static v8::Persistent<v8::Function> constructor;
|
|
28
|
+
|
|
29
|
+
static void Delete(const v8::FunctionCallbackInfo<v8::Value> &args);
|
|
30
|
+
static void GetName(v8::Local<v8::String> property, const v8::PropertyCallbackInfo<v8::Value> &info);
|
|
31
|
+
static void SetName(v8::Local<v8::String> property, v8::Local<v8::Value> val,
|
|
32
|
+
const v8::PropertyCallbackInfo<void> &info);
|
|
33
|
+
static void GetValue(v8::Local<v8::String> property, const v8::PropertyCallbackInfo<v8::Value> &info);
|
|
34
|
+
static void SetValue(v8::Local<v8::String> property, v8::Local<v8::Value> val,
|
|
35
|
+
const v8::PropertyCallbackInfo<void> &info);
|
|
36
|
+
static void Inspect(const v8::FunctionCallbackInfo<v8::Value> &args);
|
|
37
|
+
|
|
38
|
+
std::string name{};
|
|
39
|
+
int var_id{-1};
|
|
40
|
+
int parent_id{-1};
|
|
41
|
+
int type{-1};
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
} // namespace nodenetcdfjs
|
|
45
|
+
|
|
46
|
+
#endif
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
#include "Dimension.h"
|
|
2
|
+
#include "nodenetcdfjs.h"
|
|
3
|
+
#include <netcdf.h>
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
namespace nodenetcdfjs
|
|
7
|
+
{
|
|
8
|
+
|
|
9
|
+
v8::Persistent<v8::Function> Dimension::constructor;
|
|
10
|
+
|
|
11
|
+
Dimension::Dimension(int id_, int parent_id_) noexcept
|
|
12
|
+
: id(id_)
|
|
13
|
+
, parent_id(parent_id_)
|
|
14
|
+
{
|
|
15
|
+
v8::Isolate *isolate = v8::Isolate::GetCurrent();
|
|
16
|
+
v8::Local<v8::Object> obj =
|
|
17
|
+
v8::Local<v8::Function>::New(isolate, constructor)->NewInstance(isolate->GetCurrentContext()).ToLocalChecked();
|
|
18
|
+
Wrap(obj);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
void Dimension::Init(v8::Local<v8::Object> exports)
|
|
22
|
+
{
|
|
23
|
+
v8::Isolate *isolate = exports->GetIsolate();
|
|
24
|
+
v8::Local<v8::FunctionTemplate> tpl = v8::FunctionTemplate::New(isolate);
|
|
25
|
+
tpl->SetClassName(v8::String::NewFromUtf8(isolate, "Dimension", v8::NewStringType::kNormal).ToLocalChecked());
|
|
26
|
+
tpl->InstanceTemplate()->SetInternalFieldCount(1);
|
|
27
|
+
NODE_SET_PROTOTYPE_METHOD(tpl, "inspect", Dimension::Inspect);
|
|
28
|
+
tpl->InstanceTemplate()->SetAccessor(
|
|
29
|
+
v8::String::NewFromUtf8(isolate, "id", v8::NewStringType::kNormal).ToLocalChecked(), Dimension::GetId);
|
|
30
|
+
tpl->InstanceTemplate()->SetAccessor(
|
|
31
|
+
v8::String::NewFromUtf8(isolate, "length", v8::NewStringType::kNormal).ToLocalChecked(), Dimension::GetLength);
|
|
32
|
+
tpl->InstanceTemplate()->SetAccessor(
|
|
33
|
+
v8::String::NewFromUtf8(isolate, "name", v8::NewStringType::kNormal).ToLocalChecked(), Dimension::GetName,
|
|
34
|
+
Dimension::SetName);
|
|
35
|
+
constructor.Reset(isolate, tpl->GetFunction(isolate->GetCurrentContext()).ToLocalChecked());
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
bool Dimension::get_name(char *name) const noexcept
|
|
39
|
+
{
|
|
40
|
+
const int retval = nc_inq_dimname(parent_id, id, name);
|
|
41
|
+
if (retval != NC_NOERR)
|
|
42
|
+
{
|
|
43
|
+
throw_netcdf_error(v8::Isolate::GetCurrent(), retval);
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
void Dimension::GetId(v8::Local<v8::String> property, const v8::PropertyCallbackInfo<v8::Value> &info)
|
|
50
|
+
{
|
|
51
|
+
v8::Isolate *isolate = info.GetIsolate();
|
|
52
|
+
const auto *obj = node::ObjectWrap::Unwrap<Dimension>(info.Holder());
|
|
53
|
+
info.GetReturnValue().Set(v8::Integer::New(isolate, obj->id));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
void Dimension::GetLength(v8::Local<v8::String> property, const v8::PropertyCallbackInfo<v8::Value> &info)
|
|
57
|
+
{
|
|
58
|
+
v8::Isolate *isolate = info.GetIsolate();
|
|
59
|
+
const auto *obj = node::ObjectWrap::Unwrap<Dimension>(info.Holder());
|
|
60
|
+
|
|
61
|
+
size_t len = 0;
|
|
62
|
+
const int retval = nc_inq_dimlen(obj->parent_id, obj->id, &len);
|
|
63
|
+
if (retval != NC_NOERR)
|
|
64
|
+
{
|
|
65
|
+
throw_netcdf_error(isolate, retval);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
info.GetReturnValue().Set(v8::Integer::New(isolate, static_cast<int32_t>(len)));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
void Dimension::GetName(v8::Local<v8::String> property, const v8::PropertyCallbackInfo<v8::Value> &info)
|
|
72
|
+
{
|
|
73
|
+
v8::Isolate *isolate = info.GetIsolate();
|
|
74
|
+
const auto *obj = node::ObjectWrap::Unwrap<Dimension>(info.Holder());
|
|
75
|
+
|
|
76
|
+
std::array<char, NC_MAX_NAME + 1> name{};
|
|
77
|
+
if (obj->get_name(name.data()))
|
|
78
|
+
{
|
|
79
|
+
info.GetReturnValue().Set(
|
|
80
|
+
v8::String::NewFromUtf8(isolate, name.data(), v8::NewStringType::kNormal).ToLocalChecked());
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
void Dimension::SetName(v8::Local<v8::String> property, v8::Local<v8::Value> val,
|
|
85
|
+
const v8::PropertyCallbackInfo<void> &info)
|
|
86
|
+
{
|
|
87
|
+
v8::Isolate *isolate = info.GetIsolate();
|
|
88
|
+
auto *obj = node::ObjectWrap::Unwrap<Dimension>(info.Holder());
|
|
89
|
+
|
|
90
|
+
const v8::String::Utf8Value new_name_(isolate, val->ToString(isolate->GetCurrentContext()).ToLocalChecked());
|
|
91
|
+
const int retval = nc_rename_dim(obj->parent_id, obj->id, *new_name_);
|
|
92
|
+
|
|
93
|
+
if (retval != NC_NOERR)
|
|
94
|
+
{
|
|
95
|
+
throw_netcdf_error(isolate, retval);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
void Dimension::Inspect(const v8::FunctionCallbackInfo<v8::Value> &args)
|
|
100
|
+
{
|
|
101
|
+
v8::Isolate *isolate = args.GetIsolate();
|
|
102
|
+
args.GetReturnValue().Set(
|
|
103
|
+
v8::String::NewFromUtf8(isolate, "[object Dimension]", v8::NewStringType::kNormal).ToLocalChecked());
|
|
104
|
+
}
|
|
105
|
+
} // namespace nodenetcdfjs
|
package/src/Dimension.h
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#ifndef NODENETCDFJS_DIMENSION_H
|
|
2
|
+
#define NODENETCDFJS_DIMENSION_H
|
|
3
|
+
|
|
4
|
+
#include <node.h>
|
|
5
|
+
#include <node_object_wrap.h>
|
|
6
|
+
|
|
7
|
+
namespace nodenetcdfjs
|
|
8
|
+
{
|
|
9
|
+
|
|
10
|
+
class Dimension : public node::ObjectWrap
|
|
11
|
+
{
|
|
12
|
+
public:
|
|
13
|
+
static void Init(v8::Local<v8::Object> exports);
|
|
14
|
+
Dimension(int id_, int parent_id_) noexcept;
|
|
15
|
+
|
|
16
|
+
[[nodiscard]] bool get_name(char *name) const noexcept;
|
|
17
|
+
|
|
18
|
+
private:
|
|
19
|
+
// Delete copy and move operations for safety
|
|
20
|
+
Dimension(const Dimension &) = delete;
|
|
21
|
+
Dimension &operator=(const Dimension &) = delete;
|
|
22
|
+
Dimension(Dimension &&) = delete;
|
|
23
|
+
Dimension &operator=(Dimension &&) = delete;
|
|
24
|
+
|
|
25
|
+
static v8::Persistent<v8::Function> constructor;
|
|
26
|
+
|
|
27
|
+
static void GetId(v8::Local<v8::String> property, const v8::PropertyCallbackInfo<v8::Value> &info);
|
|
28
|
+
static void GetLength(v8::Local<v8::String> property, const v8::PropertyCallbackInfo<v8::Value> &info);
|
|
29
|
+
static void GetName(v8::Local<v8::String> property, const v8::PropertyCallbackInfo<v8::Value> &info);
|
|
30
|
+
static void SetName(v8::Local<v8::String> property, v8::Local<v8::Value> val,
|
|
31
|
+
const v8::PropertyCallbackInfo<void> &info);
|
|
32
|
+
static void Inspect(const v8::FunctionCallbackInfo<v8::Value> &args);
|
|
33
|
+
|
|
34
|
+
int id{-1};
|
|
35
|
+
int parent_id{-1};
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
} // namespace nodenetcdfjs
|
|
39
|
+
|
|
40
|
+
#endif
|