Difference between revisions of "Template:Groningen/message js"

 
(One intermediate revision by the same user not shown)
Line 2: Line 2:
  
 
(function(){
 
(function(){
 +
var mkErr = function(msg, code, level){
 +
var ret = new Error(msg);
 +
ret.code = code;
 +
ret.level = level;
 +
return ret;
 +
}
 +
 +
// Source: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/String/repeat
 +
if (!String.prototype.repeat) {
 +
String.prototype.repeat = function(count) {
 +
'use strict';
 +
if (this == null) {
 +
throw new TypeError('can\'t convert ' + this + ' to object');
 +
}
 +
var str = '' + this;
 +
count = +count;
 +
if (count != count) {
 +
count = 0;
 +
}
 +
if (count < 0) {
 +
throw new RangeError('repeat count must be non-negative');
 +
}
 +
if (count == Infinity) {
 +
throw new RangeError('repeat count must be less than infinity');
 +
}
 +
count = Math.floor(count);
 +
if (str.length == 0 || count == 0) {
 +
return '';
 +
}
 +
// Ensuring count is a 31-bit integer allows us to heavily optimize the
 +
// main part. But anyway, most current (August 2014) browsers can't handle
 +
// strings 1 << 28 chars or longer, so:
 +
if (str.length * count >= 1 << 28) {
 +
throw new RangeError('repeat count must not overflow maximum string size');
 +
}
 +
var rpt = '';
 +
for (;;) {
 +
if ((count % 2) == 1) {
 +
rpt += str;
 +
}
 +
count >>>= 1;
 +
if (count == 0) {
 +
break;
 +
}
 +
str += str;
 +
}
 +
// Could we try:
 +
// return Array(count + 1).join(this);
 +
return rpt;
 +
}
 +
}
 +
 +
 
/* Structure:
 
/* Structure:
 
*
 
*
Line 48: Line 101:
 
var det = DNA.Restrict.detect(msg);
 
var det = DNA.Restrict.detect(msg);
 
if(det.length > 0){
 
if(det.length > 0){
throw new Error("Restriction substitution failed");
+
throw mkErr("Restriction substitution failed", 'ERESTRICT');
 
}
 
}
 
 
Line 54: Line 107:
 
return {
 
return {
 
'msg': msg,
 
'msg': msg,
 +
'data': dna,
 
'subst': subst.length,
 
'subst': subst.length,
 
'len': len,
 
'len': len,
Line 74: Line 128:
 
 
 
if(start !== 'Spy'){ // start mismatch
 
if(start !== 'Spy'){ // start mismatch
throw new Error("Start mismatch: '"+start+"' / 'Spy'");
+
throw mkErr("Start mismatch: '"+start+"' / 'Spy'", 'ESTART', 1);
 
return null;
 
return null;
 
}
 
}
Line 89: Line 143:
 
 
 
if(CRC.crc16(data) !== crc){ // checksum mismatch
 
if(CRC.crc16(data) !== crc){ // checksum mismatch
throw new Error('CRC mismatch: '+CRC.crc16(data)+' / '+crc+" ("+data.length+" / "+len+")");
+
throw mkErr('CRC mismatch: '+CRC.crc16(data)+' / '+crc+" ("+data.length+" / "+len+")", 'ECRC', 2);
 
return null;
 
return null;
 
}
 
}
Line 97: Line 151:
 
 
 
if(end !== 'GEM'){
 
if(end !== 'GEM'){
throw new Error("End mismatch: '"+end+"' / 'GEM'");
+
throw mkErr("End mismatch: '"+end+"' / 'GEM'", 'EEND', 3);
 
return null;
 
return null;
 
}
 
}
Line 103: Line 157:
 
if(ext){
 
if(ext){
 
return {
 
return {
 +
'msg': msg,
 
'data': data,
 
'data': data,
 
'subst': subst,
 
'subst': subst,
Line 116: Line 171:
 
 
 
return data;
 
return data;
 +
};
 +
 +
var findStart = function(dna, offset){
 +
return dna.indexOf(headDNA, offset);
 
};
 
};
 
 
 
Message = {
 
Message = {
 
'packDNA': packDNA,
 
'packDNA': packDNA,
'unpackDNA': unpackDNA
+
'unpackDNA': unpackDNA,
 +
'findStart': findStart,
 +
'minLength': lengths.start + lengths.pad + lengths.subst + lengths.len +
 +
lengths.crc + lengths.end
 
};
 
};
 
})();
 
})();

Latest revision as of 08:12, 7 October 2016

var Message = {};

(function(){ var mkErr = function(msg, code, level){ var ret = new Error(msg); ret.code = code; ret.level = level; return ret; }

// Source: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/String/repeat if (!String.prototype.repeat) { String.prototype.repeat = function(count) { 'use strict'; if (this == null) { throw new TypeError('can\'t convert ' + this + ' to object'); } var str = + this; count = +count; if (count != count) { count = 0; } if (count < 0) { throw new RangeError('repeat count must be non-negative'); } if (count == Infinity) { throw new RangeError('repeat count must be less than infinity'); } count = Math.floor(count); if (str.length == 0 || count == 0) { return ; } // Ensuring count is a 31-bit integer allows us to heavily optimize the // main part. But anyway, most current (August 2014) browsers can't handle // strings 1 << 28 chars or longer, so: if (str.length * count >= 1 << 28) { throw new RangeError('repeat count must not overflow maximum string size'); } var rpt = ; for (;;) { if ((count % 2) == 1) { rpt += str; } count >>>= 1; if (count == 0) { break; } str += str; } // Could we try: // return Array(count + 1).join(this); return rpt; } }


/* Structure: * * Start: 'Spy': 3 * 4 bases * Pad: 'AAAA': 4 bases * Subst: 1 character 1 * 4 bases * Length: 16 bit number: 8 bases * CRC32: 16 bit number: 8 bases * Data: '...': length * 4 bases * End: 'GEM': 3 * 4 bases */ var headDNA = EightBit.encodeStr('Spy'), tailDNA = EightBit.encodeStr('GEM'), padDNA = 'AAAA', lengths = { 'start': headDNA.length, 'pad': 4, 'subst': 4, 'len': 8, 'crc': 8, 'end': tailDNA.length }, offsets = {}, subOffs = {}, subBase = 'A';

offsets.start = 0; offsets.pad = offsets.start + lengths.start; offsets.subst = offsets.pad + lengths.pad; offsets.len = offsets.subst + lengths.subst; subOffs.len = 0; subOffs.crc = subOffs.len + lengths.len; subOffs.data = subOffs.crc + lengths.crc;

var packDNA = function(dna, ext){ var subst = 0, len = dna.length, crc = CRC.crc16(dna), lenDNA = DNA.encodeUInt(len, lengths.len), crcDNA = DNA.encodeUInt(crc, lengths.crc), suffixDNA = lenDNA + crcDNA + dna + tailDNA, subst = DNA.Restrict.shortestAbsent(suffixDNA, subBase), substDNA = DNA.encodeUInt(subst.length, 4), msg = headDNA + padDNA + substDNA + DNA.Restrict.substitute(suffixDNA, subBase, subst);

var det = DNA.Restrict.detect(msg); if(det.length > 0){ throw mkErr("Restriction substitution failed", 'ERESTRICT'); }

if(ext){ return { 'msg': msg, 'data': dna, 'subst': subst.length, 'len': len, 'crc': crc, 'dnaStart': headDNA, 'dnaEnd': tailDNA, 'dnaSubst': substDNA, 'dnaLen': lenDNA, 'dnaCrc': crcDNA }; }

return msg; };

var unpackDNA = function(msg, ext){ var dnaStart = msg.substr(offsets.start, lengths.start), start = EightBit.decodeStr(dnaStart), pad = msg.substr(offsets.pad, lengths.pad);

if(start !== 'Spy'){ // start mismatch throw mkErr("Start mismatch: '"+start+"' / 'Spy'", 'ESTART', 1); return null; }

var dnaSubst = msg.substr(offsets.subst, lengths.subst), subst = DNA.decodeUInt(dnaSubst), suffixDNA = msg.substr(offsets.len), suffix = DNA.Restrict.restore(suffixDNA, subBase.repeat(subst)), dnaLen = suffix.substr(subOffs.len, lengths.len), len = DNA.decodeUInt(dnaLen), dnaCrc = suffix.substr(subOffs.crc, lengths.crc), crc = DNA.decodeUInt(dnaCrc), data = suffix.substr(subOffs.data, len);

if(CRC.crc16(data) !== crc){ // checksum mismatch throw mkErr('CRC mismatch: '+CRC.crc16(data)+' / '+crc+" ("+data.length+" / "+len+")", 'ECRC', 2); return null; }

var dnaEnd = suffix.substr(subOffs.data + len, lengths.end), end = EightBit.decodeStr(dnaEnd);

if(end !== 'GEM'){ throw mkErr("End mismatch: '"+end+"' / 'GEM'", 'EEND', 3); return null; }

if(ext){ return { 'msg': msg, 'data': data, 'subst': subst, 'len': len, 'crc': crc, 'dnaStart': dnaStart, 'dnaSubst': dnaSubst, 'dnaEnd': dnaEnd, 'dnaLen': dnaLen, 'dnaCrc': dnaCrc }; }

return data; };

var findStart = function(dna, offset){ return dna.indexOf(headDNA, offset); };

Message = { 'packDNA': packDNA, 'unpackDNA': unpackDNA, 'findStart': findStart, 'minLength': lengths.start + lengths.pad + lengths.subst + lengths.len + lengths.crc + lengths.end }; })();