From e08308b4df93d460f4d2518a67da5799294df36c Mon Sep 17 00:00:00 2001 From: DJP Date: Mon, 29 Mar 2010 22:58:05 +0000 Subject: [PATCH] Replicated change ielashi made with demo4 so we can use GetMeetingInfo + GetMeetings API. Courtesy of ielashi for all jscript part. git-svn-id: http://bigbluebutton.googlecode.com/svn/trunk@4065 af16638f-c34d-0410-8cfa-b39d5352b314 --- bbb-api-examples/PHP/bbb_api.inc.php | 68 ++++- bbb-api-examples/PHP/demo1.php | 11 +- bbb-api-examples/PHP/demo2.php | 11 +- bbb-api-examples/PHP/demo3.php | 11 +- bbb-api-examples/PHP/demo4.js | 147 +++++++++ bbb-api-examples/PHP/demo4.php | 54 ++++ bbb-api-examples/PHP/demo4_helper.php | 28 ++ bbb-api-examples/PHP/demo_header.php | 1 + bbb-api-examples/PHP/jquery.xml2json.js | 160 ++++++++++ bbb-api-examples/PHP/md5.js | 379 ++++++++++++++++++++++++ 10 files changed, 848 insertions(+), 22 deletions(-) create mode 100755 bbb-api-examples/PHP/demo4.js create mode 100755 bbb-api-examples/PHP/demo4.php create mode 100755 bbb-api-examples/PHP/demo4_helper.php create mode 100755 bbb-api-examples/PHP/demo_header.php create mode 100755 bbb-api-examples/PHP/jquery.xml2json.js create mode 100755 bbb-api-examples/PHP/md5.js diff --git a/bbb-api-examples/PHP/bbb_api.inc.php b/bbb-api-examples/PHP/bbb_api.inc.php index b3ed3cbead..013e9cda9b 100755 --- a/bbb-api-examples/PHP/bbb_api.inc.php +++ b/bbb-api-examples/PHP/bbb_api.inc.php @@ -1,5 +1,5 @@ - -', '', str_replace("\n", '', $xml->asXML()))); +} + +/* + * getURLMeetings() -- return a URL for listing all running meetings + * Beware : check that BIGBLUEBUTTONURL is reachable internally from your PHP Web Application Server. (Hosts, firewall...) + */ +function getURLMeetings() +{ + $base_url = BIGBLUEBUTTONURL."api/getMeetings?"; + $params = 'random='.(rand() * 1000); + + return ($base_url.$params.'&checksum='.sha1($params.SALT)); +} + +/* + * getMeetings() -- Calls getMeetings to obtain the list of meetings, then calls getMeetingInfo for each meeting and concatenates the result. + */ +function getMeetings() +{ + $xml = bbb_wrap_simplexml_load_file(getURLMeetings()); + if ($xml && $xml->returncode == 'SUCCESS') + { + if ($xml->messageKey) + return ($xml->message->asXML()); + ob_start(); + echo ''; + if (count($xml->meetings) && count($xml->meetings->meeting)) + { + foreach ($xml->meetings->meeting as $meeting) + { + echo ''; + echo getMeetingInfo($meeting->meetingID, $meeting->moderatorPW); + echo ''; + } + } + echo ''; + return (ob_get_clean()); + } + else + return (false); +} ?> \ No newline at end of file diff --git a/bbb-api-examples/PHP/demo1.php b/bbb-api-examples/PHP/demo1.php index 9b88e97af2..12b22c6951 100755 --- a/bbb-api-examples/PHP/demo1.php +++ b/bbb-api-examples/PHP/demo1.php @@ -1,5 +1,5 @@ - - @@ -60,9 +60,8 @@ Error: getJoinURL() failed } else { + include('demo_header.php'); ?> -Join a Course | Join a Selected Course | Create Your Own Meeting | Home -

Demo #1: Join a Course

diff --git a/bbb-api-examples/PHP/demo2.php b/bbb-api-examples/PHP/demo2.php index 0d822b2681..d2ce26a336 100755 --- a/bbb-api-examples/PHP/demo2.php +++ b/bbb-api-examples/PHP/demo2.php @@ -1,5 +1,5 @@ - - @@ -56,9 +56,8 @@ Error: getJoinURL() failed } else { + include('demo_header.php'); ?> -Join a Course | Join a Selected Course | Create Your Own Meeting | Home -

Demo #2: Join a Selected Course

diff --git a/bbb-api-examples/PHP/demo3.php b/bbb-api-examples/PHP/demo3.php index 38367f7e8d..4d51a74134 100755 --- a/bbb-api-examples/PHP/demo3.php +++ b/bbb-api-examples/PHP/demo3.php @@ -1,5 +1,5 @@ - - @@ -137,9 +137,8 @@ switch ($_REQUEST['action']) switch ($step) { case '1': + include('demo_header.php'); ?> - Join a Course | Join a Selected Course | Create Your Own Meeting | Home -

Demo #3: Create Your Own Meeting

diff --git a/bbb-api-examples/PHP/demo4.js b/bbb-api-examples/PHP/demo4.js new file mode 100755 index 0000000000..709bff5946 --- /dev/null +++ b/bbb-api-examples/PHP/demo4.js @@ -0,0 +1,147 @@ +/* + BigBlueButton - http://www.bigbluebutton.org + + Copyright (c) 2008-2009 by respective authors (see below). All rights reserved. + + BigBlueButton is free software; you can redistribute it and/or modify it under the + terms of the GNU Lesser General Public License as published by the Free Software + Foundation; either version 3 of the License, or (at your option) any later + version. + + BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with BigBlueButton; if not, If not, see . + + Author: Islam El-Ashi +*/ + +var meetings; // will hold the meetings data + +$(document).ready(function(){ + updateMeetingInfo(); // update the available meeting information as soon as the page is loaded. + setInterval("updateMeetingInfo()", 15000); // update the meeting information every 15 seconds +}); + + +// For each active meeting, create a table listing the participants and insert it into the page. +function createMeetings() { + var nOfMeetings = 0; + if (meetings.meeting) { + for (var i in meetings.meeting) { + + // this variable is to work around the JSON nuance of having a variable instead of an array of one member. + // if we detect there is more than one meeting use the array, otherwise use the variable + var meeting = (meetings.meeting[i].attendees != null) ? meetings.meeting[i] : meetings.meeting; + + createMeetingTable(meeting); + + if (meeting.participantCount != "0") nOfMeetings++; + + // this is also to work around the JSON nuance, if we previously detected that there is only + // one element (i.e. a variable) then we shouldn't loop again. + if (meeting == meetings.meeting) break; + } + } + + // if there are no meetings then display a message to the user. + if (nOfMeetings == 0) { + $("#no_meetings").text("No meetings currently running."); + $("#meetings").text(''); + } + else + $("#no_meetings").text(''); +} + +// creates div tags for each meeting to be able to insert the meeting table into the DOM afterwards +function initializeDivTags() { + if (meetings.meeting) { + var meetingID; + var meeting; + var encodedMeetingID; + for (var i in meetings.meeting) { + meeting = (meetings.meeting[i].attendees != null) ? meetings.meeting[i] : meetings.meeting; + meetingID = meeting.meetingID; + encodedMeeting = encode(meetingID); + + if ($("#" + encodedMeeting).length == 0) { + // assign the div tag an id unique to each meeting + // the id assigned is the encoded value of the meeting id, the encoding is to avoid + // special characters and spaces in the id + $("#meetings").append('
'); + } + + if (meeting == meetings.meeting) break; + } + } +} + +// call the demo4 helper page to fetch the updated data, this is executed every 15 seconds. +function updateMeetingInfo() { + $.ajax({ + type: "GET", + url: 'demo4_helper.php?getxml=true', + dataType: "text/xml", + cache: false, + success: function(xml) { + meetings = $.xml2json(xml); + initializeDivTags(); + createMeetings(); + }, + error: function() { + $("#no_meetings").text("Failed to connect to API."); + $("#meetings").text(""); + } + }); +} + +function getMeetingsInfoURL(meetingID, password, checksum) { + return '../api/getMeetingInfo?meetingID=' + meetingID + '&password=' + password + '&checksum=' + checksum; +} + +function createMeetingTable(meeting) { + var tableContent = ''; + var encodedMeetingID = encode(meeting.meetingID); + var tableRowId; + var newRows = new Array(); + var numberOfRows = 0; + + if (meeting.attendees.attendee) { + for (var i in meeting.attendees.attendee) { + var attendee = (meeting.attendees.attendee[i].userID != null) ? meeting.attendees.attendee[i] : meeting.attendees.attendee; + tableRowId = encodedMeetingID + '_' + attendee.userID; + tableContent += '' + + // if there is a new row to be added, then add to the new rows array to display it with a flash effect. + if ($("#" + tableRowId).length == 0) { + newRows[newRows.length] = tableRowId; + } + numberOfRows++; + + if (attendee == meeting.attendees.attendee) break; + } + } + + tableContent += '
' + meeting.meetingID + '
ParticipantsNameRole
' + attendee.userID + '' + attendee.fullName + '' + attendee.role + '
'; + + if (numberOfRows > 0) { + $("#" + encodedMeetingID).html(tableContent); + $("#" + encodedMeetingID).show("fast"); + } + else { + $("#" + encodedMeetingID).hide("fast"); + } + + for (var i = 0; i < newRows.length; i++) { + $("#" + newRows[i]).effect("highlight", {}, 3000); + } +} + +// the encoding hashes the string to an md5, which ensures - to a great extent - that the encoded string will be +// 1. unique per the original string +// 2. has no spaces and/or special characters +function encode(string) { + return hex_md5(string); +} \ No newline at end of file diff --git a/bbb-api-examples/PHP/demo4.php b/bbb-api-examples/PHP/demo4.php new file mode 100755 index 0000000000..af5aa35e08 --- /dev/null +++ b/bbb-api-examples/PHP/demo4.php @@ -0,0 +1,54 @@ +. + +Author: DJP + +*/ + +require('bbb_api.inc.php'); +?> + + + + + + Get Meeting Info + + + + + + + + +
+ +

Demo #4: Activity Monitor

+ +

+ +
+ + + \ No newline at end of file diff --git a/bbb-api-examples/PHP/demo4_helper.php b/bbb-api-examples/PHP/demo4_helper.php new file mode 100755 index 0000000000..0b154176b6 --- /dev/null +++ b/bbb-api-examples/PHP/demo4_helper.php @@ -0,0 +1,28 @@ +. + +Author: DJP + +*/ + +require('bbb_api.inc.php'); + +echo ''."\r\n"; +header('content-type: text/xml'); +echo getMeetings(); +?> \ No newline at end of file diff --git a/bbb-api-examples/PHP/demo_header.php b/bbb-api-examples/PHP/demo_header.php new file mode 100755 index 0000000000..ea1f87c561 --- /dev/null +++ b/bbb-api-examples/PHP/demo_header.php @@ -0,0 +1 @@ +Join a Course | Join a Selected Course | Create Your Own Meeting | Activity Monitor | Home diff --git a/bbb-api-examples/PHP/jquery.xml2json.js b/bbb-api-examples/PHP/jquery.xml2json.js new file mode 100755 index 0000000000..af1e46b08d --- /dev/null +++ b/bbb-api-examples/PHP/jquery.xml2json.js @@ -0,0 +1,160 @@ +/* + ### jQuery XML to JSON Plugin v1.0 - 2008-07-01 ### + * http://www.fyneworks.com/ - diego@fyneworks.com + * Dual licensed under the MIT and GPL licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html + ### + Website: http://www.fyneworks.com/jquery/xml-to-json/ +*//* + # INSPIRED BY: http://www.terracoder.com/ + AND: http://www.thomasfrank.se/xml_to_json.html + AND: http://www.kawa.net/works/js/xml/objtree-e.html +*//* + This simple script converts XML (document of code) into a JSON object. It is the combination of 2 + 'xml to json' great parsers (see below) which allows for both 'simple' and 'extended' parsing modes. +*/ +// Avoid collisions +;if(window.jQuery) (function($){ + + // Add function to jQuery namespace + $.extend({ + + // converts xml documents and xml text to json object + xml2json: function(xml, extended) { + if(!xml) return {}; // quick fail + + //### PARSER LIBRARY + // Core function + function parseXML(node, simple){ + if(!node) return null; + var txt = '', obj = null, att = null; + var nt = node.nodeType, nn = jsVar(node.localName || node.nodeName); + var nv = node.text || node.nodeValue || ''; + /*DBG*/ //if(window.console) console.log(['x2j',nn,nt,nv.length+' bytes']); + if(node.childNodes){ + if(node.childNodes.length>0){ + /*DBG*/ //if(window.console) console.log(['x2j',nn,'CHILDREN',node.childNodes]); + $.each(node.childNodes, function(n,cn){ + var cnt = cn.nodeType, cnn = jsVar(cn.localName || cn.nodeName); + var cnv = cn.text || cn.nodeValue || ''; + /*DBG*/ //if(window.console) console.log(['x2j',nn,'node>a',cnn,cnt,cnv]); + if(cnt == 8){ + /*DBG*/ //if(window.console) console.log(['x2j',nn,'node>b',cnn,'COMMENT (ignore)']); + return; // ignore comment node + } + else if(cnt == 3 || cnt == 4 || !cnn){ + // ignore white-space in between tags + if(cnv.match(/^\s+$/)){ + /*DBG*/ //if(window.console) console.log(['x2j',nn,'node>c',cnn,'WHITE-SPACE (ignore)']); + return; + }; + /*DBG*/ //if(window.console) console.log(['x2j',nn,'node>d',cnn,'TEXT']); + txt += cnv.replace(/^\s+/,'').replace(/\s+$/,''); + // make sure we ditch trailing spaces from markup + } + else{ + /*DBG*/ //if(window.console) console.log(['x2j',nn,'node>e',cnn,'OBJECT']); + obj = obj || {}; + if(obj[cnn]){ + /*DBG*/ //if(window.console) console.log(['x2j',nn,'node>f',cnn,'ARRAY']); + if(!obj[cnn].length) obj[cnn] = myArr(obj[cnn]); + obj[cnn][ obj[cnn].length ] = parseXML(cn, true/* simple */); + obj[cnn].length = obj[cnn].length; + } + else{ + /*DBG*/ //if(window.console) console.log(['x2j',nn,'node>g',cnn,'dig deeper...']); + obj[cnn] = parseXML(cn); + }; + }; + }); + };//node.childNodes.length>0 + };//node.childNodes + if(node.attributes){ + if(node.attributes.length>0){ + /*DBG*/ //if(window.console) console.log(['x2j',nn,'ATTRIBUTES',node.attributes]) + att = {}; obj = obj || {}; + $.each(node.attributes, function(a,at){ + var atn = jsVar(at.name), atv = at.value; + att[atn] = atv; + if(obj[atn]){ + /*DBG*/ //if(window.console) console.log(['x2j',nn,'attr>',atn,'ARRAY']); + if(!obj[atn].length) obj[atn] = myArr(obj[atn]);//[ obj[ atn ] ]; + obj[atn][ obj[atn].length ] = atv; + obj[atn].length = obj[atn].length; + } + else{ + /*DBG*/ //if(window.console) console.log(['x2j',nn,'attr>',atn,'TEXT']); + obj[atn] = atv; + }; + }); + //obj['attributes'] = att; + };//node.attributes.length>0 + };//node.attributes + if(obj){ + obj = $.extend( (txt!='' ? new String(txt) : {}),/* {text:txt},*/ obj || {}/*, att || {}*/); + txt = (obj.text) ? (typeof(obj.text)=='object' ? obj.text : [obj.text || '']).concat([txt]) : txt; + if(txt) obj.text = txt; + txt = ''; + }; + var out = obj || txt; + //console.log([extended, simple, out]); + if(extended){ + if(txt) out = {};//new String(out); + txt = out.text || txt || ''; + if(txt) out.text = txt; + if(!simple) out = myArr(out); + }; + return out; + };// parseXML + // Core Function End + // Utility functions + var jsVar = function(s){ return String(s || '').replace(/-/g,"_"); }; + var isNum = function(s){ return (typeof s == "number") || String((s && typeof s == "string") ? s : '').test(/^((-)?([0-9]*)((\.{0,1})([0-9]+))?$)/); }; + var myArr = function(o){ + if(!o.length) o = [ o ]; o.length=o.length; + // here is where you can attach additional functionality, such as searching and sorting... + return o; + }; + // Utility functions End + //### PARSER LIBRARY END + + // Convert plain text to xml + if(typeof xml=='string') xml = $.text2xml(xml); + + // Quick fail if not xml (or if this is a node) + if(!xml.nodeType) return; + if(xml.nodeType == 3 || xml.nodeType == 4) return xml.nodeValue; + + // Find xml root node + var root = (xml.nodeType == 9) ? xml.documentElement : xml; + + // Convert xml to json + var out = parseXML(root, true /* simple */); + + // Clean-up memory + xml = null; root = null; + + // Send output + return out; + }, + + // Convert text to XML DOM + text2xml: function(str) { + // NOTE: I'd like to use jQuery for this, but jQuery makes all tags uppercase + //return $(xml)[0]; + var out; + try{ + var xml = ($.browser.msie)?new ActiveXObject("Microsoft.XMLDOM"):new DOMParser(); + xml.async = false; + }catch(e){ throw new Error("XML Parser could not be instantiated") }; + try{ + if($.browser.msie) out = (xml.loadXML(str))?xml:false; + else out = xml.parseFromString(str, "text/xml"); + }catch(e){ throw new Error("Error parsing XML string") }; + return out; + } + + }); // extend $ + +})(jQuery); diff --git a/bbb-api-examples/PHP/md5.js b/bbb-api-examples/PHP/md5.js new file mode 100755 index 0000000000..8773a969a0 --- /dev/null +++ b/bbb-api-examples/PHP/md5.js @@ -0,0 +1,379 @@ +/* + * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message + * Digest Algorithm, as defined in RFC 1321. + * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009 + * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet + * Distributed under the BSD License + * See http://pajhome.org.uk/crypt/md5 for more info. + */ + +/* + * Configurable variables. You may need to tweak these to be compatible with + * the server-side, but the defaults work in most cases. + */ +var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */ +var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */ + +/* + * These are the functions you'll usually want to call + * They take string arguments and return either hex or base-64 encoded strings + */ +function hex_md5(s) { return rstr2hex(rstr_md5(str2rstr_utf8(s))); } +function b64_md5(s) { return rstr2b64(rstr_md5(str2rstr_utf8(s))); } +function any_md5(s, e) { return rstr2any(rstr_md5(str2rstr_utf8(s)), e); } +function hex_hmac_md5(k, d) + { return rstr2hex(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))); } +function b64_hmac_md5(k, d) + { return rstr2b64(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))); } +function any_hmac_md5(k, d, e) + { return rstr2any(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d)), e); } + +/* + * Perform a simple self-test to see if the VM is working + */ +function md5_vm_test() +{ + return hex_md5("abc").toLowerCase() == "900150983cd24fb0d6963f7d28e17f72"; +} + +/* + * Calculate the MD5 of a raw string + */ +function rstr_md5(s) +{ + return binl2rstr(binl_md5(rstr2binl(s), s.length * 8)); +} + +/* + * Calculate the HMAC-MD5, of a key and some data (raw strings) + */ +function rstr_hmac_md5(key, data) +{ + var bkey = rstr2binl(key); + if(bkey.length > 16) bkey = binl_md5(bkey, key.length * 8); + + var ipad = Array(16), opad = Array(16); + for(var i = 0; i < 16; i++) + { + ipad[i] = bkey[i] ^ 0x36363636; + opad[i] = bkey[i] ^ 0x5C5C5C5C; + } + + var hash = binl_md5(ipad.concat(rstr2binl(data)), 512 + data.length * 8); + return binl2rstr(binl_md5(opad.concat(hash), 512 + 128)); +} + +/* + * Convert a raw string to a hex string + */ +function rstr2hex(input) +{ + try { hexcase } catch(e) { hexcase=0; } + var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; + var output = ""; + var x; + for(var i = 0; i < input.length; i++) + { + x = input.charCodeAt(i); + output += hex_tab.charAt((x >>> 4) & 0x0F) + + hex_tab.charAt( x & 0x0F); + } + return output; +} + +/* + * Convert a raw string to a base-64 string + */ +function rstr2b64(input) +{ + try { b64pad } catch(e) { b64pad=''; } + var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + var output = ""; + var len = input.length; + for(var i = 0; i < len; i += 3) + { + var triplet = (input.charCodeAt(i) << 16) + | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0) + | (i + 2 < len ? input.charCodeAt(i+2) : 0); + for(var j = 0; j < 4; j++) + { + if(i * 8 + j * 6 > input.length * 8) output += b64pad; + else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F); + } + } + return output; +} + +/* + * Convert a raw string to an arbitrary string encoding + */ +function rstr2any(input, encoding) +{ + var divisor = encoding.length; + var i, j, q, x, quotient; + + /* Convert to an array of 16-bit big-endian values, forming the dividend */ + var dividend = Array(Math.ceil(input.length / 2)); + for(i = 0; i < dividend.length; i++) + { + dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1); + } + + /* + * Repeatedly perform a long division. The binary array forms the dividend, + * the length of the encoding is the divisor. Once computed, the quotient + * forms the dividend for the next step. All remainders are stored for later + * use. + */ + var full_length = Math.ceil(input.length * 8 / + (Math.log(encoding.length) / Math.log(2))); + var remainders = Array(full_length); + for(j = 0; j < full_length; j++) + { + quotient = Array(); + x = 0; + for(i = 0; i < dividend.length; i++) + { + x = (x << 16) + dividend[i]; + q = Math.floor(x / divisor); + x -= q * divisor; + if(quotient.length > 0 || q > 0) + quotient[quotient.length] = q; + } + remainders[j] = x; + dividend = quotient; + } + + /* Convert the remainders to the output string */ + var output = ""; + for(i = remainders.length - 1; i >= 0; i--) + output += encoding.charAt(remainders[i]); + + return output; +} + +/* + * Encode a string as utf-8. + * For efficiency, this assumes the input is valid utf-16. + */ +function str2rstr_utf8(input) +{ + var output = ""; + var i = -1; + var x, y; + + while(++i < input.length) + { + /* Decode utf-16 surrogate pairs */ + x = input.charCodeAt(i); + y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0; + if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF) + { + x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF); + i++; + } + + /* Encode output as utf-8 */ + if(x <= 0x7F) + output += String.fromCharCode(x); + else if(x <= 0x7FF) + output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F), + 0x80 | ( x & 0x3F)); + else if(x <= 0xFFFF) + output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F), + 0x80 | ((x >>> 6 ) & 0x3F), + 0x80 | ( x & 0x3F)); + else if(x <= 0x1FFFFF) + output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07), + 0x80 | ((x >>> 12) & 0x3F), + 0x80 | ((x >>> 6 ) & 0x3F), + 0x80 | ( x & 0x3F)); + } + return output; +} + +/* + * Encode a string as utf-16 + */ +function str2rstr_utf16le(input) +{ + var output = ""; + for(var i = 0; i < input.length; i++) + output += String.fromCharCode( input.charCodeAt(i) & 0xFF, + (input.charCodeAt(i) >>> 8) & 0xFF); + return output; +} + +function str2rstr_utf16be(input) +{ + var output = ""; + for(var i = 0; i < input.length; i++) + output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF, + input.charCodeAt(i) & 0xFF); + return output; +} + +/* + * Convert a raw string to an array of little-endian words + * Characters >255 have their high-byte silently ignored. + */ +function rstr2binl(input) +{ + var output = Array(input.length >> 2); + for(var i = 0; i < output.length; i++) + output[i] = 0; + for(var i = 0; i < input.length * 8; i += 8) + output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (i%32); + return output; +} + +/* + * Convert an array of little-endian words to a string + */ +function binl2rstr(input) +{ + var output = ""; + for(var i = 0; i < input.length * 32; i += 8) + output += String.fromCharCode((input[i>>5] >>> (i % 32)) & 0xFF); + return output; +} + +/* + * Calculate the MD5 of an array of little-endian words, and a bit length. + */ +function binl_md5(x, len) +{ + /* append padding */ + x[len >> 5] |= 0x80 << ((len) % 32); + x[(((len + 64) >>> 9) << 4) + 14] = len; + + var a = 1732584193; + var b = -271733879; + var c = -1732584194; + var d = 271733878; + + 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); +} + +/* + * These functions implement the four basic operations the algorithm uses. + */ +function md5_cmn(q, a, b, x, s, t) +{ + return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b); +} +function md5_ff(a, b, c, d, x, s, t) +{ + return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t); +} +function md5_gg(a, b, c, d, x, s, t) +{ + return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t); +} +function md5_hh(a, b, c, d, x, s, t) +{ + return md5_cmn(b ^ c ^ d, a, b, x, s, t); +} +function md5_ii(a, b, c, d, x, s, t) +{ + return md5_cmn(c ^ (b | (~d)), a, b, x, s, t); +} + +/* + * Add integers, wrapping at 2^32. This uses 16-bit operations internally + * to work around bugs in some JS interpreters. + */ +function safe_add(x, y) +{ + var lsw = (x & 0xFFFF) + (y & 0xFFFF); + var msw = (x >> 16) + (y >> 16) + (lsw >> 16); + return (msw << 16) | (lsw & 0xFFFF); +} + +/* + * Bitwise rotate a 32-bit number to the left. + */ +function bit_rol(num, cnt) +{ + return (num << cnt) | (num >>> (32 - cnt)); +}