I retrieve an encoded string (using TextEncoder into UTF-8, which was stringified before sending to the server) from the server using AJAX. I parse it upon retrieval and get an Object. I need to convert this Object to a decoded string. TextDecoder seems to have decode method, but it expects ArrayBuffer or ArrayBufferView, not Object. That method gives TypeError if I use my Object as-is:
var myStr = "This is a string, possibly with utf-8 or utf-16 chars.";
console.log("Original: " + myStr);
var encoded = new TextEncoder("UTF-16").encode(myStr);
console.log("Encoded: " + encoded);
var encStr = JSON.stringify(encoded);
console.log("Stringfied: " + encStr);
//---------- Send it to the server; store in db; retrieve it later ---------
var parsedObj = JSON.parse(encStr); // Returns an "Object"
console.log("Parsed: " + parsedObj);
// The following decode method expects ArrayBuffer or ArrayBufferView only
var decStr = new TextDecoder("UTF-16").decode(parsedObj); // TypeError
// Do something with the decoded string
This SO 6965107 has extensive discussion on converting strings/ArrayBuffers but none of those answers work for my situation. I also came across this article, which does not work if I have Object.
Some posts suggest to use "responseType: arraybuffer" which results in ArrayBuffer response from the server, but I cannot use it when retrieving this encoded string because there are many other items in the same result data which need different content-type.
I am kind of stuck and unable to find a solution after searching for a day on google and SO. I am open to any solution that lets me save "strings containing international characters" to the server and "retrieve them exactly as they were", except changing the content-type because these strings are bundled within JSON objects that carry audio, video, and files. Any help or suggestions are highly appreciated.
Related
Having a base64 string encoded JSON like object coming from a python API, what is the correct way to decode and parse the encoded JSON in javascript?
Python makes it a byte string literal by adding b prefix and additional apostrophes.
I have written the following function using Buffer.from and buf.toString methods, which is working fine, but the problem is, the string I receive from the API has b'<encoded-string>' format. With the initial b and the apostrophes(').
const decodedObject: {
foo?: string;
} = JSON.parse(
Buffer.from(encodedString.replace("b'", '').replace("'", ''), 'base64').toString(),
);
atob and btoa seems deprecated I as understand from the warning in my IDE. That's why I used Buffer methods
So, my question is: Removing those apostrophes and b manually didn't feel right. Is there something I might be missing?
For example creating the encoded base64 in python:
>>> import base64
>>> "https://example.com?encoded={}".format(base64.b64encode(str({"foo":"bar"}).encode('utf-8')))
"https://example.com?encoded=b'eydmb28nOiAnYmFyJ30='"
In order to decode that base64 in javascript, I need to first remove those prefix and apostrophes.
> console.log(atob('eydmb28nOiAnYmFyJ30='))
{'foo': 'bar'}
The problem here is that your Python code is pretending strings are JSON, instead of actually using the json library to generate proper JSON.
So, let's fix that:
import base64
import json
data = { "foo": "bar" }
encoded_value = base64.b64encode(json.dumps(data))
url = f"https://example.com?encoded={encoded_value}"
And done, the encoded URL query argument is now a normal, trivially decoded value on the JS side, because we're guaranteed that it's proper JSON, just base64 encoded.
Which means that in order to unpack that on the JS side, we just run through the obvious steps:
get the query value,
decode it,
parse it as JSON
So:
// I have no idea if you're running Node, a browser, Deno, etc.
// so substitute window.location or your framework's path object.
const url = new URL(request.path)
// get the encoded value
const query = new URLSearchParams(url.search)
const encoded = query.get(`encoded`)
// turn it back into a JSON string and parse that
const decoded = base64Decode(encoded); // again, no idea where you're running this.
try {
const unpacked = JSON.parse(decoded);
console.log(unpacked); // { foo: "bar" }
} catch (e) {
// ALWAYS run JSON.parse in a try/catch because it can, and will, throw.
}
Noting that that base64Decode(encoded) is a stand-in for whatever base64 library you're using.
I'm using the following method to convert files into base64 encoding and it's been working fine for a long time, but I see now that Buffer is depricated.
// function to encode file data to base64 encoded string
function base64_encode(file) {
var bitmap = fs.readFileSync(file);
// convert binary data to base64 encoded string
return new Buffer(bitmap).toString("base64");
}
let base64String = base64_encode("Document.png");
Can someone please help me modify this to work with the new suggested method as I'm not sure how to modify it myself?
Thank you so much in advance.
It is not Buffer that is deprecated but its constructor, so instead of new Buffer() you use e.g. Buffer.from.
However fs.readFileSync already returns a Buffer if no encoding is specified, so there is not really a need to pass that to another buffer. Instead you can do return fs.readFileSync(file).toString("base64")
Using the Sync part of the API is most of the time something would like to avoid and if possible switch over to the promise-based API.
Recently I played with websocket and it works great,
in the client side with onmessage(evt) function, I received a message from the server side,
the message is actually a JSON format like this:
{"Properties":{"name":"0a67d327-1f78-475e-b58a-d16706782223","publicname":"Page1"}}
then in the client side(html5 with javascript) I access the data using:
var page=evt.data;
then I access the JSON object
document.getElementById('name').innerHTML=page.Properties.name;
but it just won't work, I even use the eval function but it still doesn't work,
I did check the page by using alert(page);
I wonder if the evt.data is not a string data but a byte,
anyone have a solution for converting byte to string?
or any other solution that may have something to do with this evt.data
WebSocket data is either string, Blob, or ArrayBuffer. In your case it is most likely a string so you need to parse it first:
var page = JSON.parse(evt.data);
console.log("Properties.name: " + page.Properties.name);
I am using ExternalInterface in Flex to retrieve AMF encoded string from Javascript. The problem is the AMF encoded string sometimes contains \u0000 which causes the ExternalInterface to return null instead of the encoded string from Javascript.
Any idea how to solve this?
Thanks in advance.
The \0000 is falsely interpreted as EOF when reading external data. The same thing happens when it appears in XML files, as well.
You should be able to replace it with an unambiguous character sequence before passing the string to Flash, and back upon reception in ActionScript. In the JavaScript function, use something like
return returnString.replace (/\0000/g, "{nil}");
This should remove the unwanted \0000 characters from the string before returning it to Flash.
On the Flash side, use
receiveString = receiveString.replace (/\{nil\}/g, "\u0000");
directly after receiving the data.
Encoding the pyamf AMF output to base64 will do the trick.
Here is the encoding part in python:
encoder = pyamf.get_encoder(pyamf.AMF3)
encoder.writeObject(myObject)
encoded = base64.b64encode(encoder.stream.getvalue())
Here is the decoding part in AS3:
var myDecoder:Base64Decoder = new Base64Decoder();
myDecoder.decode(base64EncodedString);
var byteArr:ByteArray = myDecoder.toByteArray()
byteArr.position = 0;
var input:Amf3Input = new Amf3Input();
input.load(byteArr);
var test:MyObject = input.readObject();
I am working on my open source project Downloadify, and up until now it simply handles returning Strings in response to ExternalInterface.call commands.
I am trying to put together a test case using JSZip and Downloadify together, the end result being that a Zip file is created dynamically in the browser, then saved to the disk using FileReference.save. However, this is my problem:
The JSZip library can return either a base64 encoded string of the Zip, or the raw byte string. The problem is, if I return that byte string in response to the ExternalInterface.call command, I get this error:
Error #1085: The element type "string" must be terminated by the matching end-tag "</string>"
ActionScript 3:
var theData:* = ExternalInterface.call('Downloadify.getTextForSave',queue_name);
Where queue_name is just a string used to identify the correct instance in JS.
JavaScript:
var zip = new JSZip();
zip.add("test.txt", "Hello world!\n");
var content = zip.generate(true);
return content;
If I instead return a normal string instead of the byte string, the call works correctly.I would like to avoid using base64 as I would have to include a base64 decoder in my swf which will increase its size.
Finally: I am not looking for a AS3 Zip generator. It is imperative to my project to have that part run in JavaScript
I am admittedly not a AS3 programmer by trade, so if you need any more detail please let me know.
When data is being returned from javascript calls it's being serialized into an XML string. So if the "raw string" returned by JSZip will include characters which make the XML non-valid, which is what I think is happening here, you'll get errors like that.
What you get as a return is actually:
<string>[your JSZip generated string]</string>
Imagine your return string includes a "<" char - this will make the xml invalid, and it's hard to tell what character codes will a raw byte stream translate too.
You can read more about the external API's XML format on LiveDocs
i think the problem is caused by the fact, that flash expects a utf8 String and you throw some binary stuff at it. i think for example 0x00FF will not turn out to be valid utf8 ...
you can try fiddling around with flash.system::System.setCodePage, but i wouldn't be too optimistic ...
i guess a base64 decoder is probably really the easiest ... i'd rather worry about speed than about file size though ... this rudimentary decoder method uses less than half a K:
public function decodeBase64(source:String):ByteArray {
var ret:ByteArray = new ByteArray();
var map:Object = new Object();
var i:int = 0;
for each (var char:String in "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split("")) map[char] = i++;
map["="] = 0;
source = source.split("\n").join("").split("\r").join("");//remove linebreaks
for (i = 0; i < source.length/4; i++) {
var buf:int = 0;
for each (char in source.substr(i * 4, 4).split("")) buf = (buf << 6) + map[char];
ret.writeByte(buf >>> 16);
ret.writeShort(buf);
}
return ret;
}
you could simply shorten function names and take a smaller image ... or use ColorTransform or ConvolutionFilter on one image instead of four ... or compile the image into the SWF for smaller overall size ... or reduce function name length ...
so unless you're planning on working with MBs of data, this is the way to go ...