structron
Version:
A reader, writer and validator for binary data structures
109 lines (87 loc) • 2.84 kB
JavaScript
/**
* @class Report
* @type {Object}
* @property {Object} data The exported data.
*
* Used as context for the current import.
*/
class ReadContext {
constructor(buffer, options = {}) {
this.buffer = buffer;
this.monitorUsage = Boolean(options.monitorUsage);
this.hideReferenceValues = Boolean(options.hideReferenceValues)
if (this.monitorUsage) {
this.usageBuffer = Buffer.alloc(buffer.length);
}
// Path to the current read entry
this.path = "root";
this.errors = [];
this.arrays = [];
this.referenceOffsets = {};
}
addError(message) {
this.errors.push({
path: this.path,
message
});
}
markAreaAsRead(start, length) {
if (!this.monitorUsage) return;
for (let i = start; i < start + length; i++) {
if (this.usageBuffer[i] < 255) {
this.usageBuffer[i]++;
}
}
}
checkForArrayCollisions() {
for (let i = 0; i < this.arrays.length; i++) {
let a1 = this.arrays[i];
for (let j = i; j < this.arrays.length; j++) {
let a2 = this.arrays[j];
if (a1.length == 0 || a2.length == 0) continue;
if (a1 == a2) continue;
if (a1.start == a2.start) continue;
// Arrays are allowed in other arrays if multidimensional. This check removes this kind of error, but will give false negatives!
if (a1.path.includes(a2.path) || a2.path.includes(a1.path)) continue;
if (a1.start < (a2.start + a2.length) && a2.start < (a1.start + a1.length)) {
this.path = a1.path + "/" + a2.path;
this.addError("Array " + a1.name + " overlaps with " + a2.name);
}
}
}
}
/**
* Returns a formatted string containing the reports result.
*/
toString() {
let out = "\n===Structron-Report==="
+ "\n Buffer size: " + this.buffer.length;
if (this.monitorUsage) {
let bytesRead = this.getUsage();
out += "\n Bytes read: " + bytesRead + " (" + Math.floor((bytesRead / this.buffer.length) * 100) + "%)";
}
out += "\n Number of arrays: " + this.arrays.length;
if (this.errors.length) {
out += "\n Errors (" + this.errors.length + "):\n "
+ this.errors.map(e => e.path + ": " + e.message).join("\n ");
} else {
out += "\n No errors were found."
}
return out;
}
/**
* Returns the number of read bytes. Returns NaN, if monitorUsage is false
*/
getUsage() {
if (!this.monitorUsage) return NaN;
let number = 0;
for (let i = 0; i < this.usageBuffer.length; i++) {
if (this.usageBuffer[i] > 0) number++;
}
return number;
}
hasErrors() {
return this.errors.length > 0;
}
}
module.exports = ReadContext;