From 61ab9a904f06dd5f527b9b3566b7dd7d81e6c1b9 Mon Sep 17 00:00:00 2001 From: VirtualColossus Date: Thu, 28 Nov 2019 13:22:51 +0000 Subject: [PATCH] Added argument validation --- src/core/lib/Colossus.mjs | 140 +++++++++++++++---------------- src/core/lib/Lorenz.mjs | 3 +- src/core/operations/Colossus.mjs | 57 +++++++++---- 3 files changed, 111 insertions(+), 89 deletions(-) diff --git a/src/core/lib/Colossus.mjs b/src/core/lib/Colossus.mjs index da6829e7..acb8d6fc 100644 --- a/src/core/lib/Colossus.mjs +++ b/src/core/lib/Colossus.mjs @@ -5,8 +5,6 @@ * @copyright Crown Copyright 2019 * @license Apache-2.0 */ -import OperationError from "../errors/OperationError.mjs"; -import Utils from "../Utils.mjs"; import {INIT_PATTERNS, ITA2_TABLE, ROTOR_SIZES} from "../lib/Lorenz.mjs"; /** @@ -26,10 +24,10 @@ export class ColossusComputer { constructor(ciphertext, pattern, qbusin, qbusswitches, control, starts, settotal, limit) { this.ITAlookup = ITA2_TABLE; - this.REVERSE_ITAlookup = {}; + this.ReverseITAlookup = {}; for (const letter in this.ITAlookup) { const code = this.ITAlookup[letter]; - this.REVERSE_ITAlookup[code] = letter; + this.ReverseITAlookup[code] = letter; } this.initThyratrons(pattern); @@ -71,13 +69,13 @@ export class ColossusComputer { */ run() { - let result = { + const result = { printout: "" }; // loop until our start positions are back to the beginning this.rotorPtrs = {X1: this.starts.X1, X2: this.starts.X2, X3: this.starts.X3, X4: this.starts.X4, X5: this.starts.X5, M61: this.starts.M61, M37: this.starts.M37, S1: this.starts.S1, S2: this.starts.S2, S3: this.starts.S3, S4: this.starts.S4, S5: this.starts.S5}; - //this.rotorPtrs = this.starts; + // this.rotorPtrs = this.starts; let runcount = 1; const fast = this.control.fast; @@ -96,11 +94,11 @@ export class ColossusComputer { this.runTape(); // Only print result if larger than set total - var fastRef = "00"; - var slowRef = "00"; - if (fast !== "") fastRef = this.leftPad(this.rotorPtrs[fast],2); - if (slow !== "") slowRef = this.leftPad(this.rotorPtrs[slow],2); - var printline = ''; + let fastRef = "00"; + let slowRef = "00"; + if (fast !== "") fastRef = this.leftPad(this.rotorPtrs[fast], 2); + if (slow !== "") slowRef = this.leftPad(this.rotorPtrs[slow], 2); + let printline = ""; for (let c=0;c<5;c++) { if (this.allCounters[c] > this.settotal) { printline += String.fromCharCode(c+97) + this.allCounters[c]+" "; @@ -110,16 +108,16 @@ export class ColossusComputer { result.printout += fastRef + " " + slowRef + " : "; result.printout += printline; result.printout += "\n"; - } + } // Step fast rotor if required - if (fast != '') { + if (fast !== "") { this.rotorPtrs[fast]++; if (this.rotorPtrs[fast] > ROTOR_SIZES[fast]) this.rotorPtrs[fast] = 1; } - + // Step slow rotor if fast rotor has returned to initial start position - if (slow != '' && this.rotorPtrs[fast] === this.starts[fast]) { + if (slow !== "" && this.rotorPtrs[fast] === this.starts[fast]) { this.rotorPtrs[slow]++; if (this.rotorPtrs[slow] > ROTOR_SIZES[slow]) this.rotorPtrs[slow] = 1; } @@ -132,7 +130,7 @@ export class ColossusComputer { result.runcount = runcount; return result; - }; + } /** * Run tape loop @@ -144,13 +142,13 @@ export class ColossusComputer { this.Xptr = [this.rotorPtrs.X1, this.rotorPtrs.X2, this.rotorPtrs.X3, this.rotorPtrs.X4, this.rotorPtrs.X5]; this.Mptr = [this.rotorPtrs.M37, this.rotorPtrs.M61]; this.Sptr = [this.rotorPtrs.S1, this.rotorPtrs.S2, this.rotorPtrs.S3, this.rotorPtrs.S4, this.rotorPtrs.S5]; - //console.log(this.Xptr); + // console.log(this.Xptr); // Run full loop of all character on the input tape (Z) for (let i=0; i ROTOR_SIZES["S"+(r+1)]) this.Sptr[r] = 1; } } - + // Move M37 rotor if M61 set - if (this.rings.M[1][this.Mptr[1]-1]==1) this.Mptr[0]++; + if (this.rings.M[1][this.Mptr[1]-1]===1) this.Mptr[0]++; if (this.Mptr[0] > ROTOR_SIZES.M37) this.Mptr[0]=1; // Always move M61 rotor @@ -242,107 +240,107 @@ export class ColossusComputer { getQbusInputs(charZin) { // Zbits - the bits from the current character from the cipher tape. this.Zbits = this.ITAlookup[charZin].split(""); - //console.log('Zbits = '+this.Zbits); - if (this.qbusin.Z == 'Z') { + // console.log('Zbits = '+this.Zbits); + if (this.qbusin.Z === "Z") { // direct Z this.Qbits = this.Zbits; - //console.log('direct Z: Qbits = '+this.Qbits); - } else if(this.qbusin.Z == 'ΔZ') { + // console.log('direct Z: Qbits = '+this.Qbits); + } else if (this.qbusin.Z === "ΔZ") { // delta Z, the Bitwise XOR of this character Zbits + last character Zbits - for(let b=0;b<5;b++) { + for (let b=0;b<5;b++) { this.Qbits[b] = this.Zbits[b] ^ this.ZbitsOneBack[b]; } - //console.log('delta Z: Qbits = '+this.Qbits); + // console.log('delta Z: Qbits = '+this.Qbits); } this.ZbitsOneBack = this.Zbits.slice(); // copy value of object, not reference - //console.log('Zin::Q bus now '+this.Qbits+'['+this.REVERSE_ITAlookup[this.Qbits.join("")]+']'); + // console.log('Zin::Q bus now '+this.Qbits+'['+this.ReverseITAlookup[this.Qbits.join("")]+']'); // Xbits - the current Chi wheel bits - //console.log(this.rings.X); - //console.log('Xptr = '+this.Xptr); + // console.log(this.rings.X); + // console.log('Xptr = '+this.Xptr); for (let b=0;b<5;b++) { this.Xbits[b] = this.rings.X[b+1][this.Xptr[b]-1]; } - if (this.qbusin.Chi != "") { - //console.log('X Bits '+this.Xbits+'['+this.REVERSE_ITAlookup[this.Xbits.join("")]+']'); - //console.log('X Char = ' + this.REVERSE_ITAlookup[this.Xbits.join("")]); - if (this.qbusin.Chi == "Χ") { + if (this.qbusin.Chi !== "") { + // console.log('X Bits '+this.Xbits+'['+this.ReverseITAlookup[this.Xbits.join("")]+']'); + // console.log('X Char = ' + this.ReverseITAlookup[this.Xbits.join("")]); + if (this.qbusin.Chi === "Χ") { // direct X added to Qbits for (let b=0;b<5;b++) { this.Qbits[b] = this.Qbits[b] ^ this.Xbits[b]; } - //console.log('direct X: Qbits = '+this.Qbits); - } else if(this.qbusin.Chi == "ΔΧ") { + // console.log('direct X: Qbits = '+this.Qbits); + } else if (this.qbusin.Chi === "ΔΧ") { // delta X - for(let b=0;b<5;b++) { + for (let b=0;b<5;b++) { this.Qbits[b] = this.Qbits[b] ^ this.Xbits[b]; this.Qbits[b] = this.Qbits[b] ^ this.XbitsOneBack[b]; } - //console.log('delta X: Xbits = '+this.Xbits+' Xbits-1 = '+this.XbitsOneBack); - //console.log('delta X: Qbits = '+this.Qbits); + // console.log('delta X: Xbits = '+this.Xbits+' Xbits-1 = '+this.XbitsOneBack); + // console.log('delta X: Qbits = '+this.Qbits); } } this.XbitsOneBack = this.Xbits.slice(); - //console.log('setting XbitsOneBack to '+this.Xbits); + // console.log('setting XbitsOneBack to '+this.Xbits); - //console.log('Zin+Xin::Q bus now '+this.Qbits+'['+this.REVERSE_ITAlookup[this.Qbits.join("")]+']'); + // console.log('Zin+Xin::Q bus now '+this.Qbits+'['+this.ReverseITAlookup[this.Qbits.join("")]+']'); // Sbits - the current Psi wheel bits - //console.log(this.rings.S); - //console.log('Sptr = '+this.Sptr); + // console.log(this.rings.S); + // console.log('Sptr = '+this.Sptr); for (let b=0;b<5;b++) { this.Sbits[b] = this.rings.S[b+1][this.Sptr[b]-1]; } - if (this.qbusin.Psi != "") { - //console.log('S Bits '+this.Sbits+'['+this.REVERSE_ITAlookup[this.Sbits.join("")]+']'); - //console.log('S Char = ' + this.REVERSE_ITAlookup[this.Sbits.join("")]); - if(this.qbusin.Psi == "Ψ") { + if (this.qbusin.Psi !== "") { + // console.log('S Bits '+this.Sbits+'['+this.ReverseITAlookup[this.Sbits.join("")]+']'); + // console.log('S Char = ' + this.ReverseITAlookup[this.Sbits.join("")]); + if (this.qbusin.Psi === "Ψ") { // direct S added to Qbits for (let b=0;b<5;b++) { this.Qbits[b] = this.Qbits[b] ^ this.Sbits[b]; } - //console.log('direct S: Qbits = '+this.Qbits); - } else if(this.qbusin.Psi == "ΔΨ") { + // console.log('direct S: Qbits = '+this.Qbits); + } else if (this.qbusin.Psi === "ΔΨ") { // delta S for (let b=0;b<5;b++) { this.Qbits[b] = this.Qbits[b] ^ this.Sbits[b]; this.Qbits[b] = this.Qbits[b] ^ this.SbitsOneBack[b]; } - //console.log('delta S: Qbits = '+this.Qbits); + // console.log('delta S: Qbits = '+this.Qbits); } } this.SbitsOneBack = this.Sbits.slice(); - //console.log('Q bus now '+this.Qbits+'['+this.REVERSE_ITAlookup[this.Qbits.join("")]+']'); + // console.log('Q bus now '+this.Qbits+'['+this.ReverseITAlookup[this.Qbits.join("")]+']'); } /** * Conditional impulse Q bus section */ runQbusProcessingConditional() { - let cnt = [-1, -1, -1, -1, -1]; + const cnt = [-1, -1, -1, -1, -1]; const numrows = this.qbusswitches.condition.length; for (let r=0;r= 0 && Qswitch[s] != this.Qbits[s]) result = false; + if (Qswitch[s] >= 0 && Qswitch[s] !== this.Qbits[s]) result = false; } // Check for NOT switch if (row.Negate) result = !result; // AND each row to get final result - if (cnt[cPnt] == -1) { + if (cnt[cPnt] === -1) { cnt[cPnt] = result; - } else if (result==0) { + } else if (result === 0) { cnt[cPnt] = 0; } } @@ -352,10 +350,10 @@ export class ColossusComputer { for (let c=0;c<5;c++) { if (this.qbusswitches.condNegateAll) cnt[c] = !cnt[c]; - if (this.qbusswitches.totalMotor === "" || (this.qbusswitches.totalMotor === "x" && this.totalmotor == 0) || (this.qbusswitches.totalMotor === "." && this.totalmotor == 1)) { - if (cnt[c]==1) this.allCounters[c]++; + if (this.qbusswitches.totalMotor === "" || (this.qbusswitches.totalMotor === "x" && this.totalmotor === 0) || (this.qbusswitches.totalMotor === "." && this.totalmotor === 1)) { + if (cnt[c]===1) this.allCounters[c]++; } - + } } @@ -364,7 +362,7 @@ export class ColossusComputer { * Addition of impulses Q bus section */ runQbusProcessingAddition() { - let row = this.qbusswitches.addition[0]; + const row = this.qbusswitches.addition[0]; const Qswitch = row.Qswitches.slice(); if (row.C1) { let addition = 0; @@ -374,12 +372,12 @@ export class ColossusComputer { addition = addition ^ this.Qbits[s]; } } - const equals = (row.Equals==""?-1:(row.Equals=="."?0:1)); - if (addition == equals) { + const equals = (row.Equals===""?-1:(row.Equals==="."?0:1)); + if (addition === equals) { this.allCounters[0]++; } } - //console.log("counter1="+this.allCounters[0]); + // console.log("counter1="+this.allCounters[0]); } /** @@ -424,7 +422,7 @@ export class ColossusComputer { * Read argument bus switches X & . and convert to 1 & 0 */ readBusSwitches(row) { - let output = [-1, -1, -1, -1, -1]; + const output = [-1, -1, -1, -1, -1]; for (let c=0;c<5;c++) { if (row[c]===".") output[c] = 0; if (row[c]==="x") output[c] = 1; diff --git a/src/core/lib/Lorenz.mjs b/src/core/lib/Lorenz.mjs index e69946fa..fa4350e0 100644 --- a/src/core/lib/Lorenz.mjs +++ b/src/core/lib/Lorenz.mjs @@ -5,7 +5,6 @@ * @copyright Crown Copyright 2019 * @license Apache-2.0 */ -import OperationError from "../errors/OperationError.mjs"; export const SWITCHES = [ {name: "Up (.)", value: "."}, @@ -152,4 +151,4 @@ export const INIT_PATTERNS = { 2: [0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1] } } -}; \ No newline at end of file +}; diff --git a/src/core/operations/Colossus.mjs b/src/core/operations/Colossus.mjs index 46f0451e..60c7f14c 100644 --- a/src/core/operations/Colossus.mjs +++ b/src/core/operations/Colossus.mjs @@ -278,27 +278,27 @@ class Colossus extends Operation { value: ["", "X1", "X2", "X3", "X4", "X5", "M37", "M61", "S1", "S2", "S3", "S4", "S5"] }, { - name: "Start X1", + name: "Start Χ1", type: "number", value: 1 }, { - name: "Start X2", + name: "Start Χ2", type: "number", value: 1 }, { - name: "Start X3", + name: "Start Χ3", type: "number", value: 1 }, { - name: "Start X4", + name: "Start Χ4", type: "number", value: 1 }, { - name: "Start X5", + name: "Start Χ5", type: "number", value: 1 }, @@ -313,27 +313,27 @@ class Colossus extends Operation { value: 1 }, { - name: "Start S1", + name: "Start Ψ1", type: "number", value: 1 }, { - name: "Start S2", + name: "Start Ψ2", type: "number", value: 1 }, { - name: "Start S3", + name: "Start Ψ3", type: "number", value: 1 }, { - name: "Start S4", + name: "Start Ψ4", type: "number", value: 1 }, { - name: "Start S5", + name: "Start Ψ5", type: "number", value: 1 } @@ -355,7 +355,7 @@ class Colossus extends Operation { }; const limitation = args[5]; - let lm = [false,false,false]; + const lm = [false, false, false]; if (limitation.includes("Χ2")) lm[0] = true; if (limitation.includes("Ψ1")) lm[1] = true; if (limitation.includes("P5")) lm[2] = true; @@ -370,6 +370,16 @@ class Colossus extends Operation { args = this.selectProgram(setProgram, args); } + const re = new RegExp("^$|^[.x]$"); + for (let qr=0;qr<3;qr++) { + for (let a=0;a<5;a++) { + if (!re.test(args[((qr*7)+(a+9))])) throw new OperationError("Switch R"+(qr+1)+"-Q"+(a+1)+" can only be set to blank, . or x"); + } + } + + if (!re.test(args[37])) throw new OperationError("Switch Add-Equals can only be set to blank, . or x"); + if (!re.test(args[40])) throw new OperationError("Switch Total Motor can only be set to blank, . or x"); + // Q1,Q2,Q3,Q4,Q5,negate,counter1 const qbusswitches = { condition: [ @@ -385,7 +395,8 @@ class Colossus extends Operation { totalMotor: args[40] }; - const settotal = args[42]; + const settotal = parseInt(args[42], 10); + if (settotal < 0 || settotal > 9999) throw new OperationError("Set Total must be between 0000 and 9999"); // null|fast|slow for each of S1-5,M1-2,X1-5 const control = { @@ -394,6 +405,20 @@ class Colossus extends Operation { }; // Start positions + + if (args[52]<1 || args[52]>43) throw new OperationError("Ψ1 start must be between 1 and 43"); + if (args[53]<1 || args[53]>47) throw new OperationError("Ψ2 start must be between 1 and 47"); + if (args[54]<1 || args[54]>51) throw new OperationError("Ψ3 start must be between 1 and 51"); + if (args[55]<1 || args[55]>53) throw new OperationError("Ψ4 start must be between 1 and 53"); + if (args[56]<1 || args[57]>59) throw new OperationError("Ψ5 start must be between 1 and 59"); + if (args[51]<1 || args[51]>37) throw new OperationError("Μ37 start must be between 1 and 37"); + if (args[50]<1 || args[50]>61) throw new OperationError("Μ61 start must be between 1 and 61"); + if (args[45]<1 || args[45]>41) throw new OperationError("Χ1 start must be between 1 and 41"); + if (args[46]<1 || args[46]>31) throw new OperationError("Χ2 start must be between 1 and 31"); + if (args[47]<1 || args[47]>29) throw new OperationError("Χ3 start must be between 1 and 29"); + if (args[48]<1 || args[48]>26) throw new OperationError("Χ4 start must be between 1 and 26"); + if (args[49]<1 || args[49]>23) throw new OperationError("Χ5 start must be between 1 and 23"); + const starts = { X1: args[45], X2: args[46], X3: args[47], X4: args[48], X5: args[49], M61: args[50], M37: args[51], @@ -415,7 +440,7 @@ class Colossus extends Operation { selectProgram(progname, args) { // Basic Letter Count - if (progname == "Letter Count") { + if (progname === "Letter Count") { // Set Conditional R1 : count every character into counter 1 args[9] = ""; args[10] = ""; @@ -434,7 +459,7 @@ class Colossus extends Operation { } // Bill Tutte's 1+2 Break In - if (progname == "1+2=. (1+2 Break In, Find X1,X2)") { + if (progname === "1+2=. (1+2 Break In, Find X1,X2)") { // Clear any other counters args[15] = ""; // Conditional R1 args[22] = ""; // Conditional R2 @@ -450,7 +475,7 @@ class Colossus extends Operation { } // 4=3=/1=2 : Find X4 & X5 where X1 & X2 are known - if (progname == "4=3=/1=2 (Given X1,X2 find X4,X5)") { + if (progname === "4=3=/1=2 (Given X1,X2 find X4,X5)") { // Set Conditional R1 : Match NOT ..?.. into counter 1 args[9] = "."; args[10] = "."; @@ -476,7 +501,7 @@ class Colossus extends Operation { } // /,5,U : Count number of matches of /, 5 & U to find X3 - if (progname == "/,5,U (Count chars to find X3)") { + if (progname === "/,5,U (Count chars to find X3)") { // Set Conditional R1 : Match / char, ITA2 = ..... into counter 1 args[9] = "."; args[10] = ".";