I have been trying to get a handle on a good code that will provide Javascript for converting IMAP UTF7 mailboxes to JS to UTF-16 string. There seems to be no such work done. Anyone of you built one of these or have one available to share? I am happy to build one but didn't want to if there is someone who has it already.
As I look at the specs it looks like string between '&' and '-' is first decoded with base64 and then decoded as UTF-16 Big Endian, and the reverse process for encoding non-ascii text into UTF-16 portions and then base64. The base64 +/ is represented as +, for file safe operations instead of +_ in other cases.
Let me know if anyone has a solution and I will happy to use it or write one and put it in Github!
Thanks
Vijay
I think I found a simple enough solution to this, as no one responded. Hopefully somebody finds this little script helpful for converting UTF7
>z='Συστήματα_Ανίχνευσης_Εισ & related security.pdf'
>encode_imap_utf7(z)
"&A6MDxQPDA8QDtwMBA7wDsQPEA7E-_&A5EDvQO5AwEDxwO9A7UDxQPDA7cDwg-_&A5UDuQPD- &- related security.pdf"
>decode_imap_utf7(encode_imap_utf7(z))
"Συστήματα_Ανίχνευσης_Εισ & related security.pdf"
>decode_imap_utf7(encode_imap_utf7(z)) == z
true
/* Se RFC 2060 - no / ~ \ in folder names */
function ureplacer(pmatch) {
var ret = ""
pmatch = pmatch.replace(/\,/g,'/')
var ix = pmatch.substr(1,pmatch.length-2)
if (ix.length % 4 != 0)
ix = ix.padEnd(ix.length+ 4 - ix.length % 4,"=")
try {
var dx = atob(ix)
for (var j = 0; j < dx.length; j = j+2) {
ret = ret + String.fromCharCode((dx.charCodeAt(j) << 8) + dx.charCodeAt(j+1))
}
} catch(err) {
console.log("Error in decoding foldername IMAP UTF7, sending empty string back")
console.log(err)
ret = ""
}
return ret
}
function breplacer(umatch) {
var bst = ""
for (var i=0; i < umatch.length; i++) {
var f = umatch.charCodeAt(i)
bst = bst + String.fromCharCode(f >> 8) + String.fromCharCode(f & 255)
}
try {
bst = '&'+btoa(bst).replace(/\//g,',').replace(/=+/,'')+'-'
}catch(err) {
console.log("Error in encoding foldername IMAP UTF7, sending empty string back")
console.log(err)
bst = ""
}
return bst
}
function decode_imap_utf7(mstring) {
var stm = new RegExp(/(\&[A-Za-z0-9\+\,]+\-)/,'g')
return mstring.replace(stm,ureplacer).replace('&-','&')
}
function encode_imap_utf7(ustring) {
ustring = ustring.replace(/\/|\~|\\/g,'')
var vgm = new RegExp(/([^\x20-\x7e]+)/,'g')
return ustring.replace('&','&-').replace(vgm,breplacer)
}
Related
I have a string which is more than 32kb it needs to be chunked, with every chunk having a size limit of 32kb.is it possible ? using JavaScript , I can only find codes like cutting the string or splitting the string in which, I think is not related to my task
stringChop = function(str, size){
if (str == null)
return [];
str = String(str);
return size > 0 ? str.match(new RegExp('.{1,' + size + '}', 'g')) : [str];
}
I also have code the check the bytes
const byteSize = str => new Blob([str]).size;
const result = byteSize("sample")
You really don't want to "spend time" splitting large strings in Node.
If you have to use vanilla
This is entirely possible with JavaScript (and you're pretty close). Though this is more elegant without regular expressions and with generators:
function* chunk(str, size = 3) {
for(let i = 0; i < str.length; i+= size ) yield str.slice(i, i + size);
}
[...chunk('hello world')]; // ["hel", "lo ", "wor", "ld"];
If you can use Node.js
I'd read the file you want to split with a createReadStream and then write it to different files when it reaches the limit. This is much more effective since you don't create many small strings or keep all the data in memory:
(async () => {
let currentFileIndex = 0, currentBytes = 0;
let currentFile = fs.createWriteStream(`${currentFileIndex}.csv`);
for await(const chunk of fs.createReadStream('input.csv') {
currentBytes += chunk.length;
if (currentBytes > 32000) { // or whatever limit you want
currentFile.end(); // probably wait for the allback here
currentBytes = 0;
currentFile = fs.createWriteStream(`${++currentFileIndex}.csv`)
}
await util.promisify(cb => currentFile.write(chunk, cb)();
}
})();
How to convert from Hex string to ASCII string in JavaScript?
Ex:
32343630 it will be 2460
function hex2a(hexx) {
var hex = hexx.toString();//force conversion
var str = '';
for (var i = 0; i < hex.length; i += 2)
str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
return str;
}
hex2a('32343630'); // returns '2460'
Another way to do it (if you use Node.js):
var input = '32343630';
const output = Buffer.from(input, 'hex');
log(input + " -> " + output); // Result: 32343630 -> 2460
For completeness sake the reverse function:
function a2hex(str) {
var arr = [];
for (var i = 0, l = str.length; i < l; i ++) {
var hex = Number(str.charCodeAt(i)).toString(16);
arr.push(hex);
}
return arr.join('');
}
a2hex('2460'); //returns 32343630
You can use this..
var asciiVal = "32343630".match(/.{1,2}/g).map(function(v){
return String.fromCharCode(parseInt(v, 16));
}).join('');
document.write(asciiVal);
** for Hexa to String**
let input = '32343630';
Note : let output = new Buffer(input, 'hex'); // this is deprecated
let buf = Buffer.from(input, "hex");
let data = buf.toString("utf8");
I found a useful function present in web3 library.
var hexString = "0x1231ac"
string strValue = web3.toAscii(hexString)
Update: Newer version of web3 has this function in utils
The functions now resides in utils:
var hexString = "0x1231ac"
string strValue = web3.utils.hexToAscii(hexString)
I've found that the above solution will not work if you have to deal with control characters like 02 (STX) or 03 (ETX), anything under 10 will be read as a single digit and throw off everything after. I ran into this problem trying to parse through serial communications. So, I first took the hex string received and put it in a buffer object then converted the hex string into an array of the strings like so:
buf = Buffer.from(data, 'hex');
l = Buffer.byteLength(buf,'hex');
for (i=0; i<l; i++){
char = buf.toString('hex', i, i+1);
msgArray.push(char);
}
Then .join it
message = msgArray.join('');
then I created a hexToAscii function just like in #Delan Azabani's answer above...
function hexToAscii(str){
hexString = str;
strOut = '';
for (x = 0; x < hexString.length; x += 2) {
strOut += String.fromCharCode(parseInt(hexString.substr(x, 2), 16));
}
return strOut;
}
then called the hexToAscii function on 'message'
message = hexToAscii(message);
This approach also allowed me to iterate through the array and slice into the different parts of the transmission using the control characters so I could then deal with only the part of the data I wanted.
Hope this helps someone else!
console.log(
"68656c6c6f20776f726c6421".match(/.{1,2}/g).reduce((acc,char)=>acc+String.fromCharCode(parseInt(char, 16)),"")
)
An optimized version of the implementation of the reverse function proposed by #michieljoris (according to the comments of #Beterraba and #Mala):
function a2hex(str) {
var hex = '';
for (var i = 0, l = str.length; i < l; i++) {
var hexx = Number(str.charCodeAt(i)).toString(16);
hex += (hexx.length > 1 && hexx || '0' + hexx);
}
return hex;
}
alert(a2hex('2460')); // display 32343630
I use this one, it seems more clear to me as I also receive data with spaces like '30 31 38 30 38 30' and the output is 018080
hexToString(hex: string): string {
return hex.split(' ').map(s => string.fromCharCode(parseInt(s,16))).join('');
}
I'm trying to read a file in order to perform certain actions on the binary data before sending it to a server.
At a certain point I'm trying to convert the data returned by FileReader.readAsArrayBuffer() to an Uint16Array(). However upon doing so the code allocating the array fails with: 'Error: invalid arguments'. I need the data to be a hex string representing the entire binary.
This is the code I'm using:
function HexToHexString(ByteBuffer)
{
//Similar constructs like: 'var Array = new Uint16Array(ByteBuffer);' also fail
var View = new DataView(ByteBuffer);
var Array = new Uint16Array((ByteBuffer.byteLength / 2)); // <- this line fails
for(var i = 0; i < Array.length; i++)
{
Array[i] = View.getUint16(i*2);
}
return String.fromCharCode.apply(null, Array);
}
function OnReadFileCompletion(FileReadEvent)
{
if(FileReadEvent.target.readyState == FileReader.DONE)
{
// Debug code, will be replaced:
document.getElementById('byte_content').textContent = HexToHexString(FileReadEvent.target.result);
//FileReadEvent.target.result;
}
}
function ReadFile(File, ResultFunction)
{
var Reader = new FileReader();
Reader.onloadend = ResultFunction;
Reader.readAsArrayBuffer(File.slice(0, File.size - 1));
}
File Is a file object, ResultFunction is OnReadFileCompletion(), ByteBuffer is an '[object ArrayBuffer]'.
When I output the size of the ArrayBuffer it matches the size of the file (82kb). I'm on firefox 32 with no plugins installed.
I'm not a javascript programmer, does anyone know what I'm doing wrong?
Edit1:
It appears to have something to-do with the size of the file I'm trying to read, using a 1kb text file appears to work while a 82kb binary file does not.
Edit2
I spoke too soon, perhaps it has something to do with file types. An image file of 200kb works, while an executable of 82 does not.
It appears that javascript does not allow executable files to be accesed this way, does anybody know of any way where I could possibly access the data in hex form?
try using .length instead of byteLength
I've hacked together code that works for me, I don't know why this works or what I did wrong the other time. But it works.
function ApplyPadding(Number, PaddingLength)
{
var s = Number + "";
while (s.length < PaddingLength)
s = "0" + s;
return s;
}
function HexToHexString(ByteBuffers)
{
var AnArray = new Uint8Array(ByteBuffers);
var Result = "";
for(var i = 0; i < AnArray.length; i++)
{
if(i%2==0)
Result += ApplyPadding(AnArray[i].toString(16), 2);
}
return Result;
}
function HexStringToHex(aString)
{
var Buffer = new ArrayBuffer(aString.length*2); // 2 bytes for each char
var BufferView = new Uint16Array(Buffer);
for (var i = 0;i < aString.length; i++)
{
BufferView[i] = aString.charCodeAt(i);
}
return Buffer;
}
function OnReadFileCompletion(FileReadEvent)
{
if(FileReadEvent.target.readyState == FileReader.DONE)
{
//document.getElementById('byte_content').textContent =FileReadEvent.target.result;
var DataOfFile = HexStringToHex(FileReadEvent.target.result);
var FinalData = HexToHexString(DataOfFile);
document.getElementById('byte_content').textContent = FinalData;
//FileReadEvent.target.result;
}
}
function ReadFile(File, ResultFunction)
{
var Reader = new FileReader();
Reader.onloadend = ResultFunction;
Reader.readAsBinaryString(File.slice(0, File.size - 1));
}
I have been working on a function to parse a formula for some time, but haven't been able to make it work properly. It seems to not always work - it filters some parts of the text but not all.
parseFormula(e) {
var formula = e.value, value = 0.00, tValue = 0.00, tFormula = '', dObj = {};
if(formula !== undefined && formula !== "") {
dObj._formulaIn = formula;
var f = formula.split(/\s/g);
for(var i = 0; i < f.length; i++) {
tFormula = f[i];
// Replacing PI
tFormula = tFormula.replace(/(pi)/gi,Math.PI);
dObj._1_pi_done = tFormula;
// Replacing Squareroot with placeholder
tFormula = tFormula.replace(/(sqrt)/gi,"__sqrt__");
tFormula = tFormula.replace(/(sqr)/gi,"__sqrt__");
tFormula = tFormula.replace(/(kvrt)/gi,"__sqrt__");
tFormula = tFormula.replace(/(kvr)/gi,"__sqrt__");
dObj._2_sqrt_done = tFormula;
// Removing units that may cause trouble
tFormula = tFormula.replace(/(m2||m3||t2||t3||c2||c3)/gi,"");
dObj._3_units_done = tFormula;
// Removing text
tFormula = tFormula.replace(/\D+[^\*\/\+\-]+[^\,\.]/gi,"");
dObj._4_text_done = tFormula;
// Removing language specific decimals
if(Language.defaultLang === "no_NB") {
tFormula = tFormula.replace(/(\.)/gi,"");
tFormula = tFormula.replace(/(\,)/gi,".");
} else {
tFormula = tFormula.replace(/(\,)/gi,"");
}
dObj._5_lang_done = tFormula;
// Re-applying Squareroot
tFormula = tFormula.replace(/(__sqrt__)/g,"Math.sqrt");
dObj._6_sqrt_done = tFormula;
if(tFormula === "") {
f.splice(i,1);
} else {
f[i] = tFormula;
}
dObj._7_splice_done = tFormula;
console.log(dObj);
}
formula = "";
for(var j = 0; j < f.length; j++) {
formula += f[j];
}
try {
value = eval(formula);
}
catch(err) {}
return value === 0 ? 0 : value.toFixed(4);
} else {
return 0;
}
}
I am not sure about any of the RegEx used in this function, hence why I am asking for help. For example, I am not sure if /(pi)/ is the right way to get the exact text "pi" and replace it with 3.141.
(I am using eval at the moment, but it's merely used for development)
Any help appreciated.
Edit:
The Formula I am trying to parse is a user input formula. Where he/she would type something like: 2/0.6 pcs of foo * pi bar + sqrt(4) foobar. Where I would want it to strip all the non-math letters and calculate the rest. Meaning the above formula would be interpreted as (2/0.6) * 3.141 + Math.sqrt(4) => 12.47
Edit 2:
e is a ExtJS object, passed through by a field in a grid, it contains the following variables:
colIdx (int)
column (Ext.grid.column.Column)
field (string)
grid (Ext.grid.Panel)
originalValue (string)
record (Ext.data.Model)
row (css selector)
rowIdx (int)
store (Ext.data.Store)
value (string)
view (Ext.grid.View)
Am currently unable to get the JSFiddle to work properly.
It's probably easier to tokenize the expression you want to parse. When tokenized it's way easier to read that stream of tokens and build your own expressions.
I've put up a demo on jsFiddle which can parse your given formula
In the demo I used this Tokenizer class and tokens to build a TokenStream from the formula.
function Tokenizer() {
this.tokens = {};
// The regular expression which matches a token per group.
this.regex = null;
// Holds the names of the tokens. Index matches group. See buildExpression()
this.tokenNames = [];
}
Tokenizer.prototype = {
addToken: function(name, expression) {
this.tokens[name] = expression;
},
tokenize: function(data) {
this.buildExpression(data);
var tokens = this.findTokens(data);
return new TokenStream(tokens);
},
buildExpression: function (data) {
var tokenRegex = [];
for (var tokenName in this.tokens) {
this.tokenNames.push(tokenName);
tokenRegex.push('('+this.tokens[tokenName]+')');
}
this.regex = new RegExp(tokenRegex.join('|'), 'g');
},
findTokens: function(data) {
var tokens = [];
var match;
while ((match = this.regex.exec(data)) !== null) {
if (match == undefined) {
continue;
}
for (var group = 1; group < match.length; group++) {
if (!match[group]) continue;
tokens.push({
name: this.tokenNames[group - 1],
data: match[group]
});
}
}
return tokens;
}
}
TokenStream = function (tokens) {
this.cursor = 0;
this.tokens = tokens;
}
TokenStream.prototype = {
next: function () {
return this.tokens[this.cursor++];
},
peek: function (direction) {
if (direction === undefined) {
direction = 0;
}
return this.tokens[this.cursor + direction];
}
}
Defined tokens
tokenizer.addToken('whitespace', '\\s+');
tokenizer.addToken('l_paren', '\\(');
tokenizer.addToken('r_paren', '\\)');
tokenizer.addToken('float', '[0-9]+\\.[0-9]+');
tokenizer.addToken('int', '[0-9]+');
tokenizer.addToken('div', '\\/');
tokenizer.addToken('mul', '\\*');
tokenizer.addToken('add', '\\+');
tokenizer.addToken('constant', 'pi|PI');
tokenizer.addToken('id', '[a-zA-Z_][a-zA-Z0-9_]*');
With the above tokens defined the tokenizer can recognize everything in your formula. When the formula
2/0.6 pcs of foo * pi bar + sqrt(4) foobar
is tokenized the result would be a token stream similar to
int(2), div(/), float(0.6), whitespace( ), id(pcs), whitespace( ), id(of), whitespace( ), id(foo), whitespace( ), mul(*), whitespace( ), constant(pi), whitespace( ), id(bar), whitespace( ), add(+), whitespace( ), id(sqrt), l_paren((), int(4), r_paren()), whitespace( ), id(foobar)
You cannot really use a regular expression to match a formula. Formulae are a context-free language and regular expressions are limited to regular languages, the latter being a subset of the former. There are a number of algorithms for recognizing context-free languages such as CYK and LL parsers. I don't recommend studying those if you already haven't since the topic is quite large.
What you can do quickly, efficiently and easy though, is to attempt to calculate the formula using Reverse Polish Notation (RPN) (use the Shunting Yard algorithm to convert your formula to RPN). If the attempt fails (due to parenthesis not maching, invalid functions / constants, w/e), clearly the text is not a formula, otherwise all is good. Shunting yard is not a particularly difficult algorithm and you should have no trouble implementing it. Even if you do, the wikipedia page I linked above has pseudo code and there a good number of questions in SO as well to help you.
How to convert from Hex string to ASCII string in JavaScript?
Ex:
32343630 it will be 2460
function hex2a(hexx) {
var hex = hexx.toString();//force conversion
var str = '';
for (var i = 0; i < hex.length; i += 2)
str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
return str;
}
hex2a('32343630'); // returns '2460'
Another way to do it (if you use Node.js):
var input = '32343630';
const output = Buffer.from(input, 'hex');
log(input + " -> " + output); // Result: 32343630 -> 2460
For completeness sake the reverse function:
function a2hex(str) {
var arr = [];
for (var i = 0, l = str.length; i < l; i ++) {
var hex = Number(str.charCodeAt(i)).toString(16);
arr.push(hex);
}
return arr.join('');
}
a2hex('2460'); //returns 32343630
You can use this..
var asciiVal = "32343630".match(/.{1,2}/g).map(function(v){
return String.fromCharCode(parseInt(v, 16));
}).join('');
document.write(asciiVal);
** for Hexa to String**
let input = '32343630';
Note : let output = new Buffer(input, 'hex'); // this is deprecated
let buf = Buffer.from(input, "hex");
let data = buf.toString("utf8");
I found a useful function present in web3 library.
var hexString = "0x1231ac"
string strValue = web3.toAscii(hexString)
Update: Newer version of web3 has this function in utils
The functions now resides in utils:
var hexString = "0x1231ac"
string strValue = web3.utils.hexToAscii(hexString)
I've found that the above solution will not work if you have to deal with control characters like 02 (STX) or 03 (ETX), anything under 10 will be read as a single digit and throw off everything after. I ran into this problem trying to parse through serial communications. So, I first took the hex string received and put it in a buffer object then converted the hex string into an array of the strings like so:
buf = Buffer.from(data, 'hex');
l = Buffer.byteLength(buf,'hex');
for (i=0; i<l; i++){
char = buf.toString('hex', i, i+1);
msgArray.push(char);
}
Then .join it
message = msgArray.join('');
then I created a hexToAscii function just like in #Delan Azabani's answer above...
function hexToAscii(str){
hexString = str;
strOut = '';
for (x = 0; x < hexString.length; x += 2) {
strOut += String.fromCharCode(parseInt(hexString.substr(x, 2), 16));
}
return strOut;
}
then called the hexToAscii function on 'message'
message = hexToAscii(message);
This approach also allowed me to iterate through the array and slice into the different parts of the transmission using the control characters so I could then deal with only the part of the data I wanted.
Hope this helps someone else!
console.log(
"68656c6c6f20776f726c6421".match(/.{1,2}/g).reduce((acc,char)=>acc+String.fromCharCode(parseInt(char, 16)),"")
)
An optimized version of the implementation of the reverse function proposed by #michieljoris (according to the comments of #Beterraba and #Mala):
function a2hex(str) {
var hex = '';
for (var i = 0, l = str.length; i < l; i++) {
var hexx = Number(str.charCodeAt(i)).toString(16);
hex += (hexx.length > 1 && hexx || '0' + hexx);
}
return hex;
}
alert(a2hex('2460')); // display 32343630
I use this one, it seems more clear to me as I also receive data with spaces like '30 31 38 30 38 30' and the output is 018080
hexToString(hex: string): string {
return hex.split(' ').map(s => string.fromCharCode(parseInt(s,16))).join('');
}