Archive for the ‘javascript’ Category

JavaScript MD5 hash for air.FileStream

This is the MD5 file hash used in progTools.

You can copy and paste the code below or get it via. bitbucket.

The code builds upon Paul Johnston’s MD5 implementation and you’ll need to include his code first.

<!-- Paul Johnston's MD5 implementation -->
<script type="text/javascript" src="tools/md5/md5.js"></script>

<!-- Additional MD5 functions for working on air.FileStream; requires Paj's md5.js -->
<script type="text/javascript" src="tools/md5/md5_file.js"></script>

core_md5_ex() is a modified/hacked version of the original core_md5() to allow for progressively processing chunks of data, instead of doing it all in one go.

// modified version of Paul Johnston's MD5 implementation
function core_md5_ex(x, len, abcd_start, append_padding, total_len)
{
/* append padding */
if (append_padding) {
    x[len >> 5] |= 0x80 << ((len) % 32);
    x[(((len + 64) >>> 9) << 4) + 14] = total_len*8;
}

var a = abcd_start[0];
var b = abcd_start[1];
var c = abcd_start[2];
var d = abcd_start[3];

for(var i = 0; i < x.length; i += 16)
{
var olda = a;
var oldb = b;
var oldc = c;
var oldd = d;

a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819);
b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426);
c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416);
d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682);
d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329);

a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
c = md5_gg(c, d, a, b, x[i+11], 14, 643717713);
b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083);
c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438);
d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501);
a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473);
b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);

a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562);
b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353);
c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174);
d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189);
a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
c = md5_hh(c, d, a, b, x[i+15], 16, 530742520);
b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);

a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415);
c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571);
d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359);
d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649);
a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259);
b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);

a = safe_add(a, olda);
b = safe_add(b, oldb);
c = safe_add(c, oldc);
d = safe_add(d, oldd);
}

return Array(a, b, c, d);
}

What’s changed is:

  • We pass in the starting values (which is the current hash on the data thus far, minus the necessary padding)
  • We use a variable to determine whether or not to append padding to the input; this is only done when processing the last block on data read from the stream.

hex_md5_stream() is the function which processes the stream: reading in chunks, transforming the bytes in inBytes into an array 4-byte WORDs, and calling core_md5_ex() with the necessary data.

function hex_md5_stream(inStream)
{
    
var abcd_start = new Array();
    abcd_start.push(1732584193);
    abcd_start.push(-271733879);
    abcd_start.push(-1732584194);
    abcd_start.push(271733878);
    
    
var inBytes = new air.ByteArray();
    
var appendPaddingToBlock = false;
    
var totalLen = 0;
    
    
while (inStream.bytesAvailable > 0)
    {
        inStream.readBytes(inBytes, 0, Math.min(8192, inStream.bytesAvailable));        
        
if(inBytes.length < 8192)
        {
            appendPaddingToBlock =
true;
        }
        
        totalLen += inBytes.length;
        
        bin =
new Array();
        
for(var i = 0; i < inBytes.length * 8; i+=8)
            bin[i>>5] |= (inBytes[i>>3] & 0xff) << (i%32);
        
        abcd_start = core_md5_ex(bin, inBytes.length*8, abcd_start, appendPaddingToBlock, totalLen);
        inBytes.clear();
    }
    
    
return binl2hex(abcd_start);    
}

Here’s the top-level view of how it works:

var inStream = new air.FileStream();
                
var file = new air.File();
file.url =
"file:///" + filename;                

inStream.open(file, air.FileMode.READ);
var md5result = hex_md5_stream(inStream);                 
inStream.close();             

Cloning and changing the TYPE attribute of an INPUT element

Cool snippet I found here, which was helpful in building Ekkio’s login forms.

ekkio login form

Notice that the password field is really a text field when the page loads – it does not mask characters. However, once the the field has focus and the user beings typing his password, masking is expected, so the field is transformed into a password field. This is trickier than it sounds because you can’t change the type attribute of an input element.

A possible solution is to clone the input element, then change the type attribute of the clone.

var clone = $('#login_field_password').clone(); clone.attr('type', 'password'); clone.attr('id', 'new_login_field_password'); clone.insertBefore($('#login_field_password')); $('#login_field_password').remove(); clone.attr('id', 'login_field_password'); $('#login_field_password').val(''); $('#login_field_password').css('color', '#000'); $('#login_field_password').focus();

You clone the field, change the type attribute of the clone, then delete the original. Unfortuantely, this doesn’t work in IE, as even changing the type attribute of a clone is not allowed. The only solution I’ve found so far is to clone manually by actually writing the HTML markup with the new type:

var clone = $('<input id="new_login_field_password" name="password" type="password" />');

This works but it’s not as versatile. The revised code is shown below.

var clone = $('<input id="new_login_field_password" name="password" type="password" />'); clone.attr('id', 'new_login_field_password'); clone.insertBefore($('#login_field_password')); $('#login_field_password').remove(); clone.attr('id', 'login_field_password'); $('#login_field_password').val(''); $('#login_field_password').css('color', '#000'); $('#login_field_password').focus();

XML DOM object to string conversion

One of those simple things which has eluded me for far too long. I finally found the solution here:

var string = (new XMLSerializer()).serializeToString(xmlobject); alert(string);

While the above is good to know, I’ve also discovered I don’t need it. I was looking to convert an XML DOM object, from an AJAX call, to plain text, but the XMLHttpRequest.responseText property provides just that. For jQuery users like myself, the XMLHttpRequest can be access via a synchronous jQuery.ajax call as the return value, or asynchronously via. the jQuery.ajax.complete callback or the jQuery.ajax.success callback (as of jQuery 1.4 the XMLHttpRequest object is now the third parameter).

Preloading multiple images in javascript

I needed to preload a set of images for a nav. menu using javascript. I googled “javascript preload” and found a few sites with examples. I followed the examples and adapted the code to my problem… it didn’t work.

You’ll find many sites that have examples for how to preload a set of images in javascript, such as this one, this one, this one, etc… They all basically have the same code, which as far as I can tell doesn’t work because they all have the same simple mistake.

Here’s my code after following the examples from these sites:

function preloadMenuImages()
{
pl =
new Image();
imgurl =
new Array();
imgurl[0] =
"images/nav_products_highlight.jpg";
imgurl[1] =
"images/nav_services_highlight.jpg";
imgurl[2] =
"images/nav_location_highlight.jpg";
imgurl[3] =
"images/nav_about_highlight.jpg";
imgurl[4] =
"images/nav_contact_highlight.jpg";

var i=0;
for(i=0; i<5; i++)
{
pl.src = imgurl[i];
}
}

I tested with IE7 and after the browser executes this code, the only image preloaded is the one referred to by imgurl[4], the last element in the array. I loaded the page with IE6 and Firefox 2, and it was obvious that the preload function didn’t work in these browsers either.

It seems that simply assigning to the src member doesn’t load the image. You actually have to create an Image object then assign to the src member. So the correct code is:

function preloadMenuImages()
{
imgurl =
new Array();
imgurl[0] =
"images/nav_products_highlight.jpg";
imgurl[1] =
"images/nav_services_highlight.jpg";
imgurl[2] =
"images/nav_location_highlight.jpg";
imgurl[3] =
"images/nav_about_highlight.jpg";
imgurl[4] =
"images/nav_contact_highlight.jpg";

var i=0;
for(i=0; i<5; i++)
{
pl =
new Image();
pl.src = imgurl[i];
}
}

Simple enough.

Of course it’s simple after you find the bug. I spent about an hour trying to figure out why my original code wasn’t working; never thinking that there could be a mistake in the code I found online.