Skip to content

Add new operation: From/To MS-DOS Date and Time #1454

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/core/config/Categories.json
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,8 @@
"To UNIX Timestamp",
"Windows Filetime to UNIX Timestamp",
"UNIX Timestamp to Windows Filetime",
"From MS-DOS Date and Time",
"To MS-DOS Date and Time",
"DateTime Delta",
"Extract dates",
"Get Time",
Expand Down
87 changes: 87 additions & 0 deletions src/core/operations/FromMSDOSDateAndTime.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/**
* @author mikecat
* @copyright Crown Copyright 2022
* @license Apache-2.0
*/

import Operation from "../Operation.mjs";
import moment from "moment-timezone";
import OperationError from "../errors/OperationError.mjs";

/**
* From MS-DOS Date and Time operation
*/
class FromMSDOSDateAndTime extends Operation {

/**
* FromMSDOSDateAndTime constructor
*/
constructor() {
super();

this.name = "From MS-DOS Date and Time";
this.module = "Default";
this.description = "Receives a space-separated pair of MS-DOS date and time (16-bit unsigned integers) in this order and returns the corresponding datetime in <code>yyyy-MM-dd HH:mm:ss</code> format.<br><br>Some examples of where MS-DOS date and time are used are ZIP archive file and FAT filesystem.";
this.infoURL = "https://learn.microsoft.com/en-us/windows/win32/sysinfo/ms-dos-date-and-time";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
"name": "Input Format",
"type": "option",
"value": ["Decimal", "Hex"]
},
{
"name": "Validate datetime",
"type": "boolean",
"value": true
}
];
}

/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const inputFormat = args[0], validate = args[1];
const radixTable = {"Decimal": 10, "Hex": 16};
if (!(inputFormat in radixTable)) {
throw new OperationError("undefined input format");
}
const radix = radixTable[inputFormat];
const inputParts = input.split(/\s+/);
if (inputParts.length < 2) {
throw new OperationError("invalid input");
}
const dateInput = parseInt(inputParts[0], radix);
const timeInput = parseInt(inputParts[1], radix);
if (isNaN(dateInput) || dateInput < 0 || 0xffff < dateInput ||
isNaN(timeInput) || timeInput < 0 || 0xffff < timeInput) {
throw new OperationError("invalid input");
}
const year = ((dateInput >> 9) & 0x7f) + 1980;
const month = (dateInput >> 5) & 0x0f;
const date = dateInput & 0x1f;
const hour = (timeInput >> 11) & 0x1f;
const minute = (timeInput >> 5) & 0x3f;
const second = (timeInput & 0x1f) << 1;

if (validate) {
const m = moment([year, month - 1, date, hour, minute, second]);
if (!m.isValid()) {
throw new OperationError("invalid datetime");
}
}

const toTwoDigits = function(value) {
return (value >= 10 ? "" : "0") + value;
};
return "" + year + "-" + toTwoDigits(month) + "-" + toTwoDigits(date) +
" " + toTwoDigits(hour) + ":" + toTwoDigits(minute) + ":" + toTwoDigits(second);
}

}

export default FromMSDOSDateAndTime;
90 changes: 90 additions & 0 deletions src/core/operations/ToMSDOSDateAndTime.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/**
* @author mikecat
* @copyright Crown Copyright 2022
* @license Apache-2.0
*/

import Operation from "../Operation.mjs";
import moment from "moment-timezone";
import OperationError from "../errors/OperationError.mjs";

/**
* To MS-DOS Date and Time operation
*/
class ToMSDOSDateAndTime extends Operation {

/**
* ToMSDOSDateAndTime constructor
*/
constructor() {
super();

this.name = "To MS-DOS Date and Time";
this.module = "Default";
this.description = "Parses a datetime string and returns the corresponding space-separated pair of MS-DOS date and time in this order.<br>Each of date and time are represented as 16-bit unsigned integers.<br>Years between 1980 and 2107 (inclusive) are supported.<br><br>Some examples of where MS-DOS date and time are used are ZIP archive file and FAT filesystem.";
this.infoURL = "https://learn.microsoft.com/en-us/windows/win32/sysinfo/ms-dos-date-and-time";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
"name": "Output Format",
"type": "option",
"value": ["Decimal", "Hex"]
},
{
"name": "Show parsed datetime",
"type": "boolean",
"value": true
}
];
}

/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const outputFormat = args[0], showDate = args[1];
const date = moment(input);
if (!date.isValid()) {
throw new OperationError("invalid input");
}
const outputFormatter = (function() {
switch (outputFormat) {
case "Decimal":
return function(value) {
return value.toString();
};
case "Hex":
return function(value) {
const result = value.toString(16);
if (result.length >= 4) return result;
return ("0000" + result).substring(result.length);
};
default:
throw new OperationError("undefined output format");
}
})();
const year = date.year();
if (year < 1980 || 2107 < year) {
throw new OperationError("out-of-range");
}
const dateOut =
((year - 1980) << 9) |
((date.month() + 1) << 5) |
date.date();
const timeOut =
(date.hour() << 11) |
(date.minute() << 5) |
(date.second() >> 1);
const output = outputFormatter(dateOut) + " " + outputFormatter(timeOut);
if (showDate) {
return output + " (" + date.format("yyyy-MM-DD HH:mm:ss") + ")";
}
return output;
}

}

export default ToMSDOSDateAndTime;
1 change: 1 addition & 0 deletions tests/operations/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ import "./tests/MIMEDecoding.mjs";
import "./tests/Modhex.mjs";
import "./tests/MorseCode.mjs";
import "./tests/MS.mjs";
import "./tests/MSDOSDateAndTime.mjs";
import "./tests/MultipleBombe.mjs";
import "./tests/MurmurHash3.mjs";
import "./tests/NetBIOS.mjs";
Expand Down
Loading
Loading