Usuario:Atalanta86/Live Preview/sources.js
Apariencia
Nota: Después de guardar, debes refrescar la caché de tu navegador para ver los cambios. Internet Explorer: mantén presionada Ctrl mientras pulsas Actualizar. Firefox: mientras presionas Mayús pulsas el botón Actualizar, (o presiona Ctrl-Shift-R). Los usuarios de Google Chrome y Safari pueden simplemente pulsar el botón Recargar. Para más detalles e instrucciones acerca de otros exploradores, véase Ayuda:Cómo limpiar la caché.
//<nowiki>
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* MediaWiki to HTML converter
* Written by Pedro Fayolle (pfayolle@gmail.com)
*
* Permission is granted to use and distribute.
* You can modify the code provided that you send me message with the changes.
*
* Mediawiki is maintained by the Wikimedia Foundation
* http://wikipedia.sourceforge.net
* http://wikimedia.org
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* CHANGELOG:
*
* 0.5.1
* + Added image failback (e.g. for Commons)
* + Added support for inline images with complex syntax and full nesting
* + Fixed some bugs with tables
*
* 0.5
*
* + Added basic image support, still needs _much_ improvement.
*
* 0.4.3
* + Made code more object oriented by putting all self-modifying WikiCode methods
* inside the class. This probably means faster code execution too.
*
* 0.4.2
* + Fixed bug in parsing of links with replaced text
* + Fixed bug with combined bold and italics text
* + Added support for continuous line breaking
* + Added support for invisible namespaces in links (categories, interwiki, etc)
* + Added support for signatures
* + Done a few minor optimizations
*
* 0.4.1
* + Fixed several bugs, mostly related to tables
*
* 0.4
* + Added support for tables (with nesting)
*
* 0.3
* + Added support for nested lists and definition lists (can all be mixed)
*
*
* TODO:
*
* - Add HTML stripping
* - Add nowiki support
* - Add support for [[/subpage]] link syntax
*
*
* DESIGN NOTES:
*
* This parser is not based on the original Mediawiki parser code (written in PHP),
* but on its direct output instead. I figured it would take me longer if I had to
* learn how the original parser does its trick.
*
* Some parts of the HTML generation are handled in a lazy fashion. That is, tags
* are not always formally closed (with a </*>) as all browsers (or those I've tested)
* can handle that sort of HTML very neatly, this saves for some code complexity.
*
* Stupid me! I spent days trying to figure out a neat way of preloading each used
* image just to have the width and height beforehand so I could compute the right
* height based on the original proportions and the given width... and, guess what?
* simply by giving the width the browser will resize the image proportionally, so
* there was not damn need to fetch the original proportions. I wanna slap myself.
* Thinking again, preloading would be useful to check if there's already a thumb of
* the image or to failback to commons.
*
* JAVASCRIPT NOTES:
*
* As much as I'd like to use the prettier string[char_index] syntax for char-wise
* comparisons, neither Opera or IE seem to support that kind of syntax, forcing
* me to use the much uglier string.substr() method instead. I'm new to JS, so if
* anyone knows of a nicier (faster?) way of doing this just let me know.
* UPDATED: hadn't noticed string.charAt(pos), I'm still not entirely happy though.
*
* Apparently variables declared without 'var' become globals, so be *very* careful.
*
* When passing function parameters, only primitives get passed by value, objects get
* passed by reference.
*
* REFERENCES:
*
* - Optimization tips:
* http://home.earthlink.net/~kendrasg/info/js_opt/jsOptMain.html
* - MD5 hash generator:
* http://pajhome.org.uk/crypt/md5/
* - Javascript Compression:
* http://dean.edwards.name/packer/
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*** User defined options ***/
// Your username
var wpUserName = wpUserName || 'Wikipedian';
// Signature string (user name)
var wpUserSignature = wpUserSignature || wpUserName;
// Download and display images
var wpShowImages = wpShowImages || true;
/*** System-wide options ***/
// Language code for local wiki
var wpLanguageCode = 'en';
// Interwiki codes
var wpInterwikiCodes = 'ab|aa|af|ak|sq|als|am|ang|ar|an|arc|hy|roa-rup|as|ast|av|ay|az|bm|ba|eu|be|bn|bh|bi|bs|br|bg|my|ca|ch|ce|chr|chy|ny|zh|zh-tw|zh-cn|cho|cv|kw|co|cr|hr|cs|da|dv|nl|dz|en|eo|et|ee|fo|fj|fi|fr|fy|ff|gl|ka|de|got|el|kl|gn|gu|ht|ha|haw|he|hz|hi|ho|hu|is|io|ig|id|ia|ie|iu|ik|ga|it|ja|jv|kn|kr|csb|ks|kk|km|ki|rw|rn|tlh|kv|kg|ko|kj|ku|ky|lo|la|lv|li|ln|lt|jbo|nds|lg|lb|mk|mg|ms|ml|mt|gv|mi|minnan|mr|mh|zh-min-nan|mo|mn|mus|nah|na|nv|ne|se|no|nn|oc|or|om|pi|fa|pl|pt|pa|ps|qu|ro|rm|ru|sm|sg|sa|sc|gd|sr|sh|st|tn|sn|scn|simple|sd|si|sk|sl|so|st|es|su|sw|ss|sv|tl|ty|tg|ta|tt|te|th|bo|ti|tpi|to|tokipona|ts|tum|tr|tk|tw|uk|ur|ug|uz|ve|vi|vo|wa|cy|wo|xh|ii|yi|yo|za|zu';
// Base path for internal links
var wpBaseArticlePath = '/wiki/';
// Image config vars
var wpImageBasePath = 'http://upload.wikimedia.org/wikipedia/' + wpLanguageCode + '/';
var wpImageFailbackPath = 'http://upload.wikimedia.org/wikipedia/commons/';
var wpDefaultThumbWidth = 180;
var wpSkinMagnifyClip = '/skins/common/images/magnify-clip.png';
// Namespaces
var wpUserNamespace = 'User';
var wpImageNamespace = 'Image';
var wpCategoryNamespace = 'Category';
/*** DO NOT EDIT BELOW THIS LINE ***/
// Main function, takes raw wikicode and outputs HTML
function wiki2html(str)
{
str = strip_cr(str);
var w = new WikiCode();
w.lines = str.split(/\n/);
w.parse();
return w.html;
};
// Base signature format
var wpSignature = '[['+wpUserNamespace+':'+wpUserName+'|'+wpUserSignature+']]';
// Invisible namespace links matching regexp
var wpInvisibleNamespaces = new RegExp('\\[\\[(?:'+wpCategoryNamespace+'|'+wpInterwikiCodes+'):.*?\\]\\]', 'gi')
// Image matching regexps
var wpBlockImage = new RegExp('^\\[\\['+wpImageNamespace+':.*?\\|.*?(?:frame|thumbnail|thumb|none|right|left|center)', 'i');
function WikiCode()
{
this.lines = new Array;
this.html = new String;
this._endline = function(str)
{
this.html += str;
this.lines.shift();
};
this.parse = function()
{
var p = false; // flag for checking if there's an open P element
do {
if ((h_match = this.lines[0].match(/^(={1,6})(.*)\1(.*)$/)) != null) { // heading
p = false;
this._endline('<h' + h_match[1].length + '>' + _parse_inline_wiki(h_match[2]) + '</h' + h_match[1].length + '>' + h_match[3]);
} else if (this.lines[0].match(/^[*#:;]/) != null) { // list
p = false;
this._parse_list();
} else if (this.lines[0].charAt(0) == ' ') { // preformatted text
p = false;
this._parse_pre();
} else if (this.lines[0].substr(0, 2) == '{|') { // table
p = false;
this._parse_table();
} else if (this.lines[0].match(/^----+$/) != null) { // horizontal bar
p = false;
this._endline('<hr/>');
} else if (this.lines[0].match(wpBlockImage) != null) { // block image
p = false;
this._parse_block_image();
} else {
/*
* NOTE: P elements can't contain block-level elements (including P),
* so it's safe not to close P tags as anything else will break it.
*/
if (this.lines[0] == '') {
if (p = (this.lines.length > 1 && this.lines[1] == '')) {
this._endline('<p><br />');
}
} else {
if (!p) {
this.html += '<p>';
p = true;
}
this.html += _parse_inline_wiki(this.lines[0]) + ' ';
}
this.lines.shift();
}
} while (this.lines.length);
};
// parse nested lists and definitions
this._parse_list = function() {
var prev = new String;
var l_match, imatch;
while (this.lines.length && (l_match = this.lines[0].match(/^([*#:;]+)(.*)$/)) != null) {
this.lines.shift();
imatch = str_imatch(prev, l_match[1]);
/* TODO:
* Try to optimize this by using an auxiliary buffer to close
* and open tags within the same loop
*/
for (var i = prev.length-1; i >= imatch; i--) { // close tags
if (prev.charAt(i) == '*') {
this.html += '</ul>';
} else if (prev.charAt(i) == '#') {
this.html += '</ol>'
} else {
this.html += '</d' + ((prev.charAt(i) == ';')?'t':'d') + '>';
switch (l_match[1].charAt(i)) {
case '': case '*': case '#': this.html += '</dl>';
}
}
}
for (var i = imatch; i < l_match[1].length; i++) { // open tags
if (l_match[1].charAt(i) == '*') {
this.html += '<ul>';
} else if (l_match[1].charAt(i) == '#') {
this.html += '<ol>';
} else {
switch (prev.charAt(i)) {
case '': case '*': case '#': this.html += '<dl>';
}
this.html += '<d' + ((l_match[1].charAt(i) == ';')?'t':'d') + '>';
}
}
if (l_match[1].charAt(l_match[1].length-1) == '*' || l_match[1].charAt(l_match[1].length-1) == '#') {
this.html += '<li>' + _parse_inline_wiki(l_match[2]) + '</li>';
} else {
if ((dt_match = l_match[2].match(/(.*?) (:.*?)$/)) != null) {
this.html += _parse_inline_wiki(dt_match[1]);
this.lines.unshift(dt_match[2]);
} else {
this.html += _parse_inline_wiki(l_match[2]);
}
}
prev = l_match[1];
}
// TODO: Try to include this in main loop
for (i = prev.length-1; i >= 0; i--) { // close remaining
if (prev.charAt(i) == '*') {
this.html += '</ul>';
} else if (prev.charAt(i) == '#') {
this.html += '</ol>';
} else {
this.html += '</d' + ((prev.charAt(i) == ';')?'t':'d') + '></dl>';
}
}
};
this._parse_table = function()
{
var table_match;
if ((table_match = this.lines[0].match(/^\{\|( .*)$/)) != null) {
this._endline('<table' + table_match[1] + '>');
} else this._endline('<table>');
do {
if (this.lines[0].charAt(0) == '|') {
switch (this.lines[0].charAt(1)) {
case '}':
this._endline('</table>');
return;
case '-':
this._endline('<tr ' + this.lines[0].match(/\|-*(.*)/)[1] + '>');
break;
default:
this._parse_table_data();
}
} else if (this.lines[0].charAt(0) == '!') {
this._parse_table_data();
} else {
this.lines.shift();
}
} while (this.lines.length)
};
// parse table data (td, th, caption)
this._parse_table_data = function()
{
var td_match, td_line;
/*
* Regexp disection:
*
* 1) ^(\|\+|\||!)
* match either |+, | or ! at beggining of line
* 2) ((?:(.*?)\|(?!\|))?(.*))$
* match whole line (sub-matching follows...)
* 3) (?:([^[|]*?)\|(?!\|))?
* match HTML attributes and make sure we don't match a wikilink
* 4) (.*)$
* Match the rest
*/
td_match = this.lines.shift().match(/^(\|\+|\||!)((?:([^[|]*?)\|(?!\|))?(.*))$/);
if (td_match[1] == '|+') {
this.html += '<caption';
} else {
this.html += '<t' + ((td_match[1] == '|')?'d':'h');
}
if (typeof td_match[3] != 'undefined') {
this.html += ' ' + td_match[3]; // insert attributes
td_line = td_match[4].split('||');
} else {
td_line = td_match[2].split('||');
}
this.html += '>';
while (td_line.length > 1) { // send inline cells to next pass TODO: handle this locally to avoid extra parsing overhead
this.lines.unshift(td_match[1] + td_line.pop());
}
this.html += _parse_inline_wiki(td_line[0]);
var td = new WikiCode;
var table_count = 0;
while (this.lines.length) {
// manage nested tables
if (this.lines[0].charAt(0) == '|') {
if (table_count == 0) break;
else if (this.lines[0].charAt(1) == '}') table_count--;
} else if (this.lines[0].charAt(0) == '!' && table_count == 0) {
break;
} else if (this.lines[0].substr(0, 2) == '{|') table_count++;
td.lines.push(this.lines.shift());
}
if (td.lines.length) {
td.parse();
}
this.html += td.html;
};
// parse pre code
this._parse_pre = function()
{
this.html += '<pre>';
do {
this._endline(_parse_inline_wiki(this.lines[0].substring(1, this.lines[0].length)) + "\n");
} while (this.lines.length && this.lines[0].charAt(0) == ' ');
this.html += '</pre>';
};
// parse block images (ie. not simple inline images)
this._parse_block_image = function()
{
// FIXME: make this handle multiple lines and nested wiki
/*var line = '';
var exitflag = true;
do { // put full image syntax into a single line
exitflag = (this.lines[0].replace(/\[\[.*?\]\]/, '').match(/\]\]$/) == null); // evals to false to exit
if (!exitflag) alert('a');
line += this.lines.shift() + ' ';
} while (this.lines.length && exitflag);
this.html += _parse_image(line.substring(0, line.length - 1));*/
this.html += _parse_image(this.lines.shift());
};
};
// parse a wikicode image and return its HTML code
function _parse_image(str)
{
var attr = str.substring(wpImageNamespace.length + 3, str.length - 2).split(/\s*\|\s*/);
var filename = attr[0];
var caption = attr[attr.length-1];
//var width = '';
var width, w_match;
var thumb = false;
var frame = false;
var center = false;
var align = '';
var html = '';
do { // mine image information
if ((w_match = attr[0].match(/^(\d*)px$/)) != null) {
width = w_match[1];
} else switch (attr[0]) {
case 'thumb':
case 'thumbnail':
thumb = true;
case 'frame':
frame = true;
break;
case 'none':
case 'right':
case 'left':
center = false;
align = attr[0];
break;
case 'center':
center = true;
align = 'none';
}
attr.shift();
} while (attr.length);
if (frame) {
if (align == '') align = 'right';
html += "<div class='thumb t" + align + "'>";
if (thumb) {
if (width == '') width = wpDefaultThumbWidth;
html += "<div style='width:" + (2 + parseInt(width)) + "px;'>";
html += _make_image(filename, caption, width);
html += "<div class='thumbcaption'><div class='magnify' style='float:right'><a href='" + wpBaseArticlePath + wpImageNamespace + ':' + filename + "' class='internal' title='Enlarge'><img src='" + wpSkinMagnifyClip + "' /></a></div>" + _parse_inline_wiki(caption) + "</div>";
} else {
html += '<div>';
html += _make_image(filename, caption);
html += "<div class='thumbcaption'>" + _parse_inline_wiki(caption) + "</div>";
}
html += '</div></div>';
} else if (align != '') {
html += "<div class='float" + align + "'><span>" + _make_image(filename, caption, width) + "</span></div>";
} else {
return _make_image(filename, caption, width);
}
if (center) {
return "<div class='center'>" + html + '</div>';
} else {
return html;
}
};
function _make_image(filename, caption, /*optional*/ width)
{
filename = filename.charAt(0).toUpperCase() + filename.substr(1); // capitalize
filename = filename.replace(/ /g, '_'); // replace spaces with underscore
var md5 = hex_md5(filename);
var source = md5.charAt(0) + '/' + md5.substr(0, 2) + '/' + filename;
var img;
if (wpShowImages) {
if (width) {
width = "width='" + width + "px'";
}
img = "<img onerror='this.onerror=null;this.src=\"" + wpImageFailbackPath + source + "\";' src='" + wpImageBasePath + source + "' alt='" + caption + "' " + width + "/>";
} else {
img = wpImageNamespace + ':' + filename + " <em style='color:red;'>(images disabled)</em>";
}
caption = _strip_inline_wiki(caption);
return "<a class='image' title='" + caption + "' href='" + wpBaseArticlePath + wpImageNamespace + ':' + filename + "'>" + img + "</a>";
};
function _parse_inline_images(str)
{
var start, substart = 0, nestlev = 0;
var loop, close, open, wiki, html;
while (-1 != (start = str.indexOf('[[', substart) )) { // iterate through each top-level image
if (str.substr(start+2).match(RegExp('^' + wpImageNamespace + ':', 'i')) != null) {
loop = true;
substart = start;
do {
substart += 2;
close = str.indexOf(']]', substart);
open = str.indexOf('[[', substart);
if (close <= open || open == -1) {
if (close == -1) return str;
substart = close;
if (nestlev) {
nestlev--;
} else {
wiki = str.substring(start, close+2);
html = _parse_image(wiki);
str = str.replace(wiki, html);
substart = start + html.length;
loop = false;
}
} else {
substart = open;
nestlev++;
}
} while (loop);
} else {
break;
}
}
return str;
};
// parse links and common inline formatting
function _parse_inline_wiki(str)
{
// FIXME: simplify this mess!
str = str.replace(/'''''(.*?)''(.*?)'''/g, '<strong><em>$1</em>$2</strong>');
str = str.replace(/'''''(.*?)'''(.*?)''/g, '<em><strong>$1</strong>$2</em>');
str = str.replace(/'''(.*?)''(.*?)'''''/g, '<strong>$1<em>$2</em></strong>');
str = str.replace(/'''(.*?)'''/g, '<strong>$1</strong>');
str = str.replace(/''(.*?)''/g, '<em>$1</em>');
str = str.replace(/~{4,5}(?!~)/g, wpSignature + ' ' + Date()); // signature
str = str.replace(/~{3}(?!~)/g, wpSignature); // simple signature
str = _parse_inline_images(str); // inline images
str = str.replace(wpInvisibleNamespaces, ''); // remove invisible namespaces
str = str.replace(/\[\[([^|]*?)\]\](\w*)/g, "<a href='" + wpBaseArticlePath + "$1'>$1$2</a>"); // normal wikilink
str = str.replace(/\[\[(.*?)\|([^\]]+?)\]\](\w*)/g, "<a href='" + wpBaseArticlePath + "$1'>$2$3</a>"); // wikilink with replaced text
str = str.replace(/\[\[([^\]]*:)?(.*?)( *\(.*?\))?\|\]\]/g, "<a href='" + wpBaseArticlePath + "$1$2$3'>$2</a>"); // hidden namespace & parentheses
str = str.replace(/\[(http|news|ftp|mailto|gopher|irc):(\/*)([^\]]*?) (.*?)\]/g, "<a href='$1:$2$3'>$4</a>");
str = str.replace(/\[http:\/\/(.*?)\]/g, "<a href='http://$1'>[#]</a>");
str = str.replace(/\[(news|ftp|mailto|gopher|irc):(\/*)(.*?)\]/g, "<a href='$1:$2$3'>$1:$2$3</a>");
str = str.replace(/(^| )(http|news|ftp|mailto|gopher|irc):(\/*)([^ $]*)/g, "$1<a href='$2:$3$4'>$2:$3$4</a>");
str = str.replace('__NOTOC__', '');
str = str.replace('__NOEDITSECTION__', '');
return str;
};
function _strip_inline_wiki(str)
{
str = str.replace(/\[\[[^\]]*\|(.*?)\]\]/g, '$1');
str = str.replace(/\[\[(.*?)\]\]/g, '$1');
str = str.replace(/''(.*?)''/g, '$1');
return str;
};
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// return the greatest of two numbers
function max(a, b)
{
if (a > b) return a; else return b;
};
// return the smallest of two numbers
function min(a, b)
{
if (a < b) return a; else return b;
};
// find the length of the initial matching segment between two strings
function str_imatch(str_a, str_b)
{
var lim = min(str_a.length, str_b.length);
for (var i = 0; i < lim; i++) {
if (str_a.charAt(i) != str_b.charAt(i)) return i;
}
return i;
};
// remove carriage returns
function strip_cr(str)
{
str = str.replace(/\n\r/g, "\n");
str = str.replace(/\r/g, '');
return str;
};
/*
* A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
* Digest Algorithm, as defined in RFC 1321.
* Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
* Distributed under the BSD License
* See http://pajhome.org.uk/crypt/md5 for more info.
*
* Stripped down for wikicode parser use
*/
var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */
var hex_tab = "0123456789abcdef";
function hex_md5(s){ return binl2hex(core_md5(str2binl(s), s.length * chrsz)); };
/*
* Calculate the MD5 of an array of little-endian words, and a bit length
*/
function core_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));
};
/*
* Convert a string to an array of little-endian words
* If chrsz is ASCII, characters >255 have their hi-byte silently ignored.
*/
function str2binl(str)
{
var bin = Array();
var mask = (1 << chrsz) - 1;
for(var i = 0; i < str.length * chrsz; i += chrsz)
bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32);
return bin;
};
/*
* Convert an array of little-endian words to a hex string.
*/
function binl2hex(binarray)
{
var str = '';
for(var i = 0; i < binarray.length * 4; i++)
{
str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +
hex_tab.charAt((binarray[i>>2] >> ((i%4)*8 )) & 0xF);
}
return str;
};