Firebase "MD5" & BloddyCrytpo's dont match - actionscript-3

I'm trying to do a check to see if the user has a local file. If the user does, I get bloodycrypto to make a md5 out of it. Then I compare the two values. One from the firebase file's metadata and the other from the byte array of the file digested. They never match. Does Firebase do something different when trying to generate the md5 of a file I upload?
private function handleMetaSuccess(e:StorageReferenceEvent):void
{
trace("Meta succes for reference:" + this.name);
storageMetaData = e.metadata;
trace("reading file.");
fileBA = new ByteArray();
var fs:FileStream = new FileStream();
fs.open(Definitions.CACHE_DIRECTORY.resolvePath(name + ".jpg"), FileMode.READ)
fs.readBytes(fileBA);
fs.close();
var byteHash:String = MD5.hashBytes(fileBA)
trace("Local hash = " + byteHash); //93b885adfe0da089cdf634904fd59f71
trace("Network hash = " + storageMetaData.md5Hash); //bo7XPotC+T5wmAcpagnXBw==
if (byteHash != storageMetaData.md5Hash)
{
trace("Not equal. Getting file."); //Always happens
getFile();
}
else
{
loadFile();
}
}
Upon closer inspetion (thanks to Organis) firebase doesn't return a proper MD5. What is it? In my storage consol I don't see an md5 property, so is this autogenerated? The files were uploaded through my rest API based off phantom's guide.
Update: Following Organis' comment about the way Firebase handle's MD5s
var byteHash:ByteArray = new ByteArray();
byteHash.writeUTFBytes(MD5.hashBytes(fileBA));
var byteHashWithLength:ByteArray = new ByteArray();
byteHashWithLength.writeUTF(MD5.hashBytes(fileBA));
trace("Bytehash with length = " + Base64.encode(byteHashWithLength)); //ACAyMTMzYTdmYjczYTEzZDQ3ZDkzMTEyY2I1OWQyYTBmMg==
trace("Plain = " + Base64.encode(byteHash)); //OTNiODg1YWRmZTBkYTA4OWNkZjYzNDkwNGZkNTlmNzE=
trace("Storage md5 = " + storageMetaData.md5Hash); //UsoNl5sL1+aLiAhTOTBXyQ==
Trying to take the md5 I get and turn it into base64 results in consistent mismatching results. Is there an argument I am missing or applying incorrectly when I try to decode everything?

...So I would do something like
var storageHash:String = Base64.decode(storageMetaData.md5Hash).toString();
to follow your example right?
Try this code below to get your storageMetaData.md5Hash correctly decoded from Base64 :
Let me know result of trace("storage hash : " + storageHash); to check if you're getting an (expected) sequence of 32 hex values.
private function handleMetaSuccess(e:StorageReferenceEvent):void
{
trace("Meta succes for reference:" + this.name);
storageMetaData = e.metadata;
trace("reading file.");
fileBA = new ByteArray();
var fs:FileStream = new FileStream();
fs.open(Definitions.CACHE_DIRECTORY.resolvePath(name + ".jpg"), FileMode.READ)
fs.readBytes(fileBA);
fs.close();
var byteHash:String = MD5.hashBytes(fileBA); //Local hash
var ba_storageHash:ByteArray = new ByteArray();
ba_storageHash = Base64.decode(storageMetaData.md5Hash); //update ByteArray
var storageHash:String = bytesToHexString(ba_storageHash); //Hex values of bytes shown as String
trace("Network hash : " + storageMetaData.md5Hash); //bo7XPotC+T5wmAcpagnXBw==
trace("Local hash : " + byteHash); //93b885adfe0da089cdf634904fd59f71
trace("storage hash : " + storageHash); //what is result??
if (byteHash != storageHash)
{
trace("Not equal. Getting file."); //Always happens
getFile();
}
else
{
loadFile();
}
}
// # Byte values (Hex) shown as (returned) String type
private function bytesToHexString(input:ByteArray) : String
{
var strOut:String = ""; var strRead:String = "";
input.position = 0;
var intBASize:uint = input.length;
for (var i:int = 0; i < intBASize; i++)
{
strRead = input.readUnsignedByte().toString(16);
if(strRead.length < 2) { strRead = "0" + strRead; } //# do padding
strOut += strRead ;
}
return strOut.toLowerCase(); //strOut.toUpperCase();
}

Related

Hash txt strings in GAS, incorrect line ending

I want hash (md5) some txt strings in GAS, and have a problem, may be
incorrect line ending.
Example:
test
test
correct hash 76ce9f441de2ed5de337d391ad4516b7
using GAS i getting wrong hash: e8230113fbba92427c1c41cf34a80c13
function test() {
var data = 'test\
test';
Logger.log(data.MD5());
return (data.MD5());
}
String.prototype.MD5 = function(charset, toByte) {
charset = charset || Utilities.Charset.UTF_8;
var digest = Utilities.computeDigest(Utilities.DigestAlgorithm.MD5, this, charset);
if (toByte) return digest;
var __ = '';
for (i = 0; i < digest.length; i++) {
var byte = digest[i];
if (byte < 0) byte += 256;
var bStr = byte.toString(16);
if (bStr.length == 1) bStr = '0' + bStr;
__ += bStr;
}
return __;
}
As already #Ameen mentioned you are checking different strings
function test(){
var s1 = 'test\ntest';
var s2 = 'test\r\ntest';
Logger.log(s1.MD5() === '76ce9f441de2ed5de337d391ad4516b7');
Logger.log(s2.MD5() === '76ce9f441de2ed5de337d391ad4516b7');
}
[19-03-22 18:03:11:441 MSK] false
[19-03-22 18:03:11:442 MSK] true
A string containing "\r\n" for non-Unix platforms, or a string containing "\n" for Unix platforms.
It seems you're working under Windows.

How can I order my string in as3

A complex question :
I've got this code (not the complete code, but the essentials for the question, I think) :
var $pmm:String;
var $pms:String;
var $bmm:String;
var $bms:String;
function get haute1():String { return $pmm; };
function get haute2():String { return $pms; }
function get basse1():String { return $bmm; };
function get basse2():String { return $bms; };
accueil.todayHaute_txt.htmlText = haute1;
accueil.todayBasse_txt.htmlText = basse1;
accueil.todayHauteSecond_txt.htmlText = haute2;
accueil.todayBasseSecond_txt.htmlText = basse2;
"haute1" is an hour (in 24h format). Something like "13h25".
It changes everyday.
Question : How can put them in ascending order in AS3 ?
Example : If haute1 = 15h20, haute2= 6h00, basse1= 11h and basse2 = 17h, the function would put them in this order :
"haute2", then "basse1", then "haute1" and finally "basse2".
Thx
EDIT
I add this code that I have. is it helping you ?
/ Assigns hours and tidal heights
$pmm = convdateheure($tpbs[1 + $deltapm]);
$pms = convdateheure($tpbs[3 + $deltapm]);
$bmm = convdateheure($tpbs[2 - $deltapm]);
$bms = convdateheure($tpbs[4 - $deltapm]);
function convdateheure($valeur:Number):String
{
var $heure:Number = Math.floor($valeur);
var $minute:Number = Math.floor(Math.floor(($valeur - Math.floor($valeur)) * 100) * 0.6);
var hoursLabel:String = "", minsLabel:String = "";
if ($heure == 24) $heure = 0; // Check if at the 24 hour mark, change to 0
if ($heure < 10) hoursLabel += "0" + $heure.toString(); else hoursLabel = $heure.toString();
if ($minute < 10) minsLabel += "0" + $minute.toString(); else minsLabel = $minute.toString();
return hoursLabel + ":" + minsLabel;
}
If you want to order some dates written in some String format:
One way would be, depending on you date string format, just to push them into array and sort them as strings, then read them all.
Another way would be to first parse those strings into Date instances, and push their Date.time property to array, sort it, then do reverse: parse all time values from sorted array into new Date instances then use Date.toString or similar.
Assuming that $valuer is a numerical value:
var timesArray:Array = new Array();
var convertedTimesArray:Array = new Array();
function sortTimes():void{
timesArray.push($valuer);
timesArray.sort(Array.NUMERIC);
}
function convertTimes():void{
convertedTimesArray = []; // clear the array
for (var i:int = 0; i < timesArray.length; i++){
var s:String = convdateheure(timesArray[i]);
convertedTimesArray.push(s);
}
}
That should give you one array of actual times, sorted in numerical order, and one array sorted in the same numerical order, but converted to String values using your function.

Render json string from controller to mvc view

My json string is coming as follows:
"[{\"StartTime\":\"09:00\",\"Dates\":\"05-28-2015\",\"Code\":\"DF\",\"LocationCode\":\"NY\"},{\"StartTime\":\"09:30\",\"Dates\":\"05-28-2015\",\"Code\":\"DF\",\"LocationCode\":\"NY\"},{\"StartTime\":\"10:00\",\"Dates\":\"05-28-2015\",\"Code\":\"DF\",\"LocationCode\":\"NY\"},{\"StartTime\":\"10:30\",\"Dates\":\"05-28-2015\",\"Code\":\"DF\",\"LocationCode\":\"NY\"},{\"StartTime\":\"11:30\",\"Dates\":\"05-28-2015\",\"Code\":\"DF\",\"LocationCode\":\"NY\"}]"
I need to parse this json string on view and show the data in a table.
I am new to json. Any help will be really appreciated. Thanks.
$("#divLoad").load("GetAvailableTimeSlots?strProvider=" + provider + "&strFrom=" + from, function (data) {
var newStr = data.replace('"[', '').replace(']"', '').replace('[', '').replace(']', '');
var dataArr = newStr.split('},{');
var jsonArr = new Array(dataArr.length);
for (var i = 0; i < dataArr.length; i++) {
dataArr[i] = '{' + dataArr[i] + '}';
var dataElem = dataArr[i].replace('{{', '{').replace('}}', '}');
var jsonElem = "'" + dataElem + "'";
jsonArr[i] = JSON.parse(jsonElem);
}
$(this).html(jsonArr);
});
If you are using jQuery, you can use the jQuery.parseJSON() method.
http://api.jquery.com/jquery.parsejson/
Just call JSON.parse(data) and manipulate the javascript object instead of performing error-prone string manipulation.
function (data) {
var locations = JSON.parse(data);
var table = $("<ul>");
for (var i = 0; i < locations.length; i++) {
var row = $("<li>").text(locations[i].StartTime + " " + locations[i].Dates + " " ...);
table.append(row);
}
$("#divLoad").empty().append(table); // $(this) won't work
}
This example is using an unordered list but you can easily replace this with table markup.
Here's what it looks like in Chrome dev tools with console.log(locations) after parsing:

How to get byteArray or base64 string from RenderTexture Cocos2d-JS

I am making a game on cocos2d-JS for facebook in which there is a requirement of sharing a screenshot of the game.
I am able to take the screenshot but now I am unable to upload it in the Parse.com server because it requires base64 format or byte array. I am unable to find any solution of converting Sprite in to this format.. Here's my code so result when I do addchild its coming proper .. I have also added my commented code so that it will help to understand that I have tried lot of things but couldnt achieve the same.
shareToSocialNetworking: function () {
cc.director.setNextDeltaTimeZero(true);
var newsize = cc.director.getVisibleSize();
var renderText = new cc.RenderTexture(newsize.width,newsize.height);
renderText.begin();
cc.director.getRunningScene().visit();
renderText.end();
var result = cc.Sprite.create(renderText.getSprite().getTexture());
result.flippedY = true;
this._mainViewNode.addChild(result,6000);
//renderText.saveToFile("screenshot.jpg",cc.IMAGE_FORMAT_PNG);
//var based = renderText.getSprite().getTexture().getStringForFormat().toString();
//var data = based.getData();
var file = new Parse.File("screen.jpg", { base64: this.getBase64(result) });
//var file = new Parse.File("screen.jpg", data, "image/png");
var self = this;
file.save().then(function() {
// The file has been saved to Parse.
alert(file.url);
this.onSharePictureInfoLink(file.url());
}, function(error) {
// The file either could not be read, or could not be saved to Parse.
});
//
//var ccImage = renderText.newCCImage();
//
//var str = ccImage.getData();
},
is there any workaround that can be done
there is a private variable called _cacheCanvas, which is the instance of the offscreen canvas
you can simply do renderText._cacheCanvas.toDataURL()
Here's how you can take the screnshot from cocos2d-JS
screenshot: function (fileName) {
var tex = new cc.RenderTexture(winSize.width, winSize.height, cc.Texture2D.PIXEL_FORMAT_RGBA8888);
tex.setPosition(cc.p(winSize.width / 2, winSize.height / 2));
tex.begin();
cc.director.getRunningScene().visit();
tex.end();
var imgPath = jsb.fileUtils.getWritablePath();
if (imgPath.length == 0) {
return;
}
var result = tex.saveToFile(fileName, cc.IMAGE_FORMAT_JPEG);
if (result) {
imgPath += fileName;
cc.log("save image:" + imgPath);
return imgPath;
}
return "";
}
then make a Java call from Javascript
public static void ScreenShot()
{
Bitmap imageBitmap = BitmapFactory.decodeFile(Cocos2dxHelper.getCocos2dxWritablePath() + "/" + "screenshot.png");
String fileHolder = "SampleFolder";
File filepathData = new File("/sdcard/" + fileHolder);
//~~~Create Dir
try {
if (!filepathData.exists())
{
filepathData.mkdirs();
filepathData.createNewFile();
FileWriter fw = new FileWriter(filepathData + fileHolder);
BufferedWriter out = new BufferedWriter(fw);
String toSave = String.valueOf(0);
out.write(toSave);
out.close();
}
}
catch (IOException e1) {
}
//~~~Create Image
File file = new File("/sdcard/" + "Your filename");
try
{
file.createNewFile();
FileOutputStream ostream = new FileOutputStream(file);
imageBitmap.compress(CompressFormat.PNG, 100, ostream);
ostream.close();
}
catch (Exception e) {}
Uri phototUri = Uri.fromFile(file);
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_STREAM, phototUri);
//~~~Add Code Below
}
Do not forget to add permission for external storage

AS3 load variables from a txt file which has && formatting

I'm trying to load a txt file of variables into my AS3 project. The problem I have though seems to be down to the fact that the txt file (which is pre formatted and cannot be changed) is formatted using double amphersands... e.g.
&name=mark&
&address=here&
&tel=12345&
I'm using the following code to load the txt file
myLoader.addEventListener(Event.COMPLETE, onLoaded, false, 0, true);
myLoader.dataFormat = URLLoaderDataFormat.VARIABLES;
urlRqSend = new URLRequest(addressToTxt.txt);
public function onLoaded(e:Event):void {
trace(myLoader.data);
}
Using URLLoaderDataFormat.VARIABLES generates the following error:
Error: Error #2101: The String passed to URLVariables.decode() must be a URL-encoded query string containing name/value pairs.
If I use URLLoaderDataFormat.TEXT I can load the data successfully but I'm not able (or don't know how to) access the variables.
Would anyone have any ideas or work arounds to this please.
Thanks,
Mark
I had that kind of problem some time ago.
I suggest you to load first as a text, remove those line breaks, the extra amphersands and parse manually:
var textVariables:String;
var objectVariables:Object = new Object();
...
myLoader.addEventListener(Event.COMPLETE, onLoaded, false, 0, true);
myLoader.dataFormat = URLLoaderDataFormat.TEXT;
urlRqSend = new URLRequest(addressToTxt.txt);
public function onLoaded(e:Event):void {
textVariables = myLoader.data;
textVariables = textVariables.split("\n").join("").split("\r").join(""); // removing line breaks
textVariables = textVariables.split("&&").join("&"); // removing extra amphersands
var params:Array = textVariables.split('&');
for(var i:int=0, index=-1; i < params.length; i++)
{
var keyValuePair:String = params[i];
if((index = keyValuePair.indexOf("=")) > 0)
{
var key:String = keyValuePair.substring(0,index);
var value:String = keyValuePair.substring(index+1);
objectVariables[key] = value;
trace("[", key ,"] = ", value);
}
}
}
I wrote that code directly here, I don't have any AS3 editor here, so, maybe you'll find errors.
If you have data in String and it has a structure just like you wrote, you can do a workaround:
dataInString = dataInString.split("\n").join("").split("\r").join(""); // removing EOL
dataInString = dataInString.slice(0,-1); // removing last "&"
dataInString = dataInString.slice(0,1); // removing first "&"
var array:Array = dataInString.split("&&");
var myVariables:Object = new Object();
for each(var item:String in array) {
var pair:Array = item.split("=");
myVariables[pair[0]] = pair[1];
}
That should make you an object with proper variables.