Skip to content

Commit

Permalink
Refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
copy committed Jul 19, 2014
1 parent 1168610 commit 6af7d54
Show file tree
Hide file tree
Showing 4 changed files with 529 additions and 580 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ CLOSURE_FLAGS=\
CORE_FILES=const.js io.js cpu.js main.js fpu.js ide.js pci.js floppy.js memory.js\
dma.js pit.js vga.js ps2.js pic.js rtc.js uart.js hpet.js acpi.js
BROWSER_FILES=browser/main.js browser/screen.js\
browser/keyboard.js browser/mouse.js browser/serial.js
browser/keyboard.js browser/mouse.js browser/serial.js browser/lib.js
NODE_FILES=node/main.js node/keyboard_sdl.js\
node/screen_sdl.js node/keyboard_tty.js node/screen_tty.js

Expand Down
2 changes: 1 addition & 1 deletion loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
var
CORE_FILES = "const.js io.js cpu.js main.js ide.js fpu.js pci.js floppy.js " +
"memory.js dma.js pit.js vga.js ps2.js pic.js rtc.js uart.js acpi.js hpet.js"
BROWSER_FILES = "main.js screen.js keyboard.js mouse.js serial.js",
BROWSER_FILES = "main.js screen.js keyboard.js mouse.js serial.js lib.js",
LIB_FILES = "esprima.js walk.js";


Expand Down
378 changes: 378 additions & 0 deletions src/browser/lib.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,378 @@

/** @param {?=} progress */
function load_file(filename, done, progress, headers)
{
var http = new XMLHttpRequest();

http.open("get", filename, true);
http.responseType = "arraybuffer";

if(headers)
{
var header_names = Object.keys(headers);

for(var i = 0; i < header_names.length; i++)
{
var name = header_names[i];

http.setRequestHeader(name, headers[name]);
}
}

http.onload = function(e)
{
if(http.readyState === 4)
{
if(http.status !== 200 && http.status !== 206)
{
log("Loading the image `" + filename + "` failed");
}
else if(http.response)
{
done(http.response);
}
}
};

if(progress)
{
http.onprogress = function(e)
{
progress(e);
};
}

http.send(null);
}

// A function set on the protoype of asynchronous buffers (such as AsyncXHRBuffer)
// Relies on this.load_block and this.block_size
// Warning: fn may be called synchronously or asynchronously
function async_buffer_get(offset, len, fn)
{
// TODO: Unaligned read
dbg_assert(offset % this.block_size === 0);
dbg_assert(len % this.block_size === 0);
dbg_assert(len);

var block_size = this.block_size,
blocks_to_load = len / block_size,
data,
loaded_count = 0,
start_block = offset / block_size;

if(blocks_to_load > 1)
{
// copy blocks in this buffer if there is more than one
data = new Uint8Array(len);
}

for(var i = start_block; i < start_block + blocks_to_load; i++)
{
this.load_block(i, block_loaded);
}

function block_loaded(buffer, i)
{
var block = new Uint8Array(buffer);
loaded_count++;

if(blocks_to_load === 1)
{
data = block;
}
else
{
data.set(block, (i - start_block) * block_size);
}

if(loaded_count === blocks_to_load)
{
fn(data);
}
}
}

// Likewise, relies on this.byteLength, this.loaded_blocks and this.block_size
function async_buffer_set(offset, data, fn)
{
dbg_assert(offset + data.length <= this.byteLength);

var len = data.length;

// TODO: Unaligned write
dbg_assert(offset % this.block_size === 0);
dbg_assert(len % this.block_size === 0);
dbg_assert(len);

var start_block = offset / this.block_size;
var block_count = len / this.block_size;

for(var i = 0; i < block_count; i++)
{
var block = this.loaded_blocks[start_block + i];

if(block === undefined)
{
block = this.loaded_blocks[start_block + i] = new ArrayBuffer(this.block_size);
}

var data_slice = data.subarray(i * this.block_size, (i + 1) * this.block_size);
new Uint8Array(block).set(data_slice);

dbg_assert(block.byteLength === data_slice.length);
}

fn();
}

/**
* Asynchronous access to ArrayBuffer, loading blocks lazily as needed.
* This is just a prototype and partly incomplete.
*
* @constructor
* @param {string} filename Name of the file to download parts
* from. Replaces %d with the block number (padded)
*/
function AsyncXHRBuffer(filename, block_size, size)
{
this.block_size = block_size;
this.block_count = size / block_size;
dbg_assert(this.block_count === (this.block_count | 0));

this.loaded_blocks = [];
for(var i = 0; i < this.block_count; i++)
{
this.loaded_blocks[i] = undefined;
}

this.byteLength = size;

// can be called to preload a block into the cache
this.load_block = function(i, fn)
{
var cached_block = this.loaded_blocks[i];

if(cached_block === undefined)
{
var me = this;

// use Range: bytes=... to load slices of a file
var range_start = i * block_size,
range_end = range_start + block_size - 1;

load_file(filename,
function(buffer)
{
dbg_assert(buffer.byteLength === block_size);

me.loaded_blocks[i] = buffer;
fn(buffer, i);
},
null,
{
Range: "bytes=" + range_start + "-" + range_end,
}
);
}
else
{
fn(cached_block, i);
}
};

this.get_buffer = function(fn)
{
// We must download all parts, unlikely a good idea for big files
};
}
AsyncXHRBuffer.prototype.get = async_buffer_get;
AsyncXHRBuffer.prototype.set = async_buffer_set;

/**
* Synchronous access to File, loading blocks from the input type=file
* The whole file is loaded into memory during initialisation
*
* @constructor
*/
function SyncFileBuffer(file)
{
var PART_SIZE = 4 << 20,
ready = false,
me = this;

this.byteLength = file.size;

if(file.size > (1 << 30))
{
dbg_log("Warning: Allocating buffer of " + (file.size >> 20) + " MB ...");
}

var buffer = new ArrayBuffer(file.size),
pointer = 0,
filereader = new FileReader();

this.load = function()
{
// Here: Read all parts sequentially
// Other option: Read all parts in parallel
filereader.onload = function(e)
{
new Uint8Array(buffer, pointer).set(new Uint8Array(e.target.result));
pointer += PART_SIZE;
//dbg_log(PART_SIZE + " bytes of file read");
next();
};

next();

function next()
{
if(me.onprogress)
{
me.onprogress({
loaded: pointer,
total: file.size,
lengthComputable: true,
});
}

if(pointer < file.size)
{
filereader.readAsArrayBuffer(file.slice(pointer, Math.min(pointer + PART_SIZE, file.size)));
}
else
{
ready = true;

if(me.onload)
{
me.onload({

});
}
}
}
}

this.get = function(offset, len, fn)
{
if(ready)
{
dbg_assert(offset + len <= buffer.byteLength);

fn(new Uint8Array(buffer, offset, len));
}
else
{
throw "SyncFileBuffer: Wait for ready";
}
};

this.get_buffer = function(fn)
{
if(ready)
{
fn(buffer);
}
else
{
throw "SyncFileBuffer: Wait for ready";
}
};

/** @param data {Uint8Array] */
this.set = function(offset, data, fn)
{
if(ready)
{
dbg_assert(offset + data.byteLength <= buffer.byteLength);

new Uint8Array(buffer, offset, data.byteLength).set(data);
fn();
}
else
{
throw "SyncFileBuffer: Wait for ready";
}
};
}

/**
* Asynchronous access to File, loading blocks from the input type=file
*
* @constructor
*/
function AsyncFileBuffer(file)
{
var BLOCK_SHIFT = 9,
BLOCK_SIZE = 1 << BLOCK_SHIFT;

this.file = file;
this.byteLength = file.size;

this.block_count = file.size >> BLOCK_SHIFT;
this.block_size = BLOCK_SIZE;

this.loaded_blocks = [];
for(var i = 0; i < this.block_count; i++)
{
this.loaded_blocks[i] = undefined;
}

this.load_block = function(i, fn)
{
var cached_block = this.loaded_blocks[i];

if(cached_block === undefined)
{
var fr = new FileReader();
var me = this;

fr.onload = function(e)
{
var buffer = e.target.result;

me.loaded_blocks[i] = buffer;
fn(buffer, i);
};

fr.readAsArrayBuffer(file.slice(i * this.block_size, (i + 1) * this.block_size));
}
else
{
fn(cached_block, i);
}
};

this.get_buffer = function(fn)
{
};

this.load = function()
{
this.onload && this.onload({});
};
}
AsyncFileBuffer.prototype.get = function(offset, len, fn)
{
dbg_assert(offset % this.block_size === 0);
dbg_assert(len % this.block_size === 0);
dbg_assert(len);

var fr = new FileReader();
var me = this;

fr.onload = function(e)
{
var buffer = e.target.result;

//me.loaded_blocks[i] = buffer;
fn(new Uint8Array(buffer));
};

fr.readAsArrayBuffer(this.file.slice(offset, offset + len));
}
//AsyncFileBuffer.prototype.get = async_buffer_get;
AsyncFileBuffer.prototype.set = async_buffer_set;

Loading

0 comments on commit 6af7d54

Please sign in to comment.