• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

melchor629 / node-flac-bindings / 14597664676

22 Apr 2025 02:43PM UTC coverage: 91.38% (-0.02%) from 91.398%
14597664676

push

github

melchor629
chore: update deps

159 of 202 branches covered (78.71%)

Branch coverage included in aggregate %.

5025 of 5471 relevant lines covered (91.85%)

37329.45 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.56
/src/metadata/metadata1.cpp
1
#include "../mappings/mappings.hpp"
2
#include "../mappings/native_async_iterator.hpp"
3
#include "../mappings/native_iterator.hpp"
4
#include "../utils/async.hpp"
5
#include "../utils/enum.hpp"
6
#include <FLAC/metadata.h>
7
#include <memory>
8

9
namespace flac_bindings {
10

11
  using namespace Napi;
12

13
  class SimpleIterator: public ObjectWrap<SimpleIterator> {
14
    FLAC__Metadata_SimpleIterator* it;
15

16
    void throwIfStatusIsNotOk(const Napi::Env& env) {
4✔
17
      auto status = FLAC__metadata_simple_iterator_status(it);
4✔
18
      if (status != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK) {
4✔
19
        throw Error::New(
×
20
          env,
21
          "Operation failed: "s + &FLAC__Metadata_SimpleIteratorStatusString[status][38]);
×
22
      }
23
    }
4✔
24

25
    template<typename T>
26
    void rejectIfStatusIsNotOk(typename AsyncBackgroundTask<T>::ExecutionProgress& c) {
4✔
27
      auto status = FLAC__metadata_simple_iterator_status(it);
4✔
28
      if (status != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK) {
4✔
29
        c.reject("Operation failed: "s + &FLAC__Metadata_SimpleIteratorStatusString[status][38]);
×
30
      }
31
    }
4✔
32

33
    template<typename R>
34
    Napi::Value asyncImpl(
38✔
35
      const Napi::Env& env,
36
      const char* name,
37
      const std::initializer_list<Napi::Value>& args,
38
      std::function<R()> impl,
39
      std::function<Napi::Value(const Napi::Env&, R)> converter = booleanToJs<R>) {
40
      EscapableHandleScope scope(env);
38✔
41
      auto worker = new AsyncBackgroundTask<R>(
114✔
42
        env,
43
        [impl](auto c) {
38✔
44
          auto res = impl();
50✔
45
          c.resolve(res);
50✔
46
        },
47
        nullptr,
48
        name,
49
        converter);
50

51
      for (auto i = args.begin(); i != args.end(); i += 1) {
81✔
52
        worker->Receiver().Set(i - args.begin(), *i);
43✔
53
      }
54

55
      worker->Queue();
38✔
56
      return scope.Escape(worker->getPromise());
76✔
57
    }
76✔
58

59
    void checkStatus(Napi::Env env, bool succeeded) {
26✔
60
      if (!succeeded) {
26✔
61
        auto status = FLAC__metadata_simple_iterator_status(it);
2✔
62
        // remove prefix FLAC__METADATA_SIMPLE_ITERATOR_STATUS_
63
        auto statusString = FLAC__Metadata_SimpleIteratorStatusString[status] + 38;
2✔
64
        auto error = Error::New(env, "SimpleIterator initialization failed: "s + statusString);
2✔
65
        error.Set("status", numberToJs(env, status));
2✔
66
        error.Set("statusString", String::New(env, statusString));
2✔
67
        throw error;
2✔
68
      }
2✔
69
    }
24✔
70

71
  public:
72
    static Function init(Napi::Env env, FlacAddon& addon) {
21✔
73
      EscapableHandleScope scope(env);
21✔
74

75
      auto constructor = DefineClass(
21✔
76
        env,
77
        "SimpleIterator",
78
        {
79
          InstanceMethod(Napi::Symbol::WellKnown(env, "iterator"), &SimpleIterator::iterator),
42✔
80
          InstanceMethod(
42✔
81
            Napi::Symbol::WellKnown(env, "asyncIterator"),
82
            &SimpleIterator::asyncIterator),
83
          InstanceMethod("status", &SimpleIterator::status),
21✔
84
          InstanceMethod("init", &SimpleIterator::init),
21✔
85
          InstanceMethod("initAsync", &SimpleIterator::initAsync),
21✔
86
          InstanceMethod("isWritable", &SimpleIterator::isWritable),
21✔
87
          InstanceMethod("isLast", &SimpleIterator::isLast),
21✔
88
          InstanceMethod("next", &SimpleIterator::next),
21✔
89
          InstanceMethod("nextAsync", &SimpleIterator::nextAsync),
21✔
90
          InstanceMethod("prev", &SimpleIterator::prev),
21✔
91
          InstanceMethod("prevAsync", &SimpleIterator::prevAsync),
21✔
92
          InstanceMethod("getBlockOffset", &SimpleIterator::getBlockOffset),
21✔
93
          InstanceMethod("getBlockType", &SimpleIterator::getBlockType),
21✔
94
          InstanceMethod("getBlockLength", &SimpleIterator::getBlockLength),
21✔
95
          InstanceMethod("getApplicationId", &SimpleIterator::getApplicationId),
21✔
96
          InstanceMethod("getApplicationIdAsync", &SimpleIterator::getApplicationIdAsync),
21✔
97
          InstanceMethod("getBlock", &SimpleIterator::getBlock),
21✔
98
          InstanceMethod("getBlockAsync", &SimpleIterator::getBlockAsync),
21✔
99
          InstanceMethod("setBlock", &SimpleIterator::setBlock),
21✔
100
          InstanceMethod("setBlockAsync", &SimpleIterator::setBlockAsync),
21✔
101
          InstanceMethod("insertBlockAfter", &SimpleIterator::insertBlockAfter),
21✔
102
          InstanceMethod("insertBlockAfterAsync", &SimpleIterator::insertBlockAfterAsync),
21✔
103
          InstanceMethod("deleteBlock", &SimpleIterator::deleteBlock),
21✔
104
          InstanceMethod("deleteBlockAsync", &SimpleIterator::deleteBlockAsync),
21✔
105
        });
106
      c_enum::declareInObject(constructor, "Status", createStatusEnum);
21✔
107

108
      constructor.Freeze();
21✔
109
      addon.simpleIteratorConstructor = Persistent(constructor);
21✔
110

111
      return scope.Escape(constructor).As<Function>();
42✔
112
    }
21✔
113

114
    SimpleIterator(const CallbackInfo& info): ObjectWrap<SimpleIterator>(info) {
32✔
115
      it = FLAC__metadata_simple_iterator_new();
32✔
116
      if (it == nullptr) {
32✔
117
        throw Error::New(info.Env(), "Could not allocate memory");
×
118
      }
119
    }
32✔
120

121
    ~SimpleIterator() {
×
122
      FLAC__metadata_simple_iterator_delete(it);
×
123
    }
×
124

125
    Napi::Value iterator(const CallbackInfo& info) {
1✔
126
      while (FLAC__metadata_simple_iterator_prev(it))
1✔
127
        ;
128
      std::shared_ptr<bool> pastEnd(new bool(false));
1✔
129
      return NativeIterator::newIterator(
2✔
130
        info.Env(),
131
        [this, pastEnd](auto env, auto) -> NativeIterator::IterationReturnValue {
1✔
132
          if (FLAC__metadata_simple_iterator_is_last(it)) {
5✔
133
            if (*pastEnd) {
2✔
134
              return {};
1✔
135
            }
136

137
            *pastEnd = true;
1✔
138
          }
139

140
          auto metadata = FLAC__metadata_simple_iterator_get_block(it);
4✔
141
          throwIfStatusIsNotOk(env);
4✔
142
          FLAC__metadata_simple_iterator_next(it);
4✔
143
          return Metadata::toJs(env, metadata, true);
4✔
144
        });
2✔
145
    }
2✔
146

147
    Napi::Value asyncIterator(const CallbackInfo& info) {
1✔
148
      using NAI = NativeAsyncIterator<FLAC__StreamMetadata*>;
149
      std::shared_ptr<bool> hasRollbacked(new bool(false));
1✔
150
      std::shared_ptr<bool> pastEnd(new bool(false));
1✔
151
      return NAI::newIterator(
2✔
152
        info.Env(),
2✔
153
        "flac_bindings::SimpleIterator::asyncIterator",
154
        [this, hasRollbacked, pastEnd](auto c, auto) -> NAI::IterationReturnValue {
1✔
155
          if (!*hasRollbacked) {
5✔
156
            while (FLAC__metadata_simple_iterator_prev(it))
1✔
157
              ;
158
            *hasRollbacked = true;
1✔
159
          }
160

161
          if (FLAC__metadata_simple_iterator_is_last(it)) {
5✔
162
            if (*pastEnd) {
2✔
163
              return std::nullopt;
1✔
164
            }
165

166
            *pastEnd = true;
1✔
167
          }
168

169
          auto metadata = FLAC__metadata_simple_iterator_get_block(it);
4✔
170
          rejectIfStatusIsNotOk<std::optional<FLAC__StreamMetadata*>>(c);
4✔
171
          FLAC__metadata_simple_iterator_next(it);
4✔
172
          return metadata;
4✔
173
        },
174
        [](auto env, auto* metadata) { return Metadata::toJs(env, metadata, true); });
6✔
175
    }
2✔
176

177
    Napi::Value status(const CallbackInfo& info) {
2✔
178
      return numberToJs(info.Env(), FLAC__metadata_simple_iterator_status(it));
2✔
179
    }
180

181
    void init(const CallbackInfo& info) {
15✔
182
      auto path = stringFromJs(info[0]);
15✔
183
      auto readOnly = maybeBooleanFromJs<FLAC__bool>(info[1]).value_or(false);
14✔
184
      auto preserve = maybeBooleanFromJs<FLAC__bool>(info[2]).value_or(false);
14✔
185
      auto res = FLAC__metadata_simple_iterator_init(it, path.c_str(), readOnly, preserve);
14✔
186
      checkStatus(info.Env(), res);
14✔
187
    }
14✔
188

189
    Napi::Value initAsync(const CallbackInfo& info) {
13✔
190
      auto path = stringFromJs(info[0]);
13✔
191
      auto readOnly = maybeBooleanFromJs<FLAC__bool>(info[1]).value_or(false);
12✔
192
      auto preserve = maybeBooleanFromJs<FLAC__bool>(info[2]).value_or(false);
12✔
193
      return asyncImpl<FLAC__bool>(
12✔
194
        info.Env(),
24✔
195
        "flac_bindings::SimpleIterator::initAsync",
196
        {info.This()},
12✔
197
        [this, path, readOnly, preserve]() {
12✔
198
          return FLAC__metadata_simple_iterator_init(it, path.c_str(), readOnly, preserve);
12✔
199
        },
200
        [this](auto env, auto value) {
12✔
201
          this->checkStatus(env, value);
12✔
202
          return env.Undefined();
11✔
203
        });
24✔
204
    }
24✔
205

206
    Napi::Value isWritable(const CallbackInfo& info) {
2✔
207
      return booleanToJs(info.Env(), FLAC__metadata_simple_iterator_is_writable(it));
2✔
208
    }
209

210
    Napi::Value isLast(const CallbackInfo& info) {
20✔
211
      return booleanToJs(info.Env(), FLAC__metadata_simple_iterator_is_last(it));
20✔
212
    }
213

214
    Napi::Value next(const CallbackInfo& info) {
18✔
215
      return booleanToJs(info.Env(), FLAC__metadata_simple_iterator_next(it));
18✔
216
    }
217

218
    Napi::Value nextAsync(const CallbackInfo& info) {
16✔
219
      return asyncImpl<FLAC__bool>(
48✔
220
        info.Env(),
32✔
221
        "flac_bindings::SimpleIterator::nextAsync",
222
        {info.This()},
16✔
223
        [this]() { return FLAC__metadata_simple_iterator_next(it); });
80✔
224
    }
225

226
    Napi::Value prev(const CallbackInfo& info) {
5✔
227
      return booleanToJs(info.Env(), FLAC__metadata_simple_iterator_prev(it));
5✔
228
    }
229

230
    Napi::Value prevAsync(const CallbackInfo& info) {
5✔
231
      return asyncImpl<FLAC__bool>(
15✔
232
        info.Env(),
10✔
233
        "flac_bindings::SimpleIterator::prevAsync",
234
        {info.This()},
5✔
235
        [this]() { return FLAC__metadata_simple_iterator_prev(it); });
25✔
236
    }
237

238
    Napi::Value getBlockOffset(const CallbackInfo& info) {
20✔
239
      auto ret = FLAC__metadata_simple_iterator_get_block_offset(it);
20✔
240
      return numberToJs(info.Env(), ret);
20✔
241
    }
242

243
    Napi::Value getBlockType(const CallbackInfo& info) {
24✔
244
      auto ret = FLAC__metadata_simple_iterator_get_block_type(it);
24✔
245
      return numberToJs(info.Env(), ret);
24✔
246
    }
247

248
    Napi::Value getBlockLength(const CallbackInfo& info) {
20✔
249
      auto ret = FLAC__metadata_simple_iterator_get_block_length(it);
20✔
250
      return numberToJs(info.Env(), ret);
20✔
251
    }
252

253
    Napi::Value getApplicationId(const CallbackInfo& info) {
2✔
254
      FLAC__byte id[4];
255
      auto ret = FLAC__metadata_simple_iterator_get_application_id(it, id);
2✔
256
      if (ret) {
2✔
257
        return Buffer<FLAC__byte>::Copy(info.Env(), id, 4);
2✔
258
      }
259

260
      return info.Env().Null();
×
261
    }
262

263
    Napi::Value getApplicationIdAsync(const CallbackInfo& info) {
2✔
264
      return asyncImpl<FLAC__byte*>(
4✔
265
        info.Env(),
4✔
266
        "flac_bindings::SimpleIterator:getApplicationId",
267
        {info.This()},
2✔
268
        [this]() -> FLAC__byte* {
4✔
269
          FLAC__byte* id = new FLAC__byte[4];
2✔
270
          if (FLAC__metadata_simple_iterator_get_application_id(it, id)) {
2✔
271
            return id;
2✔
272
          }
273

274
          delete[] id;
×
275
          return nullptr;
×
276
        },
277
        [](auto env, FLAC__byte* id) -> Napi::Value {
2✔
278
          if (id != nullptr) {
2✔
279
            auto buffer = Buffer<FLAC__byte>::Copy(env, id, 4);
2✔
280
            delete[] id;
2✔
281
            return buffer;
2✔
282
          }
283

284
          return env.Null();
×
285
        });
4✔
286
    }
287

288
    Napi::Value getBlock(const CallbackInfo& info) {
12✔
289
      auto metadata = FLAC__metadata_simple_iterator_get_block(it);
12✔
290
      return Metadata::toJs(info.Env(), metadata);
12✔
291
    }
292

293
    Napi::Value getBlockAsync(const CallbackInfo& info) {
10✔
294
      return asyncImpl<FLAC__StreamMetadata*>(
20✔
295
        info.Env(),
20✔
296
        "flac_bindings::SimpleIterator::getBlockAsync",
297
        {info.This()},
10✔
298
        [this]() { return FLAC__metadata_simple_iterator_get_block(it); },
30✔
299
        [](auto env, auto metadata) { return Metadata::toJs(env, metadata, true); });
30✔
300
    }
301

302
    Napi::Value setBlock(const CallbackInfo& info) {
3✔
303
      auto metadata = Metadata::fromJs(info[0]);
3✔
304
      auto pad = maybeNumberFromJs<FLAC__bool>(info[1]).value_or(true);
2✔
305

306
      auto ret = FLAC__metadata_simple_iterator_set_block(it, metadata, pad);
2✔
307
      return booleanToJs(info.Env(), ret);
4✔
308
    }
2✔
309

310
    Napi::Value setBlockAsync(const CallbackInfo& info) {
3✔
311
      FLAC__StreamMetadata* metadata = Metadata::fromJs(info[0]);
3✔
312
      auto pad = maybeNumberFromJs<FLAC__bool>(info[1]).value_or(true);
2✔
313

314
      return asyncImpl<FLAC__bool>(
6✔
315
        info.Env(),
4✔
316
        "flac_bindings::SimpleIterator::setBlockAsync",
317
        {info.This(), info[0]},
2✔
318
        [this, metadata, pad]() {
4✔
319
          return FLAC__metadata_simple_iterator_set_block(it, metadata, pad);
2✔
320
        });
4✔
321
    }
322

323
    Napi::Value insertBlockAfter(const CallbackInfo& info) {
2✔
324
      auto metadata = Metadata::fromJs(info[0]);
2✔
325
      auto pad = maybeNumberFromJs<FLAC__bool>(info[1]).value_or(true);
1✔
326

327
      auto ret = FLAC__metadata_simple_iterator_insert_block_after(it, metadata, pad);
1✔
328
      return booleanToJs(info.Env(), ret);
2✔
329
    }
1✔
330

331
    Napi::Value insertBlockAfterAsync(const CallbackInfo& info) {
2✔
332
      FLAC__StreamMetadata* metadata = Metadata::fromJs(info[0]);
2✔
333
      auto pad = maybeNumberFromJs<FLAC__bool>(info[1]).value_or(true);
1✔
334

335
      return asyncImpl<FLAC__bool>(
3✔
336
        info.Env(),
2✔
337
        "flac_bindings::SimpleIterator::insertBlockAfterAsync",
338
        {info.This(), info[0]},
1✔
339
        [this, metadata, pad]() {
2✔
340
          return FLAC__metadata_simple_iterator_insert_block_after(it, metadata, pad);
1✔
341
        });
2✔
342
    }
343

344
    Napi::Value deleteBlock(const CallbackInfo& info) {
2✔
345
      auto pad = maybeNumberFromJs<FLAC__bool>(info[0]).value_or(true);
2✔
346

347
      auto ret = FLAC__metadata_simple_iterator_delete_block(it, pad);
2✔
348
      return booleanToJs(info.Env(), ret);
2✔
349
    }
350

351
    Napi::Value deleteBlockAsync(const CallbackInfo& info) {
2✔
352
      auto pad = maybeNumberFromJs<FLAC__bool>(info[0]).value_or(true);
2✔
353

354
      return asyncImpl<FLAC__bool>(
6✔
355
        info.Env(),
4✔
356
        "flac_bindings::SimpleIterator::deleteBlockAsync",
357
        {info.This(), info[0]},
2✔
358
        [this, pad]() { return FLAC__metadata_simple_iterator_delete_block(it, pad); });
10✔
359
    }
360

361
    static c_enum::DefineReturnType createStatusEnum(const Napi::Env& env) {
21✔
362
      auto obj1 = Object::New(env);
21✔
363
      auto obj2 = Object::New(env);
21✔
364
      c_enum::defineValue(obj1, obj2, "OK", FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK);
21✔
365
      c_enum::defineValue(
21✔
366
        obj1,
367
        obj2,
368
        "ILLEGAL_INPUT",
369
        FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT);
370
      c_enum::defineValue(
21✔
371
        obj1,
372
        obj2,
373
        "ERROR_OPENING_FILE",
374
        FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE);
375
      c_enum::defineValue(
21✔
376
        obj1,
377
        obj2,
378
        "NOT_A_FLAC_FILE",
379
        FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE);
380
      c_enum::defineValue(
21✔
381
        obj1,
382
        obj2,
383
        "NOT_WRITABLE",
384
        FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE);
385
      c_enum::defineValue(
21✔
386
        obj1,
387
        obj2,
388
        "BAD_METADATA",
389
        FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA);
390
      c_enum::defineValue(
21✔
391
        obj1,
392
        obj2,
393
        "READ_ERROR",
394
        FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR);
395
      c_enum::defineValue(
21✔
396
        obj1,
397
        obj2,
398
        "SEEK_ERROR",
399
        FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR);
400
      c_enum::defineValue(
21✔
401
        obj1,
402
        obj2,
403
        "WRITE_ERROR",
404
        FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR);
405
      c_enum::defineValue(
21✔
406
        obj1,
407
        obj2,
408
        "RENAME_ERROR",
409
        FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR);
410
      c_enum::defineValue(
21✔
411
        obj1,
412
        obj2,
413
        "UNLINK_ERROR",
414
        FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR);
415
      c_enum::defineValue(
21✔
416
        obj1,
417
        obj2,
418
        "MEMORY_ALLOCATION_ERROR",
419
        FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR);
420
      c_enum::defineValue(
21✔
421
        obj1,
422
        obj2,
423
        "INTERNAL_ERROR",
424
        FLAC__METADATA_SIMPLE_ITERATOR_STATUS_INTERNAL_ERROR);
425
      return std::make_tuple(obj1, obj2);
42✔
426
    }
427
  };
428

429
  Function initMetadata1(Env env, FlacAddon& addon) {
21✔
430
    EscapableHandleScope scope(env);
21✔
431
    return scope.Escape(SimpleIterator::init(env, addon)).As<Function>();
42✔
432
  }
21✔
433

434
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc