converting array buffers to string - javascript
I'm getting some weird results when converting an array buffer to a string then displaying the output in a div.
I'm getting some GPS data from the USB port in a chrome packaged app. It converts the array buffer received from the port into a string and outputs. The functions are:
var onReceiveCallback = function(info) {
if (info.connectionId == connectionId && info.data) {
$(".output").append(ab2str(info.data));
}
};
/* Interprets an ArrayBuffer as UTF-8 encoded string data. */
var ab2str = function(buf) {
var bufView = new Uint8Array(buf);
var encodedString = String.fromCharCode.apply(null, bufView);
return decodeURIComponent(escape(encodedString));
};
I have a start and stop button to obviously start and stop the reading of data from the gps device. When I start it the first time it works and outputs as expected, something like:
$GPGGA,214948.209,,,,,0,0,,,M,,M,,*41 $GPGSA,A,1,,,,,,,,,,,,,,,*1E
$GPGSV,1,1,01,07,,,33*7F
$GPRMC,214948.209,V,,,,,0.00,0.00,270814,,,N*4C
$GPGGA,214949.209,,,,,0,0,,,M,,M,,*40 $GPGSA,A,1,,,,,,,,,,,,,,,*1E
$GPGSV,1,1,01,07,,,34*78
$GPRMC,214949.209,V,,,,,0.00,0.00,270814,,,N*4D
but then when I stop it, and restart it, although I clear the output div, the output data seems to be mixing in with the previous result. Like:
$$GPGPGGGGAA,,221155115544..202099,,,,,,,,,0,0,0,0,,,,,,MM,,,,MM,,,,**4455
$$GGPPGGSSAA,,AA,,11,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,**11EE
$$GGPGPGSSVV,,11,,11,,0022,,0077,,,,,,3344,1,177,,,,,,3311**77FF
$$GGPPRRMMCC,,212155115544..220099,,VV,,,,,,,,,,00..0000,,00..0000,,227700881144,,,,,,NN*4*488
$$GPGGPGGGAA,,221155115555..220099,,,,,,,,,,00,,00,,,,,,MM,,,,MM,,,,**4444
$$GGPPGGSSAA,,AA,,11,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,**11EE
$G$GPPGGSSVV,,11,,11,,0022,,0077,,,,,,331,1,1177,,,,,,2255**77FF
$$GGPPRRMMCC,2,21155115555..220099,,VV,,,,,,,,,,00..0000,,00..0000,,227700881144,,,,,,N*N*4499
Its like a buffer or variable isnt being emptied, or something else crazy that I cant figure out. Any pointers appreciated.
edit:
this is the 'start' function which clears the output div and reconnects:
// when the start button is clicked
$( "#start" ).click(function() {
if ( deviceId == 0 ) {
console.log("Please select a device");
return;
}
else {
$(".output").empty();
serial.connect(deviceId, {bitrate: 9600}, onConnect);
}
});
I have found this technique unreliable in my own code, although I don't remember if the problem was similar to one you report:
var ab2str = function(buf) { // not reliable
var bufView = new Uint8Array(buf);
var encodedString = String.fromCharCode.apply(null, bufView);
return decodeURIComponent(escape(encodedString));
};
So, I have done it this way, with code taken from one of the Google Chrome App examples (tcpserver):
function ab2str(buf, callback) {
var bb = new Blob([new Uint8Array(buf)]);
var f = new FileReader();
f.onload = function(e) {
callback(e.target.result);
};
f.readAsText(bb);
}
Note that this version isn't an exact replacement, since it's asynchronous.
Now, starting with Chrome Version 38 (now in beta), you can do it this way:
function ab2str(buf) {
var dataView = new DataView(buf);
var decoder = new TextDecoder('utf-8');
return decoder.decode(dataView);
}
As I always run the beta and am preparing examples for a forthcoming book, I am now doing it the newest way. Give that a try and see if your problem goes away. If not, my suggestion to examine info.data is still a good one, I think.
UPDATE: I've just checked out this reverse function, which you may also find handy at some point:
function str2ab(buf) {
var encoder = new TextEncoder('utf-8');
return encoder.encode(buf).buffer;
}
Related
Salesforce, Locker: Cannot "createObjectURL" using a unsecure [object File]
I'm having some problem with a lightning component that was done by other developer that left the company, users are telling me that the tool was working perfectly 1 month ago but i don't have any idea of what is happening then The error is : This page has an error. You might just need to refresh it. Action failed: c:EMB_CCW_Panel$controller$onPickFile [Locker: Cannot "createObjectURL" using a unsecure [object File]!] Failing descriptor: {c:EMB_CCW_Panel$controller$onPickFile} and the javascript method is this one onPickFile : function(component, event, helper) { var catalog = component.get("v.catalogWrapper"); var brandsList = component.get("v.brandsList"); console.log("onPickFile", catalog); var file = event.target.files[0]; var fileURL = URL.createObjectURL(file); var req = new XMLHttpRequest(); req.open('GET', fileURL); req.onload = function() { URL.revokeObjectURL(fileURL); component.set("v.catalogWrapper", helper.fillCatalogWithXMLData(catalog, helper.extractSlideNotesFromODTContentXML(this.responseXML), brandsList)); }; req.onerror = function() { URL.revokeObjectURL(fileURL); console.log('Error loading XML file.'); }; req.send(); }, and the helper methods, extractSlideNotesFromODTContentXML : function(xmlDoc){ var output = []; var slides = xmlDoc.getElementsByTagName("draw:page"); for(var s=0;s<slides.length;s++){ var notes = slides[s].getElementsByTagName("presentation:notes")[0].getElementsByTagName("draw:frame")[0].getElementsByTagName("draw:text-box")[0].getElementsByTagName("text:p"); var slideNotesList = []; for(var i =0;i<notes.length;i++){ slideNotesList.push(notes[i].textContent); } output.push(slideNotesList); } return output; }, fillCatalogWithXMLData : function(catalog, slidesList, brandsList){ try { var referenceRegEX = /^(\d){9}/; for(var i=0;i<slidesList.length;i++){ catalog.slides.splice(i, 0, this.generateSlideObject(i+1)); for(var j=0;j<slidesList[i].length;j++){ var wholeLine = slidesList[i][j]; var firstWord = wholeLine.split(" ")[0].toUpperCase(); console.log('firstWord', firstWord) // Lines that begin with a number are references (SAP Id code). Consider the rest brand names: if(referenceRegEX.test(firstWord) && firstWord.length == 9){ catalog.slides[i].referencesText += wholeLine+"\n"; }else{ // That's not a reference, check if it's a brand: // 1.- Check if the whole line is a brand (removing leading and trailing spaces) if(brandsList.includes(wholeLine.trim())){ // Found brand: catalog.slides[i].brandsText += wholeLine + "\n"; }else{ // Not found, not recognized: catalog.slides[i].unrecognizedText += wholeLine + "\n"; } } } } component.set("v.catalogWrapper", catalog); } catch(err) { } return catalog; } anyone can't help me or tell me how can i fixe it ! thanks
If it used to work 1 month ago it's probably something Salesforce patched in Summer release. No idea what (if anything) is unsecure in your code but sounds like you're hit by Lightning Locker Service. Do you get same result in different browsers? See if it works if you knock back the API version of component to version 39. It's a hack but might be a temp relief while you figure out what to do. This suggests File is supported all right: https://developer.salesforce.com/docs/component-library/tools/locker-service-viewer Maybe you need to read the file's content different way, maybe you need to give up on parsing it with JavaScript and push to server-side apex? I don't know what your functionality is. If you go to setup -> lightning components -> debug mode and enable for yourself it might help a bit. You will see more human-friendly code generated in browser's developer tools, debugging might be simpler. Lesson learned would be to pay more attention to release preview windows (from ~September 12th we can preview Winter'21 release, SF should publish blog post about it in 1-2 weeks) This looks promising: https://salesforce.stackexchange.com/a/245232/799 Maybe your code needs proper Aura accessors, event.getSource().get("v.files")[0] instead of event.target.files[0]. You really would have to debug it and experiment in browser's console, see what sticks.
node.js - pngjs error: "Stream not writable" randomly
I am working with pngjs through many of it's methods. Most of the time, they work fine. However, like in the following example, I get an error: "Stream is not writable" var fs = require('fs'), PNG = require('pngjs').PNG; var dst = new PNG({width: 100, height: 50}); fs.createReadStream('http://1.1m.yt/hry7Eby.png') //download this picture in order to examine the code. .pipe(new PNG()) .on('parsed', function(data) { console.log(data); }); This case is not singular, I get this error on 1 random png image once a day, through all of pngjs methods, and that error obviously crashes my app. (note: you can't use the http link I gave you with a readStream, you will have to download & rename it and do something like): fs.createReadStream('1.png') Thank you for your time and effort.
This seems to be a bug in the library, though I'm wary of saying so as I'm no expert in PNGs. The parser seems to complete while the stream is still writing. It encounters the IEND, and so calls this: ParserAsync.prototype._finished = function() { if (this.errord) { return; } if (!this._inflate) { this.emit('error', 'No Inflate block'); } else { // no more data to inflate this._inflate.end(); } this.destroySoon(); }; If you comment out the this.destroySoon(); it finishes the image correctly, instead of eventually calling this function: ChunkStream.prototype.end = function(data, encoding) { if (data) { this.write(data, encoding); } this.writable = false; // already destroyed if (!this._buffers) { return; } // enqueue or handle end if (this._buffers.length === 0) { this._end(); } else { this._buffers.push(null); this._process(); } }; ...which would otherwise end up setting the stream.writeable to false, or, if you comment that out, to pushing a null value into the _buffers array and screwing up the ChunkStream._processRead. I'm fairly certain this is a synchronicity problem between the time the zlib parser takes to complete and the time the stream takes to complete, since if you do this synchronously it works fine: var data = fs.readFileSync('pic.png'); var png = PNG.sync.read(data); var buff = PNG.sync.write(png); fs.writeFileSync('out2.png', buff);
XML parsing syntax for OS X Yosemite JavaScript for Automation?
Has anyone deduced syntax which successfully loads XML from file/string and gives access to the data in OS X Yosemite (10.10) Javascript for Automation ? Documentation and code samples are still fairly thin (as of Nov 2014), and my inductive skills are running dry on three separate approaches to reading an XML (OPML) file at the moment: Most promising: $.NSXMLDocument Getting hold of the string data in various ways goes well, function readTextFromFile(strPath) { return $.NSString.stringWithContentsOfFile(strPath); } function readDataFromFile(strPath) { return $.NSData.alloc.initWithContentsOfFile(strPath); } function filePath(strPath) { return Path(strPath); } But no permutations on this theme have borne fruit: var strPath='/Users/houthakker/Desktop/notes-2014-11-04.opml', dataXML = readData(strPath), strXML = readTextFile(strPath), oXMLDoc1, oXMLDoc2; oXMLDoc1 = $.NSXMLDocument.alloc.initWithXMLString(strXML,0,null); oXMLDoc2 = $.NSXMLDocument.alloc.initWithData(dataXML,0,null); (the 'function undefined' error messages suggest that those two init functions may not be exposed, though initWithRootElement() does seem to be) Most progress: $.NSXMLParser var oParser = $.NSXMLParser.alloc.initWithData(dataXML); return oParser.parse; //true But event-driven parsing seems to require some further complexities which remain opaque to me, and which may not match my simple needs (reading and converting modestly sized local OPML files). Most familiar: Application("System Events") In Applescript this can be done with System Events code: set fOPML to (POSIX file "/Users/houthakker/Desktop/notes-2014-11-04.opml" as alias) as string tell application "System Events" tell XML file fOPML -- now access XML Elements by name or index end tell but I haven't found a successful javascript idiom for initializing the XMLFile object with any permutation of a unix Path(), string, or colon-delimited mac path string. Any thoughts or more successful experience here ?
This turns out to work for the (very slow executing) Application("System Events") route: var app = Application("System Events"), strPath = '~/Desktop/summarise.opml'; var oFile = app.xmlFiles[strPath], oRoot = oFile.xmlElements[0], oHead = oRoot.xmlElements.head, oBody = oRoot.xmlElements.body, lstOutlineXML = oBody.xmlElements.whose({ name: 'outline' }); And the function for initialising an NSXMLDocument from an XML string is, according to the JSExport convention (in which the letter following each ":" is capitalized, and then the ":"s are removed) .initWithXMLStringOptionsError() Thus, to choose a local OPML file and parse it to a simple JSON outline: function run() { var app = Application.currentApplication(); app.includeStandardAdditions = true; function readTextFromFile(strPath) { return $.NSString.stringWithContentsOfFile(strPath); } var strPath = ( app.chooseFile({withPrompt: "Choose OPML file:"}) ).toString(), // Path → String strXML = strPath ? readTextFromFile(strPath) : ''; if (!strXML) return; var oXMLDoc1 = $.NSXMLDocument.alloc.initWithXMLStringOptionsError(strXML, 0, null), oRoot = oXMLDoc1.rootElement, oBody = ObjC.unwrap(oRoot.children)[1], lstOutline = ObjC.unwrap(oBody.children), lstParse, strJSON; function parseOPML(lst) { var lstParse=[], oNode, dctNode, lstChiln; for (var i = 0, lng=lst.length; i<lng; i++) { oNode = lst[i]; dctNode = {}; dctNode.txt = ObjC.unwrap(oNode.attributeForName('text').stringValue); lstChiln = ObjC.unwrap(oNode.children); if (lstChiln && lstChiln.length) dctNode.chiln = parseOPML(lstChiln); lstParse.push(dctNode); } return lstParse; } lstParse = parseOPML(lstOutline); strJSON = JSON.stringify(lstParse,null, 2); app.setTheClipboardTo(strJSON); return strJSON; }
Error when decoding base64 with buffer. First argument needs to be a number
I am working on running different encoding statements based on the URL. My code: var parsedUrl = url.parse(req.url, true); var queryAsObject = parsedUrl.query; var myString = queryAsObject["string"]; var myFunction = queryAsObject["function"]; if (myFunction == "encodeb64") { var bufEncode = new Buffer(JSON.stringify(myString)); var myEncode = bufEncode.toString('base64'); console.log(myEncode); } else { console.log("Error1"); }; if (myFunction == "decodeb64") { // var bufDecode = new Buffer(myEncode, 'base64'); // var myDecode = bufDecode.toString('utf8'); var myDecode = new Buffer(myEncode, 'base64').toString('utf8'); console.log(myDecode); } else { console.log("Error2"); }; URL used: http://127.0.0.1:8020/?string=text&function=decodeb64 The issue is that I am having is with the last if statement. If its looking for decodeb64 and the first statement is looking for encodeb64 it crashes when function=decodeb64 is in the URL. If both if statements are looking for either encodeb64 or decodeb64, it runs perfectly. It also works if function=encodeb64 is in the URL. The error message I get is: buffer.js:188 throw new TypeError('First argument needs to be a number, ' + ^ It points to: var myDecode = new Buffer(myEncode, 'base64').toString('utf8'); The given number on the error is pointed to the n in new. I have located the problem to be inside the decode if statement by moving and reversing the order on the code. As you can see in my code notes, I have tried two different methods of decoding with no success.
The reason that it crashes I believe is that when function=decode64, the variable myEncode is not declared and initialized, as the if(myFunction=="encode64") block is not run. So when the code tried to new Buffer(myEncode...) it would fail as myEncode is undefined. I think you meant to code : var myDecode = new Buffer(myString, ...) instead
MongoDB JavaScript Yield large set of results
I'm trying to query a large set of results from a MongoDB over Python. I do this via JavaScript, because I want to get something like the grandchildren in a tree-like structure. My code looks like the following: col = db.getCollection(...) var res = new Array(); col.find( { "type" : ["example"] } ).forEach( function(entry) { v1 = col.find( {"_id" : entry["..."]} ) ... (walk through the structure) ... vn = ... res.push([v1["_id"], vn["data"]]); } ); return res; Now, I'm having the problem, that the resulting array becomes very (too) large and the memory gets exceeded. Is there a way, to yield the results instead of pushing them into an array?
Alright, I think I know, what you mean. I created a structure like the following: var bulksize = 1000; var col = db.getCollection(".."); var queryRes = col.find( { ... } ) process = function(entity) { ... } nextEntries = function() { var res = new Array(); for(var i=0; i<bulksize; i++) { if(hasNext()) res.push(process(queryRes.next())); else break; } return res; } hasNext = function() { return queryRes.hasNext(); } The script separates the results into bulks of 1000 entries. And from Python side eval the noted script and then I do the following: while database.eval('hasNext()'): print "test" for res in database.eval('return nextEntries()'): doSth(res) The interesting thing is, that the console always says: test test test test test test Then I get the error: pymongo.errors.OperationFailure: command SON([('$eval', Code('return nextEntries()', {})), ('args', ())]) failed: invoke failed: JS Error: ReferenceError: nextEntries is not defined nofile_a:0 This means, that the first calls of nextEntries() work, but then the function is not there, anymore. Could it be, that MongoDB does something like a clearing of the JavaScript cache? The problem does not depend on the bulksize (tested with 10, 100, 1000, 10000 and always the same result).
Alright, I found a line in the source code of MongoDB, which clears all JavaScripts that are used more than 10 times. So if no changes on the database server are wanted, it is necessary to query the database multiple times and send bulks to the client by selecting amounts of items with help of the skip() and limit() functions. This works surprisingly fast. Thanks for your help.