@cosyte/dicom 0.0.15 → 0.0.17

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.d.cts CHANGED
@@ -491,6 +491,7 @@ declare const WARNING_CODES: {
491
491
  readonly DICOM_DEIDENT_METHOD_NOT_ADDED: "DICOM_DEIDENT_METHOD_NOT_ADDED";
492
492
  readonly DICOM_DEIDENT_METHOD_NOT_LO: "DICOM_DEIDENT_METHOD_NOT_LO";
493
493
  readonly DICOM_DEIDENT_METHOD_PRIOR_RETAINED: "DICOM_DEIDENT_METHOD_PRIOR_RETAINED";
494
+ readonly DICOM_DEIDENT_METHOD_VALUE_OVER_LENGTH: "DICOM_DEIDENT_METHOD_VALUE_OVER_LENGTH";
494
495
  readonly DICOM_DEIDENT_SEQUENCE_NOT_AUDITABLE: "DICOM_DEIDENT_SEQUENCE_NOT_AUDITABLE";
495
496
  readonly DICOM_DEIDENT_UNDEFINED_VR_NOT_AUDITABLE: "DICOM_DEIDENT_UNDEFINED_VR_NOT_AUDITABLE";
496
497
  readonly DICOM_PRIVATE_CREATOR_UNKNOWN: "DICOM_PRIVATE_CREATOR_UNKNOWN";
@@ -2974,10 +2975,19 @@ interface DeidentifyOptions {
2974
2975
  * legally carry. The Profile name is now one Value of 61 characters and each
2975
2976
  * active option is its own, so no option subset can exceed the maximum.
2976
2977
  *
2977
- * **Your string is not bounded here.** A value of your own longer than 64
2978
- * characters is written through as given, with no warning: it is yours, and
2979
- * splitting or truncating it would invent a record you did not write. Split it
2980
- * on `\` yourself if a strict receiver is in your path.
2978
+ * **Your string is not bounded here, but it is no longer silent.** A value of
2979
+ * your own longer than 64 characters is written through as given - it is
2980
+ * yours, and splitting or truncating it would invent a record you did not
2981
+ * write - and `report.warnings` carries
2982
+ * `DICOM_DEIDENT_METHOD_VALUE_OVER_LENGTH` to say so. Split it on `\` yourself
2983
+ * if a strict receiver is in your path. The same code covers an over-long
2984
+ * value the **source file** wrote and this run kept, which in the common case
2985
+ * is this library's own 76-character text from a release before the default
2986
+ * became multi-valued. The measurement is over **bytes**: a Value of 64 bytes
2987
+ * or fewer can never carry more than 64 characters, so it cannot miss one that
2988
+ * is genuinely over, but PS3.5 §6.2 specifies the bound in characters rather
2989
+ * than bytes and excludes Code Extension escape sequences from the count, so it
2990
+ * raises on any conformant Value whose bytes outnumber its counted characters.
2981
2991
  *
2982
2992
  * PS3.15 E.1.1 says this string is "inserted in or added to" the attribute, so
2983
2993
  * a value the incoming Data Set already carried is kept and this one is
@@ -3016,7 +3026,9 @@ interface DeidentifyOptions {
3016
3026
  * When the prior value **is** kept, `report.warnings` carries
3017
3027
  * `DICOM_DEIDENT_METHOD_PRIOR_RETAINED`: `(0012,0063)` is not in Table E.1-1, so
3018
3028
  * nothing in the run inspected or redacted those bytes, and a name a sender
3019
- * wrote there is in output stamped `(0012,0062) = YES`.
3029
+ * wrote there is in output stamped `(0012,0062) = YES`. That code discloses the
3030
+ * **retention** only; the **length** of what is written, from whatever source,
3031
+ * is disclosed by `DICOM_DEIDENT_METHOD_VALUE_OVER_LENGTH` and by nothing else.
3020
3032
  */
3021
3033
  readonly deidentificationMethod?: string;
3022
3034
  }
package/dist/index.d.ts CHANGED
@@ -491,6 +491,7 @@ declare const WARNING_CODES: {
491
491
  readonly DICOM_DEIDENT_METHOD_NOT_ADDED: "DICOM_DEIDENT_METHOD_NOT_ADDED";
492
492
  readonly DICOM_DEIDENT_METHOD_NOT_LO: "DICOM_DEIDENT_METHOD_NOT_LO";
493
493
  readonly DICOM_DEIDENT_METHOD_PRIOR_RETAINED: "DICOM_DEIDENT_METHOD_PRIOR_RETAINED";
494
+ readonly DICOM_DEIDENT_METHOD_VALUE_OVER_LENGTH: "DICOM_DEIDENT_METHOD_VALUE_OVER_LENGTH";
494
495
  readonly DICOM_DEIDENT_SEQUENCE_NOT_AUDITABLE: "DICOM_DEIDENT_SEQUENCE_NOT_AUDITABLE";
495
496
  readonly DICOM_DEIDENT_UNDEFINED_VR_NOT_AUDITABLE: "DICOM_DEIDENT_UNDEFINED_VR_NOT_AUDITABLE";
496
497
  readonly DICOM_PRIVATE_CREATOR_UNKNOWN: "DICOM_PRIVATE_CREATOR_UNKNOWN";
@@ -2974,10 +2975,19 @@ interface DeidentifyOptions {
2974
2975
  * legally carry. The Profile name is now one Value of 61 characters and each
2975
2976
  * active option is its own, so no option subset can exceed the maximum.
2976
2977
  *
2977
- * **Your string is not bounded here.** A value of your own longer than 64
2978
- * characters is written through as given, with no warning: it is yours, and
2979
- * splitting or truncating it would invent a record you did not write. Split it
2980
- * on `\` yourself if a strict receiver is in your path.
2978
+ * **Your string is not bounded here, but it is no longer silent.** A value of
2979
+ * your own longer than 64 characters is written through as given - it is
2980
+ * yours, and splitting or truncating it would invent a record you did not
2981
+ * write - and `report.warnings` carries
2982
+ * `DICOM_DEIDENT_METHOD_VALUE_OVER_LENGTH` to say so. Split it on `\` yourself
2983
+ * if a strict receiver is in your path. The same code covers an over-long
2984
+ * value the **source file** wrote and this run kept, which in the common case
2985
+ * is this library's own 76-character text from a release before the default
2986
+ * became multi-valued. The measurement is over **bytes**: a Value of 64 bytes
2987
+ * or fewer can never carry more than 64 characters, so it cannot miss one that
2988
+ * is genuinely over, but PS3.5 §6.2 specifies the bound in characters rather
2989
+ * than bytes and excludes Code Extension escape sequences from the count, so it
2990
+ * raises on any conformant Value whose bytes outnumber its counted characters.
2981
2991
  *
2982
2992
  * PS3.15 E.1.1 says this string is "inserted in or added to" the attribute, so
2983
2993
  * a value the incoming Data Set already carried is kept and this one is
@@ -3016,7 +3026,9 @@ interface DeidentifyOptions {
3016
3026
  * When the prior value **is** kept, `report.warnings` carries
3017
3027
  * `DICOM_DEIDENT_METHOD_PRIOR_RETAINED`: `(0012,0063)` is not in Table E.1-1, so
3018
3028
  * nothing in the run inspected or redacted those bytes, and a name a sender
3019
- * wrote there is in output stamped `(0012,0062) = YES`.
3029
+ * wrote there is in output stamped `(0012,0062) = YES`. That code discloses the
3030
+ * **retention** only; the **length** of what is written, from whatever source,
3031
+ * is disclosed by `DICOM_DEIDENT_METHOD_VALUE_OVER_LENGTH` and by nothing else.
3020
3032
  */
3021
3033
  readonly deidentificationMethod?: string;
3022
3034
  }
package/dist/index.mjs CHANGED
@@ -9,7 +9,7 @@ var __export = (target, all) => {
9
9
  };
10
10
 
11
11
  // src/version.ts
12
- var VERSION = "0.0.15";
12
+ var VERSION = "0.0.17";
13
13
 
14
14
  // src/dictionary/index.ts
15
15
  var dictionary_exports = {};
@@ -12197,6 +12197,8 @@ var WARNING_CODES = {
12197
12197
  // emitted by deidentify(), never by the parser
12198
12198
  DICOM_DEIDENT_METHOD_PRIOR_RETAINED: "DICOM_DEIDENT_METHOD_PRIOR_RETAINED",
12199
12199
  // emitted by deidentify(), never by the parser
12200
+ DICOM_DEIDENT_METHOD_VALUE_OVER_LENGTH: "DICOM_DEIDENT_METHOD_VALUE_OVER_LENGTH",
12201
+ // emitted by deidentify(), never by the parser
12200
12202
  DICOM_DEIDENT_SEQUENCE_NOT_AUDITABLE: "DICOM_DEIDENT_SEQUENCE_NOT_AUDITABLE",
12201
12203
  // emitted by deidentify(), never by the parser
12202
12204
  DICOM_DEIDENT_UNDEFINED_VR_NOT_AUDITABLE: "DICOM_DEIDENT_UNDEFINED_VR_NOT_AUDITABLE",
@@ -12275,6 +12277,20 @@ var WARNING_MESSAGES = Object.freeze({
12275
12277
  // No value and no length, for the same reason as the code above: the retained
12276
12278
  // text is the file's own. The tag is a constant of this code.
12277
12279
  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.",
12280
+ // No value, no length, no count AND NO ORIGIN. 64 is a constant of the VR, not
12281
+ // a measurement over input; the offending Value's own length IS a measurement
12282
+ // over input and is the number DICOM-DIAGNOSTIC-PHI-RESIDUALS bound out of six
12283
+ // other messages. How many Values are over is the same kind of number, and
12284
+ // which one of them the caller supplied versus which the file did is not
12285
+ // decidable when the two are equal.
12286
+ //
12287
+ // 🛑 AND IT SAYS "LONGER THAN 64 BYTES", NOT "OVER THE MAXIMUM". A graded pass
12288
+ // refuted the draft that called 64 bytes "the largest an LO Value may be under
12289
+ // a single-byte repertoire": PS3.5 6.2 specifies these lengths "in characters
12290
+ // rather than bytes" and excludes Code Extension escape sequences from the
12291
+ // count, so a conformant 64-character Value can exceed 64 bytes under a
12292
+ // single-byte repertoire too. The message states what was measured.
12293
+ 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.",
12278
12294
  // BOTH of the disagreeing length fields are deliberately absent, and the
12279
12295
  // second one is the eighth instance of `DICOM-DIAGNOSTIC-PHI-RESIDUALS`: the
12280
12296
  // remaining-bytes count this string used to carry was the enclosing sequence's
@@ -12403,6 +12419,9 @@ function deidentMethodNotLo(position) {
12403
12419
  function deidentMethodPriorRetained(position) {
12404
12420
  return build2(WARNING_CODES.DICOM_DEIDENT_METHOD_PRIOR_RETAINED, position);
12405
12421
  }
12422
+ function deidentMethodValueOverLength(position) {
12423
+ return build2(WARNING_CODES.DICOM_DEIDENT_METHOD_VALUE_OVER_LENGTH, position);
12424
+ }
12406
12425
  function embeddedAttributeRemoved(position, tag, vr, count) {
12407
12426
  return build2(WARNING_CODES.DICOM_DEIDENT_EMBEDDED_ATTRIBUTE_REMOVED, position, {
12408
12427
  tag,
@@ -15749,6 +15768,10 @@ function defaultMethod(active) {
15749
15768
  }
15750
15769
  var VALUE_DELIMITER = 92;
15751
15770
  var MAX_SHORT_FORM_VALUE_BYTES = 65534;
15771
+ var LO_VALUE_MAX_CHARS = 64;
15772
+ function hasValueOverLoMaximum(field) {
15773
+ return splitValues(field).some((value) => value.length > LO_VALUE_MAX_CHARS);
15774
+ }
15752
15775
  function addDeidentificationMethod(existing, method) {
15753
15776
  const added = trimTrailingPad(Buffer.from(method, "latin1"));
15754
15777
  const none = { replacedPrior: false, retainedPrior: false, replacedNonLoPrior: false };
@@ -15846,6 +15869,11 @@ function deidentify(ds, options = {}) {
15846
15869
  deidentMethodNotLo({ byteOffset: priorMethod?.byteOffset ?? 0, fileMeta: false })
15847
15870
  );
15848
15871
  }
15872
+ if (hasValueOverLoMaximum(deidentMethod.value)) {
15873
+ warnings.push(
15874
+ deidentMethodValueOverLength({ byteOffset: priorMethod?.byteOffset ?? 0, fileMeta: false })
15875
+ );
15876
+ }
15849
15877
  if (hasUncleanedBurnedIn(ds)) {
15850
15878
  const offset = ds.get(TAG_PIXEL_DATA)?.byteOffset ?? 0;
15851
15879
  warnings.push(burnedInAnnotationNotRemoved({ byteOffset: offset, fileMeta: false }));