@cosyte/dicom 0.0.16 → 0.0.18

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.16";
14
+ var VERSION = "0.0.18";
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);
@@ -12199,6 +12237,8 @@ var WARNING_CODES = {
12199
12237
  // emitted by deidentify(), never by the parser
12200
12238
  DICOM_DEIDENT_METHOD_PRIOR_RETAINED: "DICOM_DEIDENT_METHOD_PRIOR_RETAINED",
12201
12239
  // emitted by deidentify(), never by the parser
12240
+ DICOM_DEIDENT_METHOD_VALUE_OVER_LENGTH: "DICOM_DEIDENT_METHOD_VALUE_OVER_LENGTH",
12241
+ // emitted by deidentify(), never by the parser
12202
12242
  DICOM_DEIDENT_SEQUENCE_NOT_AUDITABLE: "DICOM_DEIDENT_SEQUENCE_NOT_AUDITABLE",
12203
12243
  // emitted by deidentify(), never by the parser
12204
12244
  DICOM_DEIDENT_UNDEFINED_VR_NOT_AUDITABLE: "DICOM_DEIDENT_UNDEFINED_VR_NOT_AUDITABLE",
@@ -12277,6 +12317,20 @@ var WARNING_MESSAGES = Object.freeze({
12277
12317
  // No value and no length, for the same reason as the code above: the retained
12278
12318
  // text is the file's own. The tag is a constant of this code.
12279
12319
  DICOM_DEIDENT_METHOD_PRIOR_RETAINED: "A De-identification Method (0012,0063) value the source file already carried was kept beside the one this run recorded, as PS3.15 E.1.1 requires. That attribute is not in Table E.1-1, so no rule in this run inspected, audited or redacted those bytes: if the sender wrote identifying text there it is in the de-identified output, under (0012,0062) = YES. The text is withheld from this message.",
12320
+ // No value, no length, no count AND NO ORIGIN. 64 is a constant of the VR, not
12321
+ // a measurement over input; the offending Value's own length IS a measurement
12322
+ // over input and is the number DICOM-DIAGNOSTIC-PHI-RESIDUALS bound out of six
12323
+ // other messages. How many Values are over is the same kind of number, and
12324
+ // which one of them the caller supplied versus which the file did is not
12325
+ // decidable when the two are equal.
12326
+ //
12327
+ // 🛑 AND IT SAYS "LONGER THAN 64 BYTES", NOT "OVER THE MAXIMUM". A graded pass
12328
+ // refuted the draft that called 64 bytes "the largest an LO Value may be under
12329
+ // a single-byte repertoire": PS3.5 6.2 specifies these lengths "in characters
12330
+ // rather than bytes" and excludes Code Extension escape sequences from the
12331
+ // count, so a conformant 64-character Value can exceed 64 bytes under a
12332
+ // single-byte repertoire too. The message states what was measured.
12333
+ DICOM_DEIDENT_METHOD_VALUE_OVER_LENGTH: "The De-identification Method (0012,0063) this run wrote carries a Value longer than 64 bytes. PS3.5 Table 6.2-1 bounds an LO Value at 64 characters, per Value and not per Value Field, and PS3.5 6.2 specifies that length in characters rather than bytes and excludes Code Extension escape sequences from the count: a Value of 64 bytes or fewer can never carry more than 64 characters, but a longer one is not necessarily over the maximum. This run never shortens, splits or truncates a Value it did not compose: a caller-supplied method, and a value the source file already carried, are both written through as given. A receiver that enforces the VR may reject the attribute that records the de-identification. The value, its length, how many Values are over and which of them came from where are all withheld from this message.",
12280
12334
  // BOTH of the disagreeing length fields are deliberately absent, and the
12281
12335
  // second one is the eighth instance of `DICOM-DIAGNOSTIC-PHI-RESIDUALS`: the
12282
12336
  // remaining-bytes count this string used to carry was the enclosing sequence's
@@ -12405,6 +12459,9 @@ function deidentMethodNotLo(position) {
12405
12459
  function deidentMethodPriorRetained(position) {
12406
12460
  return build2(WARNING_CODES.DICOM_DEIDENT_METHOD_PRIOR_RETAINED, position);
12407
12461
  }
12462
+ function deidentMethodValueOverLength(position) {
12463
+ return build2(WARNING_CODES.DICOM_DEIDENT_METHOD_VALUE_OVER_LENGTH, position);
12464
+ }
12408
12465
  function embeddedAttributeRemoved(position, tag, vr, count) {
12409
12466
  return build2(WARNING_CODES.DICOM_DEIDENT_EMBEDDED_ATTRIBUTE_REMOVED, position, {
12410
12467
  tag,
@@ -12617,7 +12674,7 @@ function parseFileMeta(buffer$1, datasetStart, ctx, emit) {
12617
12674
  firstElement = readExplicitLeElement(cursor);
12618
12675
  } catch (err) {
12619
12676
  if (err instanceof RangeError) {
12620
- throw fileMetaTruncated(buffer$1, fmStart);
12677
+ throw fileMetaTruncated(ctx.frame, fmStart);
12621
12678
  }
12622
12679
  throw err;
12623
12680
  }
@@ -12627,7 +12684,7 @@ function parseFileMeta(buffer$1, datasetStart, ctx, emit) {
12627
12684
  if (firstElement.tag === "00020000" && firstElement.vr === "UL" && firstElement.value.length === 4) {
12628
12685
  declaredFmLength = firstElement.value.readUInt32LE(0);
12629
12686
  if (cursor.position + declaredFmLength > buffer$1.length) {
12630
- throw fileMetaGroupLengthOverruns(buffer$1, fmStart);
12687
+ throw fileMetaGroupLengthOverruns(ctx.frame, fmStart);
12631
12688
  }
12632
12689
  } else {
12633
12690
  emit(fileMetaGroupLengthMissing({ byteOffset: fmStart, fileMeta: true }));
@@ -12644,7 +12701,7 @@ function parseFileMeta(buffer$1, datasetStart, ctx, emit) {
12644
12701
  next = readExplicitLeElement(cursor);
12645
12702
  } catch (err) {
12646
12703
  if (err instanceof RangeError) {
12647
- throw fileMetaTruncated(buffer$1, fmStart);
12704
+ throw fileMetaTruncated(ctx.frame, fmStart);
12648
12705
  }
12649
12706
  throw err;
12650
12707
  }
@@ -12668,7 +12725,7 @@ function parseFileMeta(buffer$1, datasetStart, ctx, emit) {
12668
12725
  next = readExplicitLeElement(cursor);
12669
12726
  } catch (err) {
12670
12727
  if (err instanceof RangeError) {
12671
- throw fileMetaTruncated(buffer$1, fmStart);
12728
+ throw fileMetaTruncated(ctx.frame, fmStart);
12672
12729
  }
12673
12730
  throw err;
12674
12731
  }
@@ -12687,7 +12744,7 @@ function parseFileMeta(buffer$1, datasetStart, ctx, emit) {
12687
12744
  }
12688
12745
  const tsElement = fmElements.find((e) => e.tag === "00020010");
12689
12746
  if (tsElement === void 0 || tsElement.vr !== "UI") {
12690
- throw fileMetaTransferSyntaxMissing(buffer$1, fmStart);
12747
+ throw fileMetaTransferSyntaxMissing(ctx.frame, fmStart);
12691
12748
  }
12692
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) }));
12693
12750
  const fileMeta = {
@@ -12771,13 +12828,13 @@ function parsePart10Header(buffer, ctx, emit) {
12771
12828
  return { datasetStart: 132, hadPreamble: true };
12772
12829
  }
12773
12830
  if (ctx.stripPreamble === "require") {
12774
- throw notDicomPart10Required(buffer, 0);
12831
+ throw notDicomPart10Required(ctx.frame, 0);
12775
12832
  }
12776
12833
  if (looksLikeFileMetaGroupLengthAtOffsetZero(buffer)) {
12777
12834
  emit(missingPreamble({ byteOffset: 0 }));
12778
12835
  return { datasetStart: 0, hadPreamble: false };
12779
12836
  }
12780
- throw notDicomPart10(buffer, 0);
12837
+ throw notDicomPart10(ctx.frame, 0);
12781
12838
  }
12782
12839
  function looksLikeFileMetaGroupLengthAtOffsetZero(buffer) {
12783
12840
  if (buffer.length < 12) return false;
@@ -13188,7 +13245,7 @@ function parseSequence(buffer, valueStart, ctx, emit, opts) {
13188
13245
  ctx.nestingDepth += 1;
13189
13246
  if (ctx.nestingDepth > NESTING_DEPTH_LIMIT) {
13190
13247
  ctx.nestingDepth -= 1;
13191
- throw sqNestingDepthExceeded(buffer, valueStart, NESTING_DEPTH_LIMIT);
13248
+ throw sqNestingDepthExceeded(ctx.frame, valueStart, NESTING_DEPTH_LIMIT);
13192
13249
  }
13193
13250
  ctx.encodingContextStack.push(
13194
13251
  opts.encapsulatedPixelData === true ? "EncapsulatedPixelData" : "SqItem"
@@ -13224,7 +13281,7 @@ function parseSequence(buffer, valueStart, ctx, emit, opts) {
13224
13281
  itemLength = cursor.readUInt32();
13225
13282
  } catch (err) {
13226
13283
  if (err instanceof RangeError) {
13227
- throw sqItemHeaderTruncated(buffer, itemHeaderStart);
13284
+ throw sqItemHeaderTruncated(ctx.frame, itemHeaderStart);
13228
13285
  }
13229
13286
  throw err;
13230
13287
  }
@@ -13233,7 +13290,7 @@ function parseSequence(buffer, valueStart, ctx, emit, opts) {
13233
13290
  return { items, endOffset: cursor.position };
13234
13291
  }
13235
13292
  if (itemTag !== ITEM_TAG) {
13236
- throw unexpectedTagInsideSequence(buffer, itemHeaderStart);
13293
+ throw unexpectedTagInsideSequence(ctx.frame, itemHeaderStart);
13237
13294
  }
13238
13295
  if (itemLength === 0) {
13239
13296
  emit(emptyItemInSequence({ byteOffset: itemHeaderStart }, itemTag));
@@ -13249,7 +13306,7 @@ function parseSequence(buffer, valueStart, ctx, emit, opts) {
13249
13306
  }
13250
13307
  if (opts.encapsulatedPixelData === true) {
13251
13308
  if (cursor.position + itemLength > buffer.length) {
13252
- throw encapsulatedFragmentExceedsBuffer(buffer, itemHeaderStart);
13309
+ throw encapsulatedFragmentExceedsBuffer(ctx.frame, itemHeaderStart);
13253
13310
  }
13254
13311
  cursor.position += itemLength;
13255
13312
  items.push(new Item({ warnings: [], elements: /* @__PURE__ */ new Map(), index: itemIndex }));
@@ -13269,16 +13326,16 @@ function parseSequence(buffer, valueStart, ctx, emit, opts) {
13269
13326
  emit(itemCrossesSequenceEnd({ byteOffset: itemHeaderStart }, itemTag));
13270
13327
  }
13271
13328
  if (cursor.position + itemLength > buffer.length) {
13272
- throw itemLengthExceedsBuffer(buffer, itemHeaderStart);
13329
+ throw itemLengthExceedsBuffer(ctx.frame, itemHeaderStart);
13273
13330
  }
13274
13331
  const itemSlice = buffer.subarray(cursor.position, cursor.position + itemLength);
13275
- const enclosingFrame = ctx.buffer;
13332
+ const enclosingFrame = ctx.frame;
13276
13333
  let inner;
13277
13334
  try {
13278
- ctx.buffer = itemSlice;
13335
+ ctx.frame = { buffer: itemSlice, name: OFFSET_FRAMES.VALUE_SLICE };
13279
13336
  inner = opts.innerStrategy(itemSlice, 0, ctx, emit);
13280
13337
  } finally {
13281
- ctx.buffer = enclosingFrame;
13338
+ ctx.frame = enclosingFrame;
13282
13339
  }
13283
13340
  items.push(new Item({ warnings: [], elements: inner.elements, index: itemIndex }));
13284
13341
  cursor.position += itemLength;
@@ -13303,17 +13360,17 @@ function tryParseDefinedLengthSQ(buffer, valueStart, valueLength, ctx, emit, imp
13303
13360
  const savedWarningsLen = ctx.warnings.length;
13304
13361
  try {
13305
13362
  const slice = buffer.subarray(valueStart, valueStart + valueLength);
13306
- const enclosingFrame = ctx.buffer;
13363
+ const enclosingFrame = ctx.frame;
13307
13364
  let result;
13308
13365
  try {
13309
- ctx.buffer = slice;
13366
+ ctx.frame = { buffer: slice, name: OFFSET_FRAMES.VALUE_SLICE };
13310
13367
  result = parseSequence(slice, 0, ctx, emit, {
13311
13368
  explicitLength: valueLength,
13312
13369
  littleEndian: true,
13313
13370
  innerStrategy: implicitLeInner
13314
13371
  });
13315
13372
  } finally {
13316
- ctx.buffer = enclosingFrame;
13373
+ ctx.frame = enclosingFrame;
13317
13374
  }
13318
13375
  return { success: true, items: result.items };
13319
13376
  } catch (err) {
@@ -13341,13 +13398,13 @@ function tryParseUnAsSQ(buffer, valueStart, valueLength, ctx, emit, implicitLeIn
13341
13398
  // CP-246: Implicit VR LE inner per D-30.
13342
13399
  innerStrategy: implicitLeInner
13343
13400
  };
13344
- const enclosingFrame = ctx.buffer;
13401
+ const enclosingFrame = ctx.frame;
13345
13402
  let result;
13346
13403
  try {
13347
- ctx.buffer = slice;
13404
+ ctx.frame = { buffer: slice, name: OFFSET_FRAMES.VALUE_SLICE };
13348
13405
  result = parseSequence(slice, 0, ctx, emit, opts);
13349
13406
  } finally {
13350
- ctx.buffer = enclosingFrame;
13407
+ ctx.frame = enclosingFrame;
13351
13408
  }
13352
13409
  emit(unParsedAsSQ({ byteOffset: valueStart }, tag));
13353
13410
  return {
@@ -13385,7 +13442,7 @@ function parseImplicitLE(buffer, datasetStart, ctx, emit, opts = {}) {
13385
13442
  length = cursor.readUInt32();
13386
13443
  } catch (err) {
13387
13444
  if (err instanceof RangeError) {
13388
- throw truncatedDatasetHeader(buffer, headerStart);
13445
+ throw truncatedDatasetHeader(ctx.frame, headerStart);
13389
13446
  }
13390
13447
  throw err;
13391
13448
  }
@@ -13394,7 +13451,7 @@ function parseImplicitLE(buffer, datasetStart, ctx, emit, opts = {}) {
13394
13451
  if (opts.stopOnItemDelim === true && tag === "FFFEE00D") {
13395
13452
  return { elements, endOffset: cursor.position };
13396
13453
  }
13397
- throw unexpectedFffeAtDatasetRoot(buffer, headerStart);
13454
+ throw unexpectedFffeAtDatasetRoot(ctx.frame, headerStart);
13398
13455
  }
13399
13456
  const position = { byteOffset: headerStart };
13400
13457
  const vr = resolveImplicitVR(tag, ctx, emit, position);
@@ -13461,10 +13518,10 @@ function parseImplicitLE(buffer, datasetStart, ctx, emit, opts = {}) {
13461
13518
  continue;
13462
13519
  }
13463
13520
  }
13464
- throw undefinedLengthOnNonSqImplicit(buffer, headerStart, vr);
13521
+ throw undefinedLengthOnNonSqImplicit(ctx.frame, headerStart, vr);
13465
13522
  }
13466
13523
  if (cursor.position + length > buffer.length) {
13467
- throw elementLengthExceedsBuffer(buffer, headerStart);
13524
+ throw elementLengthExceedsBuffer(ctx.frame, headerStart);
13468
13525
  }
13469
13526
  const valueStart = cursor.position;
13470
13527
  const valueEnd = valueStart + length;
@@ -13540,7 +13597,7 @@ function _parseExplicit(buffer, datasetStart, ctx, emit, mode, opts = {}) {
13540
13597
  peekGroup = cursor.readUInt16At(cursor.position);
13541
13598
  } catch (err) {
13542
13599
  if (err instanceof RangeError) {
13543
- throw truncatedDatasetHeader(buffer, headerStart);
13600
+ throw truncatedDatasetHeader(ctx.frame, headerStart);
13544
13601
  }
13545
13602
  throw err;
13546
13603
  }
@@ -13553,7 +13610,7 @@ function _parseExplicit(buffer, datasetStart, ctx, emit, mode, opts = {}) {
13553
13610
  cursor.readUInt32();
13554
13611
  } catch (err) {
13555
13612
  if (err instanceof RangeError) {
13556
- throw truncatedFffeHeader(buffer, headerStart);
13613
+ throw truncatedFffeHeader(ctx.frame, headerStart);
13557
13614
  }
13558
13615
  throw err;
13559
13616
  }
@@ -13561,14 +13618,14 @@ function _parseExplicit(buffer, datasetStart, ctx, emit, mode, opts = {}) {
13561
13618
  if (opts.stopOnItemDelim === true && fffeTag === "FFFEE00D") {
13562
13619
  return { elements, endOffset: cursor.position };
13563
13620
  }
13564
- throw unexpectedFffeAtDatasetLevel(buffer, headerStart);
13621
+ throw unexpectedFffeAtDatasetLevel(ctx.frame, headerStart);
13565
13622
  }
13566
13623
  let header;
13567
13624
  try {
13568
13625
  header = readExplicitElementHeader(cursor, ctx, emit);
13569
13626
  } catch (err) {
13570
13627
  if (err instanceof RangeError) {
13571
- throw truncatedExplicitVrHeader(buffer, headerStart);
13628
+ throw truncatedExplicitVrHeader(ctx.frame, headerStart);
13572
13629
  }
13573
13630
  throw err;
13574
13631
  }
@@ -13708,10 +13765,10 @@ function _parseExplicit(buffer, datasetStart, ctx, emit, mode, opts = {}) {
13708
13765
  continue;
13709
13766
  }
13710
13767
  if (length === UNDEFINED_LENGTH2) {
13711
- throw undefinedLengthOnNonSqExplicit(buffer, headerStart, vr);
13768
+ throw undefinedLengthOnNonSqExplicit(ctx.frame, headerStart, vr);
13712
13769
  }
13713
13770
  if (cursor.position + length > buffer.length) {
13714
- throw elementLengthExceedsBuffer(buffer, headerStart);
13771
+ throw elementLengthExceedsBuffer(ctx.frame, headerStart);
13715
13772
  }
13716
13773
  const valueStart = cursor.position;
13717
13774
  const valueEnd = valueStart + length;
@@ -13772,11 +13829,14 @@ function parseDeflatedLEWithCap(buffer, datasetStart, ctx, emit, maxInflatedByte
13772
13829
  const code = errAny.code;
13773
13830
  const message = errAny.message ?? String(err);
13774
13831
  if (code === "ERR_BUFFER_TOO_LARGE" || err instanceof RangeError && /maxOutputLength|too large/i.test(message)) {
13775
- throw inflatedPayloadExceedsCap(buffer, datasetStart, maxInflatedBytes);
13832
+ throw inflatedPayloadExceedsCap(ctx.frame, datasetStart, maxInflatedBytes);
13776
13833
  }
13777
- throw inflateFailed(buffer, datasetStart, code);
13834
+ throw inflateFailed(ctx.frame, datasetStart, code);
13778
13835
  }
13779
- const innerCtx = { ...ctx, buffer: inflated };
13836
+ const innerCtx = {
13837
+ ...ctx,
13838
+ frame: { buffer: inflated, name: OFFSET_FRAMES.INFLATED_DATASET }
13839
+ };
13780
13840
  const innerChokepoint = makeEmitter(innerCtx);
13781
13841
  const innerEmit = (w) => {
13782
13842
  const wrapped = {
@@ -13826,7 +13886,7 @@ function parseDicom(input, options = {}) {
13826
13886
  const tsUid = fileMeta.transferSyntaxUID;
13827
13887
  const strategy = TRANSFER_SYNTAX_PARSERS[tsUid];
13828
13888
  if (strategy === void 0) {
13829
- throw unsupportedTransferSyntax(buffer, fileMetaEnd, tsUid);
13889
+ throw unsupportedTransferSyntax(ctx.frame, fileMetaEnd, tsUid);
13830
13890
  }
13831
13891
  const { elements } = strategy(buffer, fileMetaEnd, ctx, emit);
13832
13892
  return new Dataset({ fileMeta, warnings: ctx.warnings, elements });
@@ -13844,7 +13904,9 @@ function normalizeInput(input) {
13844
13904
  }
13845
13905
  function buildContext(buffer, options, warnings) {
13846
13906
  const base = {
13847
- 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 },
13848
13910
  strict: options.strict === true,
13849
13911
  stripPreamble: options.stripPreamble ?? "tolerate",
13850
13912
  warnings,
@@ -15751,6 +15813,10 @@ function defaultMethod(active) {
15751
15813
  }
15752
15814
  var VALUE_DELIMITER = 92;
15753
15815
  var MAX_SHORT_FORM_VALUE_BYTES = 65534;
15816
+ var LO_VALUE_MAX_CHARS = 64;
15817
+ function hasValueOverLoMaximum(field) {
15818
+ return splitValues(field).some((value) => value.length > LO_VALUE_MAX_CHARS);
15819
+ }
15754
15820
  function addDeidentificationMethod(existing, method) {
15755
15821
  const added = trimTrailingPad(buffer.Buffer.from(method, "latin1"));
15756
15822
  const none = { replacedPrior: false, retainedPrior: false, replacedNonLoPrior: false };
@@ -15848,6 +15914,11 @@ function deidentify(ds, options = {}) {
15848
15914
  deidentMethodNotLo({ byteOffset: priorMethod?.byteOffset ?? 0, fileMeta: false })
15849
15915
  );
15850
15916
  }
15917
+ if (hasValueOverLoMaximum(deidentMethod.value)) {
15918
+ warnings.push(
15919
+ deidentMethodValueOverLength({ byteOffset: priorMethod?.byteOffset ?? 0, fileMeta: false })
15920
+ );
15921
+ }
15851
15922
  if (hasUncleanedBurnedIn(ds)) {
15852
15923
  const offset = ds.get(TAG_PIXEL_DATA)?.byteOffset ?? 0;
15853
15924
  warnings.push(burnedInAnnotationNotRemoved({ byteOffset: offset, fileMeta: false }));
@@ -15885,6 +15956,7 @@ exports.Dictionary = dictionary_exports;
15885
15956
  exports.Element = Element;
15886
15957
  exports.FATAL_CODES = FATAL_CODES;
15887
15958
  exports.Item = Item;
15959
+ exports.OFFSET_FRAMES = OFFSET_FRAMES;
15888
15960
  exports.ProfileDefinitionError = ProfileDefinitionError;
15889
15961
  exports.SERIALIZE_ERROR_CODES = SERIALIZE_ERROR_CODES;
15890
15962
  exports.Sequence = Sequence;