@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/CHANGELOG.md +357 -0
- package/README.md +4 -2
- package/dist/index.cjs +163 -91
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +258 -121
- package/dist/index.d.ts +258 -121
- package/dist/index.mjs +163 -92
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -1
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.
|
|
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
|
-
|
|
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
|
|
11840
|
-
// four bytes are
|
|
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,
|
|
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(
|
|
11940
|
-
return at("NOT_DICOM_PART_10_REQUIRED",
|
|
11976
|
+
function notDicomPart10Required(frame, offset) {
|
|
11977
|
+
return at("NOT_DICOM_PART_10_REQUIRED", frame, offset);
|
|
11941
11978
|
}
|
|
11942
|
-
function notDicomPart10(
|
|
11943
|
-
return at("NOT_DICOM_PART_10",
|
|
11979
|
+
function notDicomPart10(frame, offset) {
|
|
11980
|
+
return at("NOT_DICOM_PART_10", frame, offset);
|
|
11944
11981
|
}
|
|
11945
|
-
function unsupportedTransferSyntax(
|
|
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
|
-
|
|
11987
|
+
frame.name,
|
|
11988
|
+
name.length > 0 ? name : buildSnippet(frame.buffer, offset),
|
|
11951
11989
|
{ ts }
|
|
11952
11990
|
);
|
|
11953
11991
|
}
|
|
11954
|
-
function fileMetaTruncated(
|
|
11955
|
-
return at("FILE_META_TRUNCATED",
|
|
11992
|
+
function fileMetaTruncated(frame, offset) {
|
|
11993
|
+
return at("FILE_META_TRUNCATED", frame, offset);
|
|
11956
11994
|
}
|
|
11957
|
-
function fileMetaGroupLengthOverruns(
|
|
11958
|
-
return at("FILE_META_GROUP_LENGTH_OVERRUNS",
|
|
11995
|
+
function fileMetaGroupLengthOverruns(frame, offset) {
|
|
11996
|
+
return at("FILE_META_GROUP_LENGTH_OVERRUNS", frame, offset);
|
|
11959
11997
|
}
|
|
11960
|
-
function fileMetaTransferSyntaxMissing(
|
|
11961
|
-
return at("FILE_META_TRANSFER_SYNTAX_MISSING",
|
|
11998
|
+
function fileMetaTransferSyntaxMissing(frame, offset) {
|
|
11999
|
+
return at("FILE_META_TRANSFER_SYNTAX_MISSING", frame, offset);
|
|
11962
12000
|
}
|
|
11963
|
-
function truncatedDatasetHeader(
|
|
11964
|
-
return at("TRUNCATED_DATASET_HEADER",
|
|
12001
|
+
function truncatedDatasetHeader(frame, offset) {
|
|
12002
|
+
return at("TRUNCATED_DATASET_HEADER", frame, offset);
|
|
11965
12003
|
}
|
|
11966
|
-
function truncatedFffeHeader(
|
|
11967
|
-
return at("TRUNCATED_FFFE_HEADER",
|
|
12004
|
+
function truncatedFffeHeader(frame, offset) {
|
|
12005
|
+
return at("TRUNCATED_FFFE_HEADER", frame, offset);
|
|
11968
12006
|
}
|
|
11969
|
-
function truncatedExplicitVrHeader(
|
|
11970
|
-
return at("TRUNCATED_EXPLICIT_VR_HEADER",
|
|
12007
|
+
function truncatedExplicitVrHeader(frame, offset) {
|
|
12008
|
+
return at("TRUNCATED_EXPLICIT_VR_HEADER", frame, offset);
|
|
11971
12009
|
}
|
|
11972
|
-
function sqItemHeaderTruncated(
|
|
11973
|
-
return at("SQ_ITEM_HEADER_TRUNCATED",
|
|
12010
|
+
function sqItemHeaderTruncated(frame, offset) {
|
|
12011
|
+
return at("SQ_ITEM_HEADER_TRUNCATED", frame, offset);
|
|
11974
12012
|
}
|
|
11975
|
-
function unexpectedFffeAtDatasetLevel(
|
|
11976
|
-
return at("UNEXPECTED_FFFE_AT_DATASET_LEVEL",
|
|
12013
|
+
function unexpectedFffeAtDatasetLevel(frame, offset) {
|
|
12014
|
+
return at("UNEXPECTED_FFFE_AT_DATASET_LEVEL", frame, offset);
|
|
11977
12015
|
}
|
|
11978
|
-
function unexpectedFffeAtDatasetRoot(
|
|
11979
|
-
return at("UNEXPECTED_FFFE_AT_DATASET_ROOT",
|
|
12016
|
+
function unexpectedFffeAtDatasetRoot(frame, offset) {
|
|
12017
|
+
return at("UNEXPECTED_FFFE_AT_DATASET_ROOT", frame, offset);
|
|
11980
12018
|
}
|
|
11981
|
-
function undefinedLengthOnNonSqExplicit(
|
|
11982
|
-
return at("UNDEFINED_LENGTH_ON_NON_SQ_EXPLICIT",
|
|
12019
|
+
function undefinedLengthOnNonSqExplicit(frame, offset, vr) {
|
|
12020
|
+
return at("UNDEFINED_LENGTH_ON_NON_SQ_EXPLICIT", frame, offset, { vr });
|
|
11983
12021
|
}
|
|
11984
|
-
function undefinedLengthOnNonSqImplicit(
|
|
11985
|
-
return at("UNDEFINED_LENGTH_ON_NON_SQ_IMPLICIT",
|
|
12022
|
+
function undefinedLengthOnNonSqImplicit(frame, offset, vr) {
|
|
12023
|
+
return at("UNDEFINED_LENGTH_ON_NON_SQ_IMPLICIT", frame, offset, { vr });
|
|
11986
12024
|
}
|
|
11987
|
-
function elementLengthExceedsBuffer(
|
|
11988
|
-
return at("ELEMENT_LENGTH_EXCEEDS_BUFFER",
|
|
12025
|
+
function elementLengthExceedsBuffer(frame, offset) {
|
|
12026
|
+
return at("ELEMENT_LENGTH_EXCEEDS_BUFFER", frame, offset);
|
|
11989
12027
|
}
|
|
11990
|
-
function unexpectedTagInsideSequence(
|
|
11991
|
-
return at("UNEXPECTED_TAG_INSIDE_SEQUENCE",
|
|
12028
|
+
function unexpectedTagInsideSequence(frame, offset) {
|
|
12029
|
+
return at("UNEXPECTED_TAG_INSIDE_SEQUENCE", frame, offset);
|
|
11992
12030
|
}
|
|
11993
|
-
function encapsulatedFragmentExceedsBuffer(
|
|
11994
|
-
return at("ENCAPSULATED_FRAGMENT_EXCEEDS_BUFFER",
|
|
12031
|
+
function encapsulatedFragmentExceedsBuffer(frame, offset) {
|
|
12032
|
+
return at("ENCAPSULATED_FRAGMENT_EXCEEDS_BUFFER", frame, offset);
|
|
11995
12033
|
}
|
|
11996
|
-
function itemLengthExceedsBuffer(
|
|
11997
|
-
return at("ITEM_LENGTH_EXCEEDS_BUFFER",
|
|
12034
|
+
function itemLengthExceedsBuffer(frame, offset) {
|
|
12035
|
+
return at("ITEM_LENGTH_EXCEEDS_BUFFER", frame, offset);
|
|
11998
12036
|
}
|
|
11999
|
-
function sqNestingDepthExceeded(
|
|
12000
|
-
return at("SQ_NESTING_DEPTH_EXCEEDED",
|
|
12037
|
+
function sqNestingDepthExceeded(frame, offset, limit) {
|
|
12038
|
+
return at("SQ_NESTING_DEPTH_EXCEEDED", frame, offset, { n: limit });
|
|
12001
12039
|
}
|
|
12002
|
-
function inflatedPayloadExceedsCap(
|
|
12003
|
-
return at("INFLATED_PAYLOAD_EXCEEDS_CAP",
|
|
12040
|
+
function inflatedPayloadExceedsCap(frame, offset, cap) {
|
|
12041
|
+
return at("INFLATED_PAYLOAD_EXCEEDS_CAP", frame, offset, { n: cap });
|
|
12004
12042
|
}
|
|
12005
|
-
function inflateFailed(
|
|
12006
|
-
return at("INFLATE_FAILED",
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
13329
|
+
throw itemLengthExceedsBuffer(ctx.frame, itemHeaderStart);
|
|
13273
13330
|
}
|
|
13274
13331
|
const itemSlice = buffer.subarray(cursor.position, cursor.position + itemLength);
|
|
13275
|
-
const enclosingFrame = ctx.
|
|
13332
|
+
const enclosingFrame = ctx.frame;
|
|
13276
13333
|
let inner;
|
|
13277
13334
|
try {
|
|
13278
|
-
ctx.
|
|
13335
|
+
ctx.frame = { buffer: itemSlice, name: OFFSET_FRAMES.VALUE_SLICE };
|
|
13279
13336
|
inner = opts.innerStrategy(itemSlice, 0, ctx, emit);
|
|
13280
13337
|
} finally {
|
|
13281
|
-
ctx.
|
|
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.
|
|
13363
|
+
const enclosingFrame = ctx.frame;
|
|
13307
13364
|
let result;
|
|
13308
13365
|
try {
|
|
13309
|
-
ctx.
|
|
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.
|
|
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.
|
|
13401
|
+
const enclosingFrame = ctx.frame;
|
|
13345
13402
|
let result;
|
|
13346
13403
|
try {
|
|
13347
|
-
ctx.
|
|
13404
|
+
ctx.frame = { buffer: slice, name: OFFSET_FRAMES.VALUE_SLICE };
|
|
13348
13405
|
result = parseSequence(slice, 0, ctx, emit, opts);
|
|
13349
13406
|
} finally {
|
|
13350
|
-
ctx.
|
|
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(
|
|
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(
|
|
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(
|
|
13521
|
+
throw undefinedLengthOnNonSqImplicit(ctx.frame, headerStart, vr);
|
|
13465
13522
|
}
|
|
13466
13523
|
if (cursor.position + length > buffer.length) {
|
|
13467
|
-
throw elementLengthExceedsBuffer(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
13768
|
+
throw undefinedLengthOnNonSqExplicit(ctx.frame, headerStart, vr);
|
|
13712
13769
|
}
|
|
13713
13770
|
if (cursor.position + length > buffer.length) {
|
|
13714
|
-
throw elementLengthExceedsBuffer(
|
|
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(
|
|
13832
|
+
throw inflatedPayloadExceedsCap(ctx.frame, datasetStart, maxInflatedBytes);
|
|
13776
13833
|
}
|
|
13777
|
-
throw inflateFailed(
|
|
13834
|
+
throw inflateFailed(ctx.frame, datasetStart, code);
|
|
13778
13835
|
}
|
|
13779
|
-
const innerCtx = {
|
|
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(
|
|
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
|
-
|
|
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;
|