🎨 Improve Bencode parser

This commit is contained in:
C-3PO 2018-06-22 17:17:12 +02:00
parent a221ee3a6b
commit a578d21663
Signed by: c3po
GPG key ID: 62993C4BB4D86F24
2 changed files with 64 additions and 57 deletions

View file

@ -7,67 +7,74 @@ import { TextDecoder } from 'util';
const Decoder = new TextDecoder('utf-8'); const Decoder = new TextDecoder('utf-8');
/** Takes a Bencoded-encoded file, parses it at the given starting position and returns a JSON object, or rejects on error. */ /** Takes a Bencoded-encoded file, parses it at the given starting position and returns a JSON object, or rejects on error. */
export default function bpParse(dv: DataView, posIn: number = 0): { obj: any, pos: number } { function bpParse(dv: DataView, posIn: number = 0): { obj: any, pos: number } {
let pos = posIn; let pos = posIn;
let obj; let obj;
const header = dv.getUint8(pos); pos += 1; const header = dv.getUint8(pos); pos += 1;
switch (header) { switch (header) {
case 0x64: { //'d' - dictionary (key-value object) case 0x64: { //'d' - dictionary (key-value object)
obj = []; obj = [];
do { do {
//read key //read key
const out1 = bpParse(dv, pos); const out1 = bpParse(dv, pos);
pos = out1.pos; pos = out1.pos;
//read value //read value
const out2 = bpParse(dv, pos); const out2 = bpParse(dv, pos);
pos = out2.pos; pos = out2.pos;
obj[out1.obj] = out2.obj; obj[out1.obj] = out2.obj;
} while (dv.getUint8(pos) !== 0x65); //'e' - end } while (dv.getUint8(pos) !== 0x65); //'e' - end
pos += 1; pos += 1;
break; break;
}
case 0x6C: { //'l' - list (array)
obj = [];
do {
//read entry
const out = bpParse(dv, pos);
pos = out.pos;
obj.push(out.obj);
} while (dv.getUint8(pos) !== 0x65); //'e' - end
pos += 1;
break;
}
case 0x69: { //'i' - integer
let curChar = dv.getUint8(pos); pos += 1;
let curNumber = 0;
while (curChar !== 0x65) { //'e' - end
if (curChar < 0x30 || curChar > 0x39) {
throw new Error('Unexpected int char during bencode parsing');
}
curNumber *= 10;
curNumber += curChar - 0x30;
curChar = dv.getUint8(pos); pos += 1;
} }
case 0x6C: { //'l' - list (array) obj = curNumber;
obj = []; break;
do { }
//read entry case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:
const out = bpParse(dv, pos); case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: { //string prefixed by length
pos = out.pos; //read string length
obj.push(out.obj); let curChar: number = header;
} while (dv.getUint8(pos) !== 0x65); //'e' - end let strLen = 0;
pos += 1; while (curChar !== 0x3A) { //':' - integer delimiter, beginning of string
break; if (curChar < 0x30 || curChar > 0x39) {
throw new Error('Unexpected string length during bencode parsing');
}
strLen *= 10;
strLen += curChar - 0x30;
curChar = dv.getUint8(pos); pos += 1;
} }
case 0x69: { //'i' - integer //read string
let curChar = dv.getUint8(pos); pos += 1; obj = Decoder.decode(new DataView(dv.buffer, pos, strLen));
let curNumber = 0; pos += strLen;
while (curChar !== 0x65) { //'e' - end break;
if (curChar < 0x30 || curChar > 0x39) { }
throw new Error('Unexpected int char during bencode parsing'); default:
} throw new Error('Unexpected leading char during bencode parsing.');
curNumber *= 10;
curNumber += curChar - 0x30;
curChar = dv.getUint8(pos); pos += 1;
}
obj = curNumber;
break;
}
case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:
case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: { //string prefixed by length
//read string length
let curChar: number = header;
let strLen = 0;
while (curChar !== 0x3A) { //':' - integer delimiter, beginning of string
strLen *= 10;
strLen += curChar - 0x30;
curChar = dv.getUint8(pos); pos += 1;
}
//read string
obj = Decoder.decode(new DataView(dv.buffer, pos, strLen));
pos += strLen;
break;
}
default:
throw new Error('Unexpected leading char during bencode parsing.');
} }
return { obj, pos }; return { obj, pos };
} }
export default function parseBencode(dv: DataView): any {
return bpParse(dv).obj;
}

View file

@ -2,7 +2,7 @@ import getUrlContents from '../getUrlContents';
import { Product } from '../interfaces/ISettings'; import { Product } from '../interfaces/ISettings';
import ISolid from '../interfaces/ISolidFile'; import ISolid from '../interfaces/ISolidFile';
import verifyProductName from '../ssn/verifyProductName'; import verifyProductName from '../ssn/verifyProductName';
import bpParse from './bencodeParser'; import parseBencode from './bencodeParser';
import extractFile from './extractFile'; import extractFile from './extractFile';
import readSsnFile from './readSsnFile'; import readSsnFile from './readSsnFile';
import verifySolidpkg from './verifySolidpkg'; import verifySolidpkg from './verifySolidpkg';
@ -39,7 +39,7 @@ export default async function getSolidpkg(product: Product, from: number, to: nu
//Extract metafile.solid file //Extract metafile.solid file
const solidFile = await extractFile(firstFile, [new DataView(ssnFile)]); const solidFile = await extractFile(firstFile, [new DataView(ssnFile)]);
const solidContents = bpParse(new DataView(solidFile)).obj as ISolid; const solidContents = parseBencode(new DataView(solidFile)) as ISolid;
//Verify metafile.solid for correctness //Verify metafile.solid for correctness
verifySolidpkg(solidContents, { product, from, to }); verifySolidpkg(solidContents, { product, from, to });