From 230d7f92291d2aa3b7b7493d419667b625d0513c Mon Sep 17 00:00:00 2001 From: Calixte Denizet Date: Sun, 27 Oct 2024 19:19:06 +0100 Subject: [PATCH] Make util.scand a bit more flexible with dates which don't match the given format (bug 1910431) --- src/scripting_api/aform.js | 117 +++--------------------------------- src/scripting_api/util.js | 95 ++++++++++++++++++++++++++++- test/unit/scripting_spec.js | 6 ++ 3 files changed, 108 insertions(+), 110 deletions(-) diff --git a/src/scripting_api/aform.js b/src/scripting_api/aform.js index 355fc8450f976..78a9a312df26c 100644 --- a/src/scripting_api/aform.js +++ b/src/scripting_api/aform.js @@ -38,7 +38,6 @@ class AForm { "m/d/yy HH:MM", ]; this._timeFormats = ["HH:MM", "h:MM tt", "HH:MM:ss", "h:MM:ss tt"]; - this._dateActionsCache = new Map(); // The e-mail address regex below originates from: // https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address @@ -53,120 +52,20 @@ class AForm { return event.target ? `[ ${event.target.name} ]` : ""; } - _tryToGuessDate(cFormat, cDate) { - // We use the format to know the order of day, month, year, ... - - let actions = this._dateActionsCache.get(cFormat); - if (!actions) { - actions = []; - this._dateActionsCache.set(cFormat, actions); - cFormat.replaceAll( - /(d+)|(m+)|(y+)|(H+)|(M+)|(s+)/g, - function (match, d, m, y, H, M, s) { - if (d) { - actions.push((n, date) => { - if (n >= 1 && n <= 31) { - date.setDate(n); - return true; - } - return false; - }); - } else if (m) { - actions.push((n, date) => { - if (n >= 1 && n <= 12) { - date.setMonth(n - 1); - return true; - } - return false; - }); - } else if (y) { - actions.push((n, date) => { - if (n < 50) { - n += 2000; - } else if (n < 100) { - n += 1900; - } - date.setYear(n); - return true; - }); - } else if (H) { - actions.push((n, date) => { - if (n >= 0 && n <= 23) { - date.setHours(n); - return true; - } - return false; - }); - } else if (M) { - actions.push((n, date) => { - if (n >= 0 && n <= 59) { - date.setMinutes(n); - return true; - } - return false; - }); - } else if (s) { - actions.push((n, date) => { - if (n >= 0 && n <= 59) { - date.setSeconds(n); - return true; - } - return false; - }); - } - return ""; - } - ); - } - - const number = /\d+/g; - let i = 0; - let array; - const date = new Date(); - while ((array = number.exec(cDate)) !== null) { - if (i < actions.length) { - if (!actions[i++](parseInt(array[0]), date)) { - return null; - } - } else { - break; - } - } - - if (i === 0) { - return null; - } - - return date; - } - _parseDate(cFormat, cDate, strict = false) { let date = null; try { - date = this._util.scand(cFormat, cDate); + date = this._util._scand(cFormat, cDate, strict); } catch {} - if (!date) { - if (strict) { - return null; - } - let format = cFormat; - if (/mm(?!m)/.test(format)) { - format = format.replace("mm", "m"); - } - if (/dd(?!d)/.test(format)) { - format = format.replace("dd", "d"); - } - try { - date = this._util.scand(format, cDate); - } catch {} + if (date) { + return date; } - if (!date) { - date = Date.parse(cDate); - date = isNaN(date) - ? this._tryToGuessDate(cFormat, cDate) - : new Date(date); + if (strict) { + return null; } - return date; + + date = Date.parse(cDate); + return isNaN(date) ? null : new Date(date); } AFMergeChange(event = globalThis.event) { diff --git a/src/scripting_api/util.js b/src/scripting_api/util.js index 551a3fb600797..cd2f2a6b4502b 100644 --- a/src/scripting_api/util.js +++ b/src/scripting_api/util.js @@ -16,6 +16,8 @@ import { PDFObject } from "./pdf_object.js"; class Util extends PDFObject { + #dateActionsCache = null; + constructor(data) { super(data); @@ -338,7 +340,98 @@ class Util extends PDFObject { return buf.join(""); } + #tryToGuessDate(cFormat, cDate) { + // We use the format to know the order of day, month, year, ... + + let actions = (this.#dateActionsCache ||= new Map()).get(cFormat); + if (!actions) { + actions = []; + this.#dateActionsCache.set(cFormat, actions); + cFormat.replaceAll( + /(d+)|(m+)|(y+)|(H+)|(M+)|(s+)/g, + function (match, d, m, y, H, M, s) { + if (d) { + actions.push((n, date) => { + if (n >= 1 && n <= 31) { + date.setDate(n); + return true; + } + return false; + }); + } else if (m) { + actions.push((n, date) => { + if (n >= 1 && n <= 12) { + date.setMonth(n - 1); + return true; + } + return false; + }); + } else if (y) { + actions.push((n, date) => { + if (n < 50) { + n += 2000; + } else if (n < 100) { + n += 1900; + } + date.setYear(n); + return true; + }); + } else if (H) { + actions.push((n, date) => { + if (n >= 0 && n <= 23) { + date.setHours(n); + return true; + } + return false; + }); + } else if (M) { + actions.push((n, date) => { + if (n >= 0 && n <= 59) { + date.setMinutes(n); + return true; + } + return false; + }); + } else if (s) { + actions.push((n, date) => { + if (n >= 0 && n <= 59) { + date.setSeconds(n); + return true; + } + return false; + }); + } + return ""; + } + ); + } + + const number = /\d+/g; + let i = 0; + let array; + const date = new Date(0); + while ((array = number.exec(cDate)) !== null) { + if (i < actions.length) { + if (!actions[i++](parseInt(array[0]), date)) { + return null; + } + } else { + break; + } + } + + if (i === 0) { + return null; + } + + return date; + } + scand(cFormat, cDate) { + return this._scand(cFormat, cDate); + } + + _scand(cFormat, cDate, strict = false) { if (typeof cDate !== "string") { return new Date(cDate); } @@ -508,7 +601,7 @@ class Util extends PDFObject { const matches = new RegExp(`^${re}$`, "g").exec(cDate); if (!matches || matches.length !== actions.length + 1) { - return null; + return strict ? null : this.#tryToGuessDate(cFormat, cDate); } const data = { diff --git a/test/unit/scripting_spec.js b/test/unit/scripting_spec.js index 12c7161c21c9c..94ed4aa7f8118 100644 --- a/test/unit/scripting_spec.js +++ b/test/unit/scripting_spec.js @@ -243,6 +243,12 @@ describe("Scripting", function () { value = await myeval(`util.scand(2, "4/15/07 3:14:15 am").toString()`); expect(new Date(value)).toEqual(date); + + value = await myeval(`util.scand("mmddyyyy", "07/15/2007").toString()`); + expect(new Date(value)).toEqual(new Date("07/15/2007")); + + value = await myeval(`util.scand("mmddyyyy", "07a15b2007").toString()`); + expect(new Date(value)).toEqual(new Date("07/15/2007")); }); });