@cosyte/dicom 0.0.17 → 0.0.19

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/dist/index.cjs CHANGED
@@ -11,7 +11,7 @@ var __export = (target, all) => {
11
11
  };
12
12
 
13
13
  // src/version.ts
14
- var VERSION = "0.0.17";
14
+ var VERSION = "0.0.19";
15
15
 
16
16
  // src/dictionary/index.ts
17
17
  var dictionary_exports = {};
@@ -11668,23 +11668,52 @@ var FATAL_CODES = {
11668
11668
  UNSUPPORTED_TRANSFER_SYNTAX: "UNSUPPORTED_TRANSFER_SYNTAX",
11669
11669
  EMPTY_INPUT: "EMPTY_INPUT"
11670
11670
  };
11671
+ var OFFSET_FRAMES = {
11672
+ /**
11673
+ * Byte 0 is byte 0 of the buffer handed to `parseDicom`. The only frame in
11674
+ * which indexing the caller's own input by `byteOffset` is meaningful.
11675
+ */
11676
+ INPUT: "input",
11677
+ /**
11678
+ * Byte 0 is byte 0 of the inflated Data Set of a Deflated Explicit VR LE
11679
+ * object (`1.2.840.10008.1.2.1.99`). The compressed input holds no such
11680
+ * byte, so the offset does not index it at any scale.
11681
+ */
11682
+ INFLATED_DATASET: "inflated-dataset",
11683
+ /**
11684
+ * Byte 0 is byte 0 of a slice this parser cut from inside a Value Field: a
11685
+ * defined-length Sequence Item's value, or an `SQ`/`UN` value handed to a
11686
+ * descent. **Where that slice begins is deliberately not published** - see
11687
+ * this table's own note.
11688
+ */
11689
+ VALUE_SLICE: "value-slice"
11690
+ };
11671
11691
  var DicomParseError = class extends Error {
11672
11692
  code;
11673
11693
  byteOffset;
11694
+ /**
11695
+ * The coordinate system {@link DicomParseError.byteOffset} is counted in.
11696
+ * See {@link OFFSET_FRAMES}.
11697
+ */
11698
+ offsetFrame;
11674
11699
  snippet;
11675
11700
  contextPath;
11676
11701
  /**
11677
11702
  * Construct a new `DicomParseError`. All fields except `contextPath` are
11678
- * required so every thrower populates positional context per `TOL-02`.
11703
+ * required so every thrower populates positional context per `TOL-02` - and
11704
+ * `offsetFrame` is required for the same reason `byteOffset` is, because an
11705
+ * offset whose frame is optional is an offset whose frame is usually
11706
+ * missing.
11679
11707
  *
11680
11708
  * @internal
11681
11709
  */
11682
- constructor(code, message, byteOffset, snippet, contextPath) {
11683
- const formatted = `[${code}] ${message} (offset=${String(byteOffset)})` + (contextPath !== void 0 && contextPath.length > 0 ? ` \u2026 in ${contextPath.join("/")}` : "");
11710
+ constructor(code, message, byteOffset, offsetFrame, snippet, contextPath) {
11711
+ const formatted = `[${code}] ${message} (offset=${String(byteOffset)} frame=${offsetFrame})` + (contextPath !== void 0 && contextPath.length > 0 ? ` \u2026 in ${contextPath.join("/")}` : "");
11684
11712
  super(formatted);
11685
11713
  this.name = "DicomParseError";
11686
11714
  this.code = code;
11687
11715
  this.byteOffset = byteOffset;
11716
+ this.offsetFrame = offsetFrame;
11688
11717
  this.snippet = snippet;
11689
11718
  this.contextPath = contextPath;
11690
11719
  }
@@ -11710,7 +11739,12 @@ function makeEmitter(ctx) {
11710
11739
  w.code,
11711
11740
  w.message,
11712
11741
  w.position.byteOffset,
11713
- buildSnippet(ctx.buffer, w.position.byteOffset),
11742
+ // Both come off the SAME frame object, so an escalation cannot name one
11743
+ // frame and cut its bytes from another. `DicomParseWarning.position`
11744
+ // itself carries no frame - that is `PRE-EXISTING` and stated on
11745
+ // `DicomPosition`, not closed here.
11746
+ ctx.frame.name,
11747
+ buildSnippet(ctx.frame.buffer, w.position.byteOffset),
11714
11748
  w.position.contextPath
11715
11749
  );
11716
11750
  };
@@ -11836,8 +11870,11 @@ var FATAL_MESSAGES = Object.freeze({
11836
11870
  message: "File Meta is truncated."
11837
11871
  },
11838
11872
  // The declared group length is deliberately absent. It is four bytes of the
11839
- // document read as a 32-bit integer, and this code fires precisely when those
11840
- // four bytes are not what they claim to be.
11873
+ // document read as a 32-bit integer. **NOT because this code fires only when
11874
+ // those four bytes are fabricated** - an honestly truncated file raises it
11875
+ // with a perfectly correct group length, measured - but because they are four
11876
+ // bytes a sender wrote in either reading, and in the other one they are part
11877
+ // of somebody's value.
11841
11878
  FILE_META_GROUP_LENGTH_OVERRUNS: {
11842
11879
  code: FATAL_CODES.INVALID_FILE_META,
11843
11880
  message: "(0002,0000) FileMetaInformationGroupLength declares more bytes than remain in the input. The declared length and the count of bytes that remain are withheld; the byte offset locates the group."
@@ -11922,88 +11959,89 @@ function renderTransferSyntax(ts) {
11922
11959
  function renderZlibCode(code) {
11923
11960
  return code !== void 0 && ZLIB_CODES.has(code) ? code : WITHHELD;
11924
11961
  }
11925
- function build(key, byteOffset, snippet, tokens = {}) {
11962
+ function build(key, byteOffset, offsetFrame, snippet, tokens = {}) {
11926
11963
  const entry = FATAL_MESSAGES[key];
11927
11964
  const message = entry.message.replace("{vr}", renderVr(tokens.vr)).replace("{ts}", renderTransferSyntax(tokens.ts)).replace("{zlib}", renderZlibCode(tokens.zlib)).replace("{n}", String(tokens.n ?? 0));
11928
- return new DicomParseError(entry.code, message, byteOffset, snippet);
11965
+ return new DicomParseError(entry.code, message, byteOffset, offsetFrame, snippet);
11929
11966
  }
11930
- function at(key, buffer, offset, tokens = {}) {
11931
- return build(key, offset, buildSnippet(buffer, offset), tokens);
11967
+ function at(key, frame, offset, tokens = {}) {
11968
+ return build(key, offset, frame.name, buildSnippet(frame.buffer, offset), tokens);
11932
11969
  }
11933
11970
  function emptyInput() {
11934
- return build("EMPTY_INPUT", 0, "");
11971
+ return build("EMPTY_INPUT", 0, OFFSET_FRAMES.INPUT, "");
11935
11972
  }
11936
11973
  function emptyInputAfterNormalization() {
11937
- return build("EMPTY_INPUT_AFTER_NORMALIZATION", 0, "");
11974
+ return build("EMPTY_INPUT_AFTER_NORMALIZATION", 0, OFFSET_FRAMES.INPUT, "");
11938
11975
  }
11939
- function notDicomPart10Required(buffer, offset) {
11940
- return at("NOT_DICOM_PART_10_REQUIRED", buffer, offset);
11976
+ function notDicomPart10Required(frame, offset) {
11977
+ return at("NOT_DICOM_PART_10_REQUIRED", frame, offset);
11941
11978
  }
11942
- function notDicomPart10(buffer, offset) {
11943
- return at("NOT_DICOM_PART_10", buffer, offset);
11979
+ function notDicomPart10(frame, offset) {
11980
+ return at("NOT_DICOM_PART_10", frame, offset);
11944
11981
  }
11945
- function unsupportedTransferSyntax(buffer, offset, ts) {
11982
+ function unsupportedTransferSyntax(frame, offset, ts) {
11946
11983
  const name = uid(ts)?.name ?? "";
11947
11984
  return build(
11948
11985
  "UNSUPPORTED_TRANSFER_SYNTAX",
11949
11986
  offset,
11950
- name.length > 0 ? name : buildSnippet(buffer, offset),
11987
+ frame.name,
11988
+ name.length > 0 ? name : buildSnippet(frame.buffer, offset),
11951
11989
  { ts }
11952
11990
  );
11953
11991
  }
11954
- function fileMetaTruncated(buffer, offset) {
11955
- return at("FILE_META_TRUNCATED", buffer, offset);
11992
+ function fileMetaTruncated(frame, offset) {
11993
+ return at("FILE_META_TRUNCATED", frame, offset);
11956
11994
  }
11957
- function fileMetaGroupLengthOverruns(buffer, offset) {
11958
- return at("FILE_META_GROUP_LENGTH_OVERRUNS", buffer, offset);
11995
+ function fileMetaGroupLengthOverruns(frame, offset) {
11996
+ return at("FILE_META_GROUP_LENGTH_OVERRUNS", frame, offset);
11959
11997
  }
11960
- function fileMetaTransferSyntaxMissing(buffer, offset) {
11961
- return at("FILE_META_TRANSFER_SYNTAX_MISSING", buffer, offset);
11998
+ function fileMetaTransferSyntaxMissing(frame, offset) {
11999
+ return at("FILE_META_TRANSFER_SYNTAX_MISSING", frame, offset);
11962
12000
  }
11963
- function truncatedDatasetHeader(buffer, offset) {
11964
- return at("TRUNCATED_DATASET_HEADER", buffer, offset);
12001
+ function truncatedDatasetHeader(frame, offset) {
12002
+ return at("TRUNCATED_DATASET_HEADER", frame, offset);
11965
12003
  }
11966
- function truncatedFffeHeader(buffer, offset) {
11967
- return at("TRUNCATED_FFFE_HEADER", buffer, offset);
12004
+ function truncatedFffeHeader(frame, offset) {
12005
+ return at("TRUNCATED_FFFE_HEADER", frame, offset);
11968
12006
  }
11969
- function truncatedExplicitVrHeader(buffer, offset) {
11970
- return at("TRUNCATED_EXPLICIT_VR_HEADER", buffer, offset);
12007
+ function truncatedExplicitVrHeader(frame, offset) {
12008
+ return at("TRUNCATED_EXPLICIT_VR_HEADER", frame, offset);
11971
12009
  }
11972
- function sqItemHeaderTruncated(buffer, offset) {
11973
- return at("SQ_ITEM_HEADER_TRUNCATED", buffer, offset);
12010
+ function sqItemHeaderTruncated(frame, offset) {
12011
+ return at("SQ_ITEM_HEADER_TRUNCATED", frame, offset);
11974
12012
  }
11975
- function unexpectedFffeAtDatasetLevel(buffer, offset) {
11976
- return at("UNEXPECTED_FFFE_AT_DATASET_LEVEL", buffer, offset);
12013
+ function unexpectedFffeAtDatasetLevel(frame, offset) {
12014
+ return at("UNEXPECTED_FFFE_AT_DATASET_LEVEL", frame, offset);
11977
12015
  }
11978
- function unexpectedFffeAtDatasetRoot(buffer, offset) {
11979
- return at("UNEXPECTED_FFFE_AT_DATASET_ROOT", buffer, offset);
12016
+ function unexpectedFffeAtDatasetRoot(frame, offset) {
12017
+ return at("UNEXPECTED_FFFE_AT_DATASET_ROOT", frame, offset);
11980
12018
  }
11981
- function undefinedLengthOnNonSqExplicit(buffer, offset, vr) {
11982
- return at("UNDEFINED_LENGTH_ON_NON_SQ_EXPLICIT", buffer, offset, { vr });
12019
+ function undefinedLengthOnNonSqExplicit(frame, offset, vr) {
12020
+ return at("UNDEFINED_LENGTH_ON_NON_SQ_EXPLICIT", frame, offset, { vr });
11983
12021
  }
11984
- function undefinedLengthOnNonSqImplicit(buffer, offset, vr) {
11985
- return at("UNDEFINED_LENGTH_ON_NON_SQ_IMPLICIT", buffer, offset, { vr });
12022
+ function undefinedLengthOnNonSqImplicit(frame, offset, vr) {
12023
+ return at("UNDEFINED_LENGTH_ON_NON_SQ_IMPLICIT", frame, offset, { vr });
11986
12024
  }
11987
- function elementLengthExceedsBuffer(buffer, offset) {
11988
- return at("ELEMENT_LENGTH_EXCEEDS_BUFFER", buffer, offset);
12025
+ function elementLengthExceedsBuffer(frame, offset) {
12026
+ return at("ELEMENT_LENGTH_EXCEEDS_BUFFER", frame, offset);
11989
12027
  }
11990
- function unexpectedTagInsideSequence(buffer, offset) {
11991
- return at("UNEXPECTED_TAG_INSIDE_SEQUENCE", buffer, offset);
12028
+ function unexpectedTagInsideSequence(frame, offset) {
12029
+ return at("UNEXPECTED_TAG_INSIDE_SEQUENCE", frame, offset);
11992
12030
  }
11993
- function encapsulatedFragmentExceedsBuffer(buffer, offset) {
11994
- return at("ENCAPSULATED_FRAGMENT_EXCEEDS_BUFFER", buffer, offset);
12031
+ function encapsulatedFragmentExceedsBuffer(frame, offset) {
12032
+ return at("ENCAPSULATED_FRAGMENT_EXCEEDS_BUFFER", frame, offset);
11995
12033
  }
11996
- function itemLengthExceedsBuffer(buffer, offset) {
11997
- return at("ITEM_LENGTH_EXCEEDS_BUFFER", buffer, offset);
12034
+ function itemLengthExceedsBuffer(frame, offset) {
12035
+ return at("ITEM_LENGTH_EXCEEDS_BUFFER", frame, offset);
11998
12036
  }
11999
- function sqNestingDepthExceeded(buffer, offset, limit) {
12000
- return at("SQ_NESTING_DEPTH_EXCEEDED", buffer, offset, { n: limit });
12037
+ function sqNestingDepthExceeded(frame, offset, limit) {
12038
+ return at("SQ_NESTING_DEPTH_EXCEEDED", frame, offset, { n: limit });
12001
12039
  }
12002
- function inflatedPayloadExceedsCap(buffer, offset, cap) {
12003
- return at("INFLATED_PAYLOAD_EXCEEDS_CAP", buffer, offset, { n: cap });
12040
+ function inflatedPayloadExceedsCap(frame, offset, cap) {
12041
+ return at("INFLATED_PAYLOAD_EXCEEDS_CAP", frame, offset, { n: cap });
12004
12042
  }
12005
- function inflateFailed(buffer, offset, code) {
12006
- return at("INFLATE_FAILED", buffer, offset, ...code !== void 0 ? [{ zlib: code }] : []);
12043
+ function inflateFailed(frame, offset, code) {
12044
+ return at("INFLATE_FAILED", frame, offset, ...code !== void 0 ? [{ zlib: code }] : []);
12007
12045
  }
12008
12046
  function copyValueBytes(src) {
12009
12047
  const out = buffer.Buffer.allocUnsafeSlow(src.length);
@@ -12636,7 +12674,7 @@ function parseFileMeta(buffer$1, datasetStart, ctx, emit) {
12636
12674
  firstElement = readExplicitLeElement(cursor);
12637
12675
  } catch (err) {
12638
12676
  if (err instanceof RangeError) {
12639
- throw fileMetaTruncated(buffer$1, fmStart);
12677
+ throw fileMetaTruncated(ctx.frame, fmStart);
12640
12678
  }
12641
12679
  throw err;
12642
12680
  }
@@ -12646,7 +12684,7 @@ function parseFileMeta(buffer$1, datasetStart, ctx, emit) {
12646
12684
  if (firstElement.tag === "00020000" && firstElement.vr === "UL" && firstElement.value.length === 4) {
12647
12685
  declaredFmLength = firstElement.value.readUInt32LE(0);
12648
12686
  if (cursor.position + declaredFmLength > buffer$1.length) {
12649
- throw fileMetaGroupLengthOverruns(buffer$1, fmStart);
12687
+ throw fileMetaGroupLengthOverruns(ctx.frame, fmStart);
12650
12688
  }
12651
12689
  } else {
12652
12690
  emit(fileMetaGroupLengthMissing({ byteOffset: fmStart, fileMeta: true }));
@@ -12663,7 +12701,7 @@ function parseFileMeta(buffer$1, datasetStart, ctx, emit) {
12663
12701
  next = readExplicitLeElement(cursor);
12664
12702
  } catch (err) {
12665
12703
  if (err instanceof RangeError) {
12666
- throw fileMetaTruncated(buffer$1, fmStart);
12704
+ throw fileMetaTruncated(ctx.frame, fmStart);
12667
12705
  }
12668
12706
  throw err;
12669
12707
  }
@@ -12687,7 +12725,7 @@ function parseFileMeta(buffer$1, datasetStart, ctx, emit) {
12687
12725
  next = readExplicitLeElement(cursor);
12688
12726
  } catch (err) {
12689
12727
  if (err instanceof RangeError) {
12690
- throw fileMetaTruncated(buffer$1, fmStart);
12728
+ throw fileMetaTruncated(ctx.frame, fmStart);
12691
12729
  }
12692
12730
  throw err;
12693
12731
  }
@@ -12706,7 +12744,7 @@ function parseFileMeta(buffer$1, datasetStart, ctx, emit) {
12706
12744
  }
12707
12745
  const tsElement = fmElements.find((e) => e.tag === "00020010");
12708
12746
  if (tsElement === void 0 || tsElement.vr !== "UI") {
12709
- throw fileMetaTransferSyntaxMissing(buffer$1, fmStart);
12747
+ throw fileMetaTransferSyntaxMissing(ctx.frame, fmStart);
12710
12748
  }
12711
12749
  const extraElements = fmElements.filter((e) => !MODELED_FM_TAGS.has(e.tag)).map((e) => Object.freeze({ tag: e.tag, vr: e.vr, value: buffer.Buffer.from(e.value) }));
12712
12750
  const fileMeta = {
@@ -12790,13 +12828,13 @@ function parsePart10Header(buffer, ctx, emit) {
12790
12828
  return { datasetStart: 132, hadPreamble: true };
12791
12829
  }
12792
12830
  if (ctx.stripPreamble === "require") {
12793
- throw notDicomPart10Required(buffer, 0);
12831
+ throw notDicomPart10Required(ctx.frame, 0);
12794
12832
  }
12795
12833
  if (looksLikeFileMetaGroupLengthAtOffsetZero(buffer)) {
12796
12834
  emit(missingPreamble({ byteOffset: 0 }));
12797
12835
  return { datasetStart: 0, hadPreamble: false };
12798
12836
  }
12799
- throw notDicomPart10(buffer, 0);
12837
+ throw notDicomPart10(ctx.frame, 0);
12800
12838
  }
12801
12839
  function looksLikeFileMetaGroupLengthAtOffsetZero(buffer) {
12802
12840
  if (buffer.length < 12) return false;
@@ -13207,7 +13245,7 @@ function parseSequence(buffer, valueStart, ctx, emit, opts) {
13207
13245
  ctx.nestingDepth += 1;
13208
13246
  if (ctx.nestingDepth > NESTING_DEPTH_LIMIT) {
13209
13247
  ctx.nestingDepth -= 1;
13210
- throw sqNestingDepthExceeded(buffer, valueStart, NESTING_DEPTH_LIMIT);
13248
+ throw sqNestingDepthExceeded(ctx.frame, valueStart, NESTING_DEPTH_LIMIT);
13211
13249
  }
13212
13250
  ctx.encodingContextStack.push(
13213
13251
  opts.encapsulatedPixelData === true ? "EncapsulatedPixelData" : "SqItem"
@@ -13243,7 +13281,7 @@ function parseSequence(buffer, valueStart, ctx, emit, opts) {
13243
13281
  itemLength = cursor.readUInt32();
13244
13282
  } catch (err) {
13245
13283
  if (err instanceof RangeError) {
13246
- throw sqItemHeaderTruncated(buffer, itemHeaderStart);
13284
+ throw sqItemHeaderTruncated(ctx.frame, itemHeaderStart);
13247
13285
  }
13248
13286
  throw err;
13249
13287
  }
@@ -13252,7 +13290,7 @@ function parseSequence(buffer, valueStart, ctx, emit, opts) {
13252
13290
  return { items, endOffset: cursor.position };
13253
13291
  }
13254
13292
  if (itemTag !== ITEM_TAG) {
13255
- throw unexpectedTagInsideSequence(buffer, itemHeaderStart);
13293
+ throw unexpectedTagInsideSequence(ctx.frame, itemHeaderStart);
13256
13294
  }
13257
13295
  if (itemLength === 0) {
13258
13296
  emit(emptyItemInSequence({ byteOffset: itemHeaderStart }, itemTag));
@@ -13268,7 +13306,7 @@ function parseSequence(buffer, valueStart, ctx, emit, opts) {
13268
13306
  }
13269
13307
  if (opts.encapsulatedPixelData === true) {
13270
13308
  if (cursor.position + itemLength > buffer.length) {
13271
- throw encapsulatedFragmentExceedsBuffer(buffer, itemHeaderStart);
13309
+ throw encapsulatedFragmentExceedsBuffer(ctx.frame, itemHeaderStart);
13272
13310
  }
13273
13311
  cursor.position += itemLength;
13274
13312
  items.push(new Item({ warnings: [], elements: /* @__PURE__ */ new Map(), index: itemIndex }));
@@ -13288,16 +13326,16 @@ function parseSequence(buffer, valueStart, ctx, emit, opts) {
13288
13326
  emit(itemCrossesSequenceEnd({ byteOffset: itemHeaderStart }, itemTag));
13289
13327
  }
13290
13328
  if (cursor.position + itemLength > buffer.length) {
13291
- throw itemLengthExceedsBuffer(buffer, itemHeaderStart);
13329
+ throw itemLengthExceedsBuffer(ctx.frame, itemHeaderStart);
13292
13330
  }
13293
13331
  const itemSlice = buffer.subarray(cursor.position, cursor.position + itemLength);
13294
- const enclosingFrame = ctx.buffer;
13332
+ const enclosingFrame = ctx.frame;
13295
13333
  let inner;
13296
13334
  try {
13297
- ctx.buffer = itemSlice;
13335
+ ctx.frame = { buffer: itemSlice, name: OFFSET_FRAMES.VALUE_SLICE };
13298
13336
  inner = opts.innerStrategy(itemSlice, 0, ctx, emit);
13299
13337
  } finally {
13300
- ctx.buffer = enclosingFrame;
13338
+ ctx.frame = enclosingFrame;
13301
13339
  }
13302
13340
  items.push(new Item({ warnings: [], elements: inner.elements, index: itemIndex }));
13303
13341
  cursor.position += itemLength;
@@ -13322,17 +13360,17 @@ function tryParseDefinedLengthSQ(buffer, valueStart, valueLength, ctx, emit, imp
13322
13360
  const savedWarningsLen = ctx.warnings.length;
13323
13361
  try {
13324
13362
  const slice = buffer.subarray(valueStart, valueStart + valueLength);
13325
- const enclosingFrame = ctx.buffer;
13363
+ const enclosingFrame = ctx.frame;
13326
13364
  let result;
13327
13365
  try {
13328
- ctx.buffer = slice;
13366
+ ctx.frame = { buffer: slice, name: OFFSET_FRAMES.VALUE_SLICE };
13329
13367
  result = parseSequence(slice, 0, ctx, emit, {
13330
13368
  explicitLength: valueLength,
13331
13369
  littleEndian: true,
13332
13370
  innerStrategy: implicitLeInner
13333
13371
  });
13334
13372
  } finally {
13335
- ctx.buffer = enclosingFrame;
13373
+ ctx.frame = enclosingFrame;
13336
13374
  }
13337
13375
  return { success: true, items: result.items };
13338
13376
  } catch (err) {
@@ -13360,13 +13398,13 @@ function tryParseUnAsSQ(buffer, valueStart, valueLength, ctx, emit, implicitLeIn
13360
13398
  // CP-246: Implicit VR LE inner per D-30.
13361
13399
  innerStrategy: implicitLeInner
13362
13400
  };
13363
- const enclosingFrame = ctx.buffer;
13401
+ const enclosingFrame = ctx.frame;
13364
13402
  let result;
13365
13403
  try {
13366
- ctx.buffer = slice;
13404
+ ctx.frame = { buffer: slice, name: OFFSET_FRAMES.VALUE_SLICE };
13367
13405
  result = parseSequence(slice, 0, ctx, emit, opts);
13368
13406
  } finally {
13369
- ctx.buffer = enclosingFrame;
13407
+ ctx.frame = enclosingFrame;
13370
13408
  }
13371
13409
  emit(unParsedAsSQ({ byteOffset: valueStart }, tag));
13372
13410
  return {
@@ -13404,7 +13442,7 @@ function parseImplicitLE(buffer, datasetStart, ctx, emit, opts = {}) {
13404
13442
  length = cursor.readUInt32();
13405
13443
  } catch (err) {
13406
13444
  if (err instanceof RangeError) {
13407
- throw truncatedDatasetHeader(buffer, headerStart);
13445
+ throw truncatedDatasetHeader(ctx.frame, headerStart);
13408
13446
  }
13409
13447
  throw err;
13410
13448
  }
@@ -13413,7 +13451,7 @@ function parseImplicitLE(buffer, datasetStart, ctx, emit, opts = {}) {
13413
13451
  if (opts.stopOnItemDelim === true && tag === "FFFEE00D") {
13414
13452
  return { elements, endOffset: cursor.position };
13415
13453
  }
13416
- throw unexpectedFffeAtDatasetRoot(buffer, headerStart);
13454
+ throw unexpectedFffeAtDatasetRoot(ctx.frame, headerStart);
13417
13455
  }
13418
13456
  const position = { byteOffset: headerStart };
13419
13457
  const vr = resolveImplicitVR(tag, ctx, emit, position);
@@ -13480,10 +13518,10 @@ function parseImplicitLE(buffer, datasetStart, ctx, emit, opts = {}) {
13480
13518
  continue;
13481
13519
  }
13482
13520
  }
13483
- throw undefinedLengthOnNonSqImplicit(buffer, headerStart, vr);
13521
+ throw undefinedLengthOnNonSqImplicit(ctx.frame, headerStart, vr);
13484
13522
  }
13485
13523
  if (cursor.position + length > buffer.length) {
13486
- throw elementLengthExceedsBuffer(buffer, headerStart);
13524
+ throw elementLengthExceedsBuffer(ctx.frame, headerStart);
13487
13525
  }
13488
13526
  const valueStart = cursor.position;
13489
13527
  const valueEnd = valueStart + length;
@@ -13559,7 +13597,7 @@ function _parseExplicit(buffer, datasetStart, ctx, emit, mode, opts = {}) {
13559
13597
  peekGroup = cursor.readUInt16At(cursor.position);
13560
13598
  } catch (err) {
13561
13599
  if (err instanceof RangeError) {
13562
- throw truncatedDatasetHeader(buffer, headerStart);
13600
+ throw truncatedDatasetHeader(ctx.frame, headerStart);
13563
13601
  }
13564
13602
  throw err;
13565
13603
  }
@@ -13572,7 +13610,7 @@ function _parseExplicit(buffer, datasetStart, ctx, emit, mode, opts = {}) {
13572
13610
  cursor.readUInt32();
13573
13611
  } catch (err) {
13574
13612
  if (err instanceof RangeError) {
13575
- throw truncatedFffeHeader(buffer, headerStart);
13613
+ throw truncatedFffeHeader(ctx.frame, headerStart);
13576
13614
  }
13577
13615
  throw err;
13578
13616
  }
@@ -13580,14 +13618,14 @@ function _parseExplicit(buffer, datasetStart, ctx, emit, mode, opts = {}) {
13580
13618
  if (opts.stopOnItemDelim === true && fffeTag === "FFFEE00D") {
13581
13619
  return { elements, endOffset: cursor.position };
13582
13620
  }
13583
- throw unexpectedFffeAtDatasetLevel(buffer, headerStart);
13621
+ throw unexpectedFffeAtDatasetLevel(ctx.frame, headerStart);
13584
13622
  }
13585
13623
  let header;
13586
13624
  try {
13587
13625
  header = readExplicitElementHeader(cursor, ctx, emit);
13588
13626
  } catch (err) {
13589
13627
  if (err instanceof RangeError) {
13590
- throw truncatedExplicitVrHeader(buffer, headerStart);
13628
+ throw truncatedExplicitVrHeader(ctx.frame, headerStart);
13591
13629
  }
13592
13630
  throw err;
13593
13631
  }
@@ -13727,10 +13765,10 @@ function _parseExplicit(buffer, datasetStart, ctx, emit, mode, opts = {}) {
13727
13765
  continue;
13728
13766
  }
13729
13767
  if (length === UNDEFINED_LENGTH2) {
13730
- throw undefinedLengthOnNonSqExplicit(buffer, headerStart, vr);
13768
+ throw undefinedLengthOnNonSqExplicit(ctx.frame, headerStart, vr);
13731
13769
  }
13732
13770
  if (cursor.position + length > buffer.length) {
13733
- throw elementLengthExceedsBuffer(buffer, headerStart);
13771
+ throw elementLengthExceedsBuffer(ctx.frame, headerStart);
13734
13772
  }
13735
13773
  const valueStart = cursor.position;
13736
13774
  const valueEnd = valueStart + length;
@@ -13791,11 +13829,14 @@ function parseDeflatedLEWithCap(buffer, datasetStart, ctx, emit, maxInflatedByte
13791
13829
  const code = errAny.code;
13792
13830
  const message = errAny.message ?? String(err);
13793
13831
  if (code === "ERR_BUFFER_TOO_LARGE" || err instanceof RangeError && /maxOutputLength|too large/i.test(message)) {
13794
- throw inflatedPayloadExceedsCap(buffer, datasetStart, maxInflatedBytes);
13832
+ throw inflatedPayloadExceedsCap(ctx.frame, datasetStart, maxInflatedBytes);
13795
13833
  }
13796
- throw inflateFailed(buffer, datasetStart, code);
13834
+ throw inflateFailed(ctx.frame, datasetStart, code);
13797
13835
  }
13798
- const innerCtx = { ...ctx, buffer: inflated };
13836
+ const innerCtx = {
13837
+ ...ctx,
13838
+ frame: { buffer: inflated, name: OFFSET_FRAMES.INFLATED_DATASET }
13839
+ };
13799
13840
  const innerChokepoint = makeEmitter(innerCtx);
13800
13841
  const innerEmit = (w) => {
13801
13842
  const wrapped = {
@@ -13845,7 +13886,7 @@ function parseDicom(input, options = {}) {
13845
13886
  const tsUid = fileMeta.transferSyntaxUID;
13846
13887
  const strategy = TRANSFER_SYNTAX_PARSERS[tsUid];
13847
13888
  if (strategy === void 0) {
13848
- throw unsupportedTransferSyntax(buffer, fileMetaEnd, tsUid);
13889
+ throw unsupportedTransferSyntax(ctx.frame, fileMetaEnd, tsUid);
13849
13890
  }
13850
13891
  const { elements } = strategy(buffer, fileMetaEnd, ctx, emit);
13851
13892
  return new Dataset({ fileMeta, warnings: ctx.warnings, elements });
@@ -13863,7 +13904,9 @@ function normalizeInput(input) {
13863
13904
  }
13864
13905
  function buildContext(buffer, options, warnings) {
13865
13906
  const base = {
13866
- buffer,
13907
+ // The root frame. Every nested frame is entered from here by a swap that
13908
+ // moves the bytes and the name together; see `ParseFrame`.
13909
+ frame: { buffer, name: OFFSET_FRAMES.INPUT },
13867
13910
  strict: options.strict === true,
13868
13911
  stripPreamble: options.stripPreamble ?? "tolerate",
13869
13912
  warnings,
@@ -15913,6 +15956,7 @@ exports.Dictionary = dictionary_exports;
15913
15956
  exports.Element = Element;
15914
15957
  exports.FATAL_CODES = FATAL_CODES;
15915
15958
  exports.Item = Item;
15959
+ exports.OFFSET_FRAMES = OFFSET_FRAMES;
15916
15960
  exports.ProfileDefinitionError = ProfileDefinitionError;
15917
15961
  exports.SERIALIZE_ERROR_CODES = SERIALIZE_ERROR_CODES;
15918
15962
  exports.Sequence = Sequence;