Highlighting now takes account of character set width

This commit is contained in:
n1474335 2022-09-16 16:00:39 +01:00
parent 08b91fd7ff
commit a141873db8
2 changed files with 57 additions and 5 deletions

View File

@ -6,6 +6,8 @@
* @license Apache-2.0
*/
import cptable from "codepage";
/**
* Character encoding format mappings.
*/
@ -175,6 +177,46 @@ for (const name in CHR_ENC_CODE_PAGES) {
CHR_ENC_SIMPLE_REVERSE_LOOKUP[CHR_ENC_CODE_PAGES[name]] = simpleName;
}
/**
* Returns the width of the character set for the given codepage.
* For example, UTF-8 is a Single Byte Character Set, whereas
* UTF-16 is a Double Byte Character Set.
*
* @param {number} page - The codepage number
* @returns {number}
*/
export function chrEncWidth(page) {
if (typeof page !== "number") return 0;
// Raw Bytes have a width of 1
if (page === 0) return 1;
const pageStr = page.toString();
// Confirm this page is legitimate
if (!Object.prototype.hasOwnProperty.call(CHR_ENC_SIMPLE_REVERSE_LOOKUP, pageStr))
return 0;
// Statically defined code pages
if (Object.prototype.hasOwnProperty.call(cptable, pageStr))
return cptable[pageStr].dec.length > 256 ? 2 : 1;
// Cached code pages
if (cptable.utils.cache.sbcs.includes(pageStr))
return 1;
if (cptable.utils.cache.dbcs.includes(pageStr))
return 2;
// Dynamically generated code pages
if (Object.prototype.hasOwnProperty.call(cptable.utils.magic, pageStr)) {
// Generate a single character and measure it
const a = cptable.utils.encode(page, "a");
return a.length;
}
return 0;
}
/**
* Unicode Normalisation Forms
*

View File

@ -5,7 +5,7 @@
*/
import {EditorSelection} from "@codemirror/state";
import {chrEncWidth} from "../../core/lib/ChrEnc.mjs";
/**
* Waiter to handle events related to highlighting in CyberChef.
@ -50,12 +50,23 @@ class HighlighterWaiter {
// Confirm some non-empty ranges are set
const selectionRanges = e.state.selection.ranges;
// Adjust offsets based on the width of the character set
const inputCharacterWidth = chrEncWidth(this.manager.input.inputChrEnc);
const outputCharacterWidth = chrEncWidth(this.manager.output.outputChrEnc);
let ratio = 1;
if (inputCharacterWidth !== outputCharacterWidth &&
inputCharacterWidth !== 0 && outputCharacterWidth !== 0) {
ratio = io === "input" ?
inputCharacterWidth / outputCharacterWidth :
outputCharacterWidth / inputCharacterWidth;
}
// Loop through ranges and send request for output offsets for each one
const direction = io === "input" ? "forward" : "reverse";
for (const range of selectionRanges) {
const pos = [{
start: range.from,
end: range.to
start: Math.floor(range.from * ratio),
end: Math.floor(range.to * ratio)
}];
this.manager.worker.highlight(this.app.getRecipeConfig(), direction, pos);
}
@ -80,8 +91,7 @@ class HighlighterWaiter {
/**
* Adds the relevant HTML to the specified highlight element such that highlighting appears
* underneath the correct offset.
* Sends selection updates to the relevant EditorView.
*
* @param {string} io - The input or output
* @param {Object[]} ranges - An array of position objects to highlight