radare/radare2-webui

View on GitHub
www/m/js/modules/hexdump/HexPairNavigator.js

Summary

Maintainability
B
5 hrs
Test Coverage
import {BlockNavigator} from '../../core/BlockNavigator';
import {NavigatorDirection} from '../../core/NavigatorDirection';

/**
 * howManyLines = how many lines per chunk
 * Careful at boundaries [0..end]
 */
export class HexPairNavigator extends BlockNavigator {

    constructor(howManyLines, nbCols, startOffset) {
        super();
        this.howManyBytes = howManyLines * 16;
        this.gap = this.howManyBytes;
        this.currentOffset = startOffset;

        // Define a double-linked list to navigate through chunks
        this.curChunk;

        this.providerWorker = new Worker('hexchunkProvider.js');
        this.providerWorker.postMessage({
            howManyBytes: this.howManyBytes,
            nbCols: nbCols
        });

        this.init();
    }

    /**
     * Force the configuration to be actualized on worker
     */
    changeNbCols(nbCols) {
        this.providerWorker.postMessage({
            howManyBytes: this.howManyBytes,
            nbCols: nbCols,
            reset: true
        });
        this.reset();
    }

    /**
     * Telling to r2 that we have a change
     * It's a one-byte modification so we don't reload and keep track
     */
    reportChange(offset, value) {
        this.smallModifications.push({
            offset: offset,
            value: value
        });

        r2.cmd('wx ' + value + ' @' + offset, function() {});
    }

    /**
     * Return if a value has been modified (edit function)
     */
    hasNewValue(offset) {
        for (var i = 0 ; i < this.smallModifications.length ; i++) {
            if (this.smallModifications[i].offset === offset) {
                return this.smallModifications[i].value;
            }
        }

        return null;
    }

    /**
     * Retrieve all modifications from r2
     */
    updateModifications() {
        var _this = this;
        this.smallModifications = [];
        this.modifiedBytes = [];
        r2.cmd('wcj', function(d) {
            var d = JSON.parse(d);
            for (var i = 0 ; i < d.length ; i++) {
                var offset = d[i].addr;
                for (var x = 0 ; x < d[i].size ; x++) {
                    _this.modifiedBytes.push(offset + x);
                }
            }
        });
    }

    /**
     * Tell if the byte at the current offset has been modified
     */
    isModifiedByte(offset) {
        return (this.modifiedBytes.indexOf(offset) > -1);
    }

    /**
     * Gets all visibles flags
     */
    getFlags(minSize, callback) {
        var filter = function(flags) {
            var filteredFlags = [];
            for (var i = 0 ; i < flags.length ; i++) {
                if (flags[i].size >= minSize) {
                    filteredFlags.push({
                        name: flags[i].name,
                        start: flags[i].offset,
                        end: flags[i].offset + flags[i].size
                    });
                }
            }

            // We want the biggest first
            filteredFlags.sort(function(a, b) {
                return (a.size > b.size) ? -1 : 1;
            });
            return filteredFlags;
        };

        var flags = [];
        var pings = 0;

        // We don't care about order
        var actuator = function() {
            pings++;
            if (pings < 3) {
                return;
            }
            callback(filter(flags));
        };

        this.get(NavigatorDirection.CURRENT, function(chunk) {
            flags = flags.concat(chunk.flags);
            actuator();
        });
        this.get(NavigatorDirection.BEFORE, function(chunk) {
            flags = flags.concat(chunk.flags);
            actuator();
        });
        this.get(NavigatorDirection.AFTER, function(chunk) {
            flags = flags.concat(chunk.flags);
            actuator();
        });
    }

    getBytes(range) {
        var bytes;
        r2.cmdj('p8j ' + (range.to - range.from + 1) + ' @' + range.from, function(list) {
            bytes = list;
        });
        return bytes;
    }

    refreshChunk(which, callback) {
        var modifications = [];
        var _this = this;
        this.get(which, function(chunk) {
            chunk.callback = [];
            modifications = chunk.modified;

            _this.get(which, function(newChunk) {
                newChunk.modified.concat(modifications);
                callback(newChunk);
            }, true);
        });
    }

    refreshCurrent(callback) {
        var pings = 0;
        // We don't care about order
        var actuator = function() {
            pings++;
            if (pings < 3) {
                return;
            }
            callback();
        };

        this.refreshChunk(NavigatorDirection.CURRENT, function() {
            actuator();
        });
        this.refreshChunk(NavigatorDirection.BEFORE, function() {
            actuator();
        });
        this.refreshChunk(NavigatorDirection.AFTER, function() {
            actuator();
        });
    }
}