Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 15 additions & 29 deletions lib/adapters/websql.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ var utils = require('../utils');
var merge = require('../merge');
var errors = require('../deps/errors');
var vuvuzela = require('vuvuzela');
var parseHex = require('../deps/parse-hex');
function quote(str) {
return "'" + str + "'";
}
Expand Down Expand Up @@ -83,22 +84,6 @@ function unknownError(callback) {
callback(errors.error(errors.WSQ_ERROR, errorReason, errorName));
};
}
function decodeUtf8(str) {
return decodeURIComponent(window.escape(str));
}
function parseHexString(str, encoding) {
var result = '';
var charWidth = encoding === 'UTF-8' ? 2 : 4;
for (var i = 0, len = str.length; i < len; i += charWidth) {
var substring = str.substring(i, i + charWidth);
if (charWidth === 4) { // UTF-16, twiddle the bits
substring = substring.substring(2, 4) + substring.substring(0, 2);
}
result += String.fromCharCode(parseInt(substring, 16));
}
result = encoding === 'UTF-8' ? decodeUtf8(result) : result;
return result;
}

function stringifyDoc(doc) {
// don't bother storing the id/rev. it uses lots of space,
Expand Down Expand Up @@ -254,13 +239,13 @@ function WebSqlPouch(opts, callback) {
return callback();
}
var row = rows.shift();
var doc_id_rev = parseHexString(row.hex, encoding);
var idx = doc_id_rev.lastIndexOf('::');
var doc_id = doc_id_rev.substring(0, idx);
var rev = doc_id_rev.substring(idx + 2);
var docIdRev = parseHex.sync(row.hex, encoding);
var idx = docIdRev.lastIndexOf('::');
var doc_id = docIdRev.substring(0, idx);
var rev = docIdRev.substring(idx + 2);
var sql = 'UPDATE ' + BY_SEQ_STORE +
' SET doc_id=?, rev=? WHERE doc_id_rev=?';
tx.executeSql(sql, [doc_id, rev, doc_id_rev], function () {
tx.executeSql(sql, [doc_id, rev, docIdRev], function () {
doNext();
});
}
Expand Down Expand Up @@ -1194,14 +1179,15 @@ function WebSqlPouch(opts, callback) {
// sqlite normally stores data as utf8, so even the hex() function
// "encodes" the binary data in utf8/16 before returning it. yet hex()
// is the only way to get the full data, so we do this.
var data = parseHexString(result.rows.item(0).body, encoding);
if (opts.encode) {
res = btoa(data);
} else {
data = utils.fixBinary(data);
res = utils.createBlob([data], {type: type});
}
callback(null, res);
parseHex.async(result.rows.item(0).body, encoding, function (data) {
if (opts.encode) {
res = btoa(data);
} else {
data = utils.fixBinary(data);
res = utils.createBlob([data], {type: type});
}
callback(null, res);
});
});
};

Expand Down
78 changes: 78 additions & 0 deletions lib/deps/parse-hex.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
'use strict';

var CHUNK_SIZE = 32768;

function decodeUtf8(str) {
return decodeURIComponent(window.escape(str));
}

function dehex(charCode) {
return charCode < 65 ? (charCode - 48) : (charCode - 55);
}

function parseHexCoreUtf8(str, start, end) {
var result = '';
while (start < end) {
result += String.fromCharCode(
(dehex(str.charCodeAt(start++)) << 4) |
dehex(str.charCodeAt(start++)));
}
return result;
}

function parseHexCoreUtf16(str, start, end) {
var result = '';
while (start < end) {
// UTF-16, twiddle the bits
result += String.fromCharCode(
(dehex(str.charCodeAt(start + 2)) << 12) |
(dehex(str.charCodeAt(start + 3)) << 8) |
(dehex(str.charCodeAt(start)) << 4) |
dehex(str.charCodeAt(start + 1)));
start += 4;
}
return result;
}

/**
* Parse a hex-encoded string asynchronously, to avoid blocking the DOM
*/
function parseHexString(str, encoding, callback) {
var utf8 = encoding === 'UTF-8';
var parseHexCore = utf8 ? parseHexCoreUtf8 : parseHexCoreUtf16;
var charsRead = 0;
var len = str.length;
var result = '';

function next() {
if (charsRead === len) {
result = utf8 ? decodeUtf8(result) : result;
return callback(result);
}

process.nextTick(function () {
var readUntil = Math.min(charsRead + CHUNK_SIZE, len);
result += parseHexCore(str, charsRead, readUntil);
charsRead = readUntil;
next();
});
}

next();
}

/**
* Same thing, but synchronous for those cases where we need it
*/
function parseHexStringSync(str, encoding) {
if (encoding === 'UTF-8') {
return decodeUtf8(parseHexCoreUtf8(str, 0, str.length));
} else {
return parseHexCoreUtf16(str, 0, str.length);
}
}

module.exports = {
sync: parseHexStringSync,
async: parseHexString
};