Reading 7BitEncodedInt in Javascript - javascript

I am reading a binary in javascript. I think this file was written in C# and the the way binaries handle the strings in C# is a little different than how it is handled in as mentioned in
https://learn.microsoft.com/en-us/dotnet/api/system.io.binaryreader.readstring?view=net-7.0
The thing is that I am not able to find any library which allows me to read C# style strings OR 7bitEncodedInt. Any suggestions on any code/package that allows me to do that?

Actually, I found an answer in one of the libraries and modified according to what a getString would look like:
private GetString(buffer) {
try {
let length = this.Read7BitEncodedInt(buffer);
if (length < 0) {
this.toastrService.error('Error');
}
if (length == 0) {
return '';
} else {
return buffer.getNextString(length);
}
}
catch (exception){
this.toastrService.error('Error')
}
}
private Read7BitEncodedInt(buffer) {
let count = 0, shift = 0, b = 0, i = 0;
try {
do {
if (shift === 5 * 7) {
this.toastrService.error('Error');
}
//Get a single byte
b = buffer.getNextBytes(1);
// tslint:disable-next-line:no-bitwise
//Update the value of the int based on the byte that it belongs to(shift value)
count |= (b & 0x7F) << shift;
shift += 7;
i++;
// tslint:disable-next-line:triple-equals no-bitwise
//Exit if byte is empty
} while ((b & 0x80) != 0);
}
catch (exception){
this.toastrService.error('Error message');
}

Related

padStart() not working in IE11

I'm using angularjs 1.7.2 and kendo ui scheduler. All routes are working fine in almost all browser except when it comes to padStart() part in IE 11.
When padStart code is taken this error shows up
TypeError: Object doesn't support property or method 'padStart'
let ret = '#' + ((r << 16) + (g << 8) + b).toString(16).padStart(6, '0');
Is there a way we can handle this or an alternative way for implementing padStart
IE 11 is not supporting this function. Please take a look here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padStart#Browser_compatibility
What you are looking for are polyfills to fill up missing functions of your browser.
The following code also taken from developer.mozilla.org will help you:
// https://github.com/behnammodi/polyfill/blob/master/string.polyfill.js
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padStart
if (!String.prototype.padStart) {
String.prototype.padStart = function padStart(targetLength,padString) {
targetLength = targetLength>>0; //truncate if number or convert non-number to 0;
padString = String((typeof padString !== 'undefined' ? padString : ' '));
if (this.length > targetLength) {
return String(this);
}
else {
targetLength = targetLength-this.length;
if (targetLength > padString.length) {
padString += padString.repeat(targetLength/padString.length); //append to original to ensure we are longer than needed
}
return padString.slice(0,targetLength) + String(this);
}
};
}
Edit: As mentioned in the comments, by #Plaute, the function repeat needs also to be polyfilled which can be found here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/repeat
Or include this snippet:
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 maxCount = str.length * count;
count = Math.floor(Math.log(count) / Math.log(2));
while (count) {
str += str;
count--;
}
str += str.substring(0, maxCount - str.length);
return str;
}
}
Alternatively, to work around the String.prototype.repeat dependency, use the following line:
padString += Array.apply(null, Array(targetLength)).map(function(){ return padString; }).join("");

How to count number of ways to parenthesize boolean expression string to evaluate to desired result

Straight out of CTCI, 8.14: Given a boolean expression consisting of the symbols 0 (false), 1 (true), & (AND), | (OR), and ^(XOR), and a desired boolean result value result, implement a function to count the number of ways of parenthesizing the expression such that it evaluates to result.
I'm attempting a brute force approach that calculates every single possible combo, if matches desired result, add it to an array(combos) and return that result length. It seems to work for most expressions, but not the 2nd example given. What do I seem to be missing?
function countEval(s, goalBool, combos = []) {
// on first call make s into array since theyre easier to work with
if (!(s instanceof Array)) {
// and turn 1s and 0s into their bool equivalent
s = s.split('').map((item) => {
if (item === '1') {
return true;
} else if (item === '0'){
return false;
} else {
return item;
}
});
}
if (s.length === 1 && s[0] === goalBool) {
combos.push(s[0]); // can be anything really
} else {
for (let i = 0; i < s.length - 2; i = i + 2) {
// splice out the next 3 items
const args = s.splice(i, 3);
// pass them to see what they evaluate too
const result = evalHelper(args[0], args[1], args[2]);
// splice that result back in s array
s.splice(i, 0, result);
// pass that array to recurse
countEval(s, goalBool, combos);
// remove said item that was just put in
s.splice(i, 1);
// and reset array for next iteration
s.splice(i, 0, ...args);
}
}
return combos.length;
}
function evalHelper(a, op, b) {
if (op === '|') {
return a || b;
} else if (op === '&') {
return a && b;
} else if (op === '^') {
return a !== b;
}
}
With the 2 examples given it works for the first one, but not the second...
console.log(countEval('1^0|0|1', false)); // 2, correct
console.log(countEval('0&0&0&1^1|0', true)); // 30, should be 10!?!?!
The Bug
Your program is not taking into account overlap.
Example
Consider your program when s = '1|1|1|1'.
In one of the depth-first search iterations, your algorithm will make the reduction s = (1|1)|1|1. Then in a deeper recursive level in the same search, your algorithm will make the reduction s = (1|1)|(1|1). Now s is fully reduced, so you increment the length of combos.
In a different depth-first search iteration, your algorithm will first make the reduction s = 1|1|(1|1). Then in a deeper recursive level in the same search, your algorithm will make the reduction s = (1|1)|(1|1). Now s is fully reduced, so you increment the length of combos.
Notice that for both cases, s was parenthesized the same way, thus your program does not take into account overlap.
A Better Solution
A lot of times, when a problem is asking the number of ways something can be done, this is usually a big indicator that dynamic programming could be a potential solution. The recurrence relation to this problem is a bit tricky.
We just need to pick a "principle" operator, then determine the number of ways the left and right side could evaluate to true or false. Then, based on the "principle" operator and the goal boolean, we can derive a formula for the number of ways the expression could evaluate to the goal boolean given that the operator we picked was the "principle" operator.
Code
function ways(expr, res, i, j, cache, spaces) {
if (i == j) {
return parseInt(expr[i]) == res ? 1 : 0;
} else if (!([i, j, res] in cache)) {
var ans = 0;
for (var k = i + 1; k < j; k += 2) {
var op = expr[k];
var leftTrue = ways(expr, 1, i, k - 1, cache);
var leftFalse = ways(expr, 0, i, k - 1, cache);
var rightTrue = ways(expr, 1, k + 1, j, cache);
var rightFalse = ways(expr, 0, k + 1, j, cache);
if (op == '|') {
if (res) {
ans += leftTrue * rightTrue + leftTrue * rightFalse + leftFalse * rightTrue;
} else {
ans += leftFalse * rightFalse;
}
} else if (op == '^') {
if (res) {
ans += leftTrue * rightFalse + leftFalse * rightTrue;
} else {
ans += leftTrue * rightTrue + leftFalse * rightFalse;
}
} else if (op == '&') {
if (res) {
ans += leftTrue * rightTrue;
} else {
ans += leftFalse * rightFalse + leftTrue * rightFalse + leftFalse * rightTrue;
}
}
}
cache[[i, j, res]] = ans;
}
return cache[[i, j, res]];
}
function countEval(expr, res) {
return ways(expr, res ? 1 : 0, 0, expr.length - 1, {});
}

Javascript Encapsulation and Compound Assignment Operator

My aim to to create an object in Javascript where I can easily just go block.red = 128; or block.red += 5. Which could easily be done using this.red inside the object, but I want my object also be able to do which is stumping me is to ensure that the red value falls within the accepted range (i.e. not above 255 and not below 0).
I've had a bit of a look around, and one thing I thought might work was encapsulation. The problem being then is that I can't use the compound assignment operator. Obviously this isn't the end of the world, but I would like to know if there are any solutions that I haven't thought up.
function colours(r, g, b) {
_r = r;
_g = g;
_b = b;
this.red = red;
function red(value) {
if (value == undefined) {
return _r;
} else {
if (value < 0) {
_r = 0;
} else if (value > 255) {
_r = 255;
} else {
_r = value;
}
}
}
}
// tests
colours(240, 120, 60);
alert(red());
red(120);
alert(red());
red(360);
alert(red());
// works up to here
red() -= 30;
alert(red());
So do you have any ideas of how I can keep the compound assignment operator while still ensuring the red value stays within range?
You can use getters and setters as one way to achieve this.
// our constructor function
function Color(r, g, b) {
return {
get red() {
return r;
},
set red(value) {
// let's make sure we get a number here
if ( typeof value === 'number' && !isNaN(value) ) {
// check the range
if (value < 0) {
r = 0;
} else if (value > 255) {
r = 255;
} else {
r = value;
}
} else {
// this gets set if they don't pass a number
r = 255;
}
}
// other color methods here
};
}
// --------------------
var red = new Color(255, 0, 0);
alert(red.red); // 255
red.red -= 55; // assignment within range, success
alert(red.red); // 200
red.red -= 999; // assignment out of range, failure
alert(red.red); // 0
red.red += 999; // assignment out of range, failure
alert(red.red); // 255
jsFiddle example

Substr based on bytes rather than character count

I'm creating an input system where a fields maximum value can only be 200 bytes. I am counting the remaining number of bytes by using the following (this method might but up for debate, too!):
var totalBytes = 200;
var $newVal = $(this).val();
var m = encodeURIComponent($newVal).match(/%[89ABab]/g);
var bytesLeft = totalBytes - ($newVal.length + (m ? m.length : 0));
This appears to work well, however if someone were to paste in a large chunk of data, I want to be able to slice the input and only show 200 bytes of it. I guess in psuedo-code that would look something like :
$newText = substrBytes($string, 0, 200);
Any help or guidance would be appreciated.
Edit : Everything going on here is UTF-8 btw :)
Edit 2 : I'm aware that I can loop every character and evaluate, I think I was hoping there might be something a little more graceful to take care of this.
Thanks!
A Google search yielded a blog article, complete with a try-it-yourself input box. I'm copying the code here because SO likes definitive answers rather than links, but credit goes to McDowell.
/**
* codePoint - an integer containing a Unicode code point
* return - the number of bytes required to store the code point in UTF-8
*/
function utf8Len(codePoint) {
if(codePoint >= 0xD800 && codePoint <= 0xDFFF)
throw new Error("Illegal argument: "+codePoint);
if(codePoint < 0) throw new Error("Illegal argument: "+codePoint);
if(codePoint <= 0x7F) return 1;
if(codePoint <= 0x7FF) return 2;
if(codePoint <= 0xFFFF) return 3;
if(codePoint <= 0x1FFFFF) return 4;
if(codePoint <= 0x3FFFFFF) return 5;
if(codePoint <= 0x7FFFFFFF) return 6;
throw new Error("Illegal argument: "+codePoint);
}
function isHighSurrogate(codeUnit) {
return codeUnit >= 0xD800 && codeUnit <= 0xDBFF;
}
function isLowSurrogate(codeUnit) {
return codeUnit >= 0xDC00 && codeUnit <= 0xDFFF;
}
/**
* Transforms UTF-16 surrogate pairs to a code point.
* See RFC2781
*/
function toCodepoint(highCodeUnit, lowCodeUnit) {
if(!isHighSurrogate(highCodeUnit)) throw new Error("Illegal argument: "+highCodeUnit);
if(!isLowSurrogate(lowCodeUnit)) throw new Error("Illegal argument: "+lowCodeUnit);
highCodeUnit = (0x3FF & highCodeUnit) << 10;
var u = highCodeUnit | (0x3FF & lowCodeUnit);
return u + 0x10000;
}
/**
* Counts the length in bytes of a string when encoded as UTF-8.
* str - a string
* return - the length as an integer
*/
function utf8ByteCount(str) {
var count = 0;
for(var i=0; i<str.length; i++) {
var ch = str.charCodeAt(i);
if(isHighSurrogate(ch)) {
var high = ch;
var low = str.charCodeAt(++i);
count += utf8Len(toCodepoint(high, low));
} else {
count += utf8Len(ch);
}
}
return count;
}
Strings in JavaScript are represented in UTF-16 internally, so every character take actually two bytes. So your question is more like "Get bytes length of str in UTF-8".
Hardly you need half of a symbol, so it may cut 198 or 199 bytes.
Here're 2 different solutions:
// direct byte size counting
function cutInUTF8(str, n) {
var len = Math.min(n, str.length);
var i, cs, c = 0, bytes = 0;
for (i = 0; i < len; i++) {
c = str.charCodeAt(i);
cs = 1;
if (c >= 128) cs++;
if (c >= 2048) cs++;
if (c >= 0xD800 && c < 0xDC00) {
c = str.charCodeAt(++i);
if (c >= 0xDC00 && c < 0xE000) {
cs++;
} else {
// you might actually want to throw an error
i--;
}
}
if (n < (bytes += cs)) break;
}
return str.substr(0, i);
}
// using internal functions, but is not very fast due to try/catch
function cutInUTF8(str, n) {
var encoded = unescape(encodeURIComponent(str)).substr(0, n);
while (true) {
try {
str = decodeURIComponent(escape(encoded));
return str;
} catch(e) {
encoded = encoded.substr(0, encoded.length-1);
}
}
}

Make input of type field send data in base64 rather than binary

I'm writing a simple upload form in html4. It's a very simple process, usually. The problem I'm running into, is for the image data, the server is expecting base64 and will process anything I send it as base64, resulting in corrupt images. Is there some kind of attribute I can set for my form? If not, could I set up some javascript to encode the data into base64 before sending it to the server?
Here is a link to a well documented base64 encoder/decoder http://hellerim.net/base64_src.php . I modified this code (see below) so it did not need the "core" class.
/// BEGIN_DOC(base64).METHOD(decode)
///
// method RETURNTYPE base64.decode(String inp [, enum outType [, bool safe [, bool lax]]])
//
// Encode input data into a base64 character string.
//
// Function arguments:
// String inp: base64 encoded data string to be decoded.
// enum outType Optional. This parameter specifies the type of the output and determines
// how the input data is to be interpreted.:
// 0 - binary data; create a byte array (default)
// 1 - 8-bit character string, assuming 1-byte characters encoded in inp
// 2 - 16-bit (UniCode) character string, assuming 2-byte
// characters encoded in inp
// If 2 is passed to the function, but the number of base64 characters
// is odd, a value of null is returned.
// bool safe Optional. If this parameter is set to true, the standard base64
// character set is replaced with a modified version where
// the characters '+' and '/' are replaced with '-' and '_',
// repectively, in order to avoid problems with file system
// namings which otherwise could occur on some systems.
// By default, the value of this argument is assumed to be
// false.
// bool lax Optional. If set to true, the function skips all input characters which
// cannot be processed. This includes the character '=', too, if
// it is followed by at least one different character before the string
// ends. However, if skipping infeasible characters amounts to a number
// of allowed base64 characters which is not amultiple of 4,
// this is considered an error and null is returned.
// If lax is set to false (the default), null is returned
// whenever an infeasible character is found.
// The purpose of this parameter is to give support in cases
// where data has been base64 encoded and later on was folded by
// some other software, e.g. '\r\n\'s have been inserted in email.
// exchange.
// Return value: The function's processing result value is stored in a string or in
// a byte array before it is returned, depending on the value
// assigned to the type parameter. In each case, the value
// maybe empty but not null if no error occurred.
// Errors: Whenever an error occurs, null is returned. Parameter values
// not defined above are considered errors.
//
/// END_DOC
base64.decode = function(inp, outType, safe, lax) {
// do some argument checking
if (arguments.length < 1) return null;
if (arguments.length < 2) outType = 0; // produce character array by default
if (outType != 0 && outType != 1 && outType != 2) return null;
if (arguments.length >= 3 && safe != true && safe != false) return null;
var sEnc = (arguments.length >= 3 && safe) ? this.encStringS : this.encString; // select encoding character set
if (arguments.length >= 4 && lax != true && lax != false) return null;
var aDec = {}; // create an associative array for decoding
for (var p = 0; p < sEnc.length; p++) { // populate array
aDec[sEnc.charAt(p)] = p;
}
var out = (outType == 0) ? [] : '';
lax = (arguments.length == 4 && lax); // ignore non-base64 characters
var l = 0; // work area
var i = 0; // index into input
var j = 0; // sextett counter
var c = 0; // input buffer
var k = 0; // index into work area
var end = inp.length; // one position past the last character to be processed
var C = '';
// check input
if (lax) {
var inpS = ''; // shadow input
var ignore = false; // determines wether '=' must be counted
var cnt = 0;
for (var p = 1; p <= inp.length; p++) { // check and cleanup string before trying to decode
c = inp.charAt(end - p);
if (c == '=') {
if (!ignore) {
if (++cnt > 1) ignore = true;
} else {
continue;
}
} else if (undefined != aDec[c]) { // the character is base64, hence feasible
if (!ignore) ignore = true; // no more '=' allowed
inpS = c + inpS; // prepend c to shadow input
}
}
for (var p = 0; p <= cnt; p++) { // at most cnt '=''s were garbage, a number in
if (p == 2) return null; // [inpS.length, inpS.length + cnt] must be a
if ((inpS.length + cnt) % 4 == 0) break; // multiple of 4
}
if (inpS.length % 4 == 1) return null; // must be 0, 2, or 3 for inpS to contain correctly base64 encoded data
inp = inpS; // inp now contains feasible characters only
end = inp.length;
} else {
if (inp.length % 4 > 0) return null; // invalid length
for (var p = 0; p < 2; p++) { // search for trailing '=''s
if (inp.charAt(end - 1) == '=') {
end--;
} else {
break;
}
}
}
// convert
for (i = 0; i < end; i++) {
l <<= 6; // clear space for next sextett
if (undefined == (c = aDec[inp.charAt(i)])) return null; // lax must be false at this place!
l |= (c & 0x3f); // append it
if (j == 0) {
j++;
continue; // work area contains incomplete byte only
}
if (outType == 2) {
if (k == 1) { // work area contains complete double byte
out += String.fromCharCode(l >> (2 * (3 - j))); // convert leftmost 16 bits and append them to string
l &= ~(0xffff << (2 * (3 - j))); // clear the 16 processed bits
}
k = ++k % 2;
} else { // work area contains complete byte
if (outType == 0) {
out.push(l >> (2 * (3 - j))); // append byte to array
} else {
out += String.fromCharCode(l >> (2 * (3 - j))); // convert leftmost 8 bits and append them to String
}
l &= ~(0xff << (2 * (3 - j))); // clear the 8 processed bits
}
j = ++j % 4; // increment sextett counter cyclically
}
if (outType == 2 && k == 1) return null; // incomplete double byte in work area
return out;
}

Categories