jquery-encoder-0.1.0.js 53 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452
  1. /*
  2. * Copyright (c) 2010 - The OWASP Foundation
  3. *
  4. * The jquery-encoder is published by OWASP under the MIT license. You should read and accept the
  5. * LICENSE before you use, modify, and/or redistribute this software.
  6. */
  7. (function($) {
  8. var default_immune = {
  9. 'js' : [',','.','_',' ']
  10. };
  11. var attr_whitelist_classes = {
  12. 'default': [',','.','-','_',' ']
  13. };
  14. var attr_whitelist = {
  15. 'width': ['%'],
  16. 'height': ['%']
  17. };
  18. var css_whitelist_classes = {
  19. 'default': ['-',' ','%'],
  20. 'color': ['#',' ','(',')'],
  21. 'image': ['(',')',':','/','?','&','-','.','"','=',' ']
  22. };
  23. var css_whitelist = {
  24. 'background': ['(',')',':','%','/','?','&','-',' ','.','"','=','#'],
  25. 'background-image': css_whitelist_classes['image'],
  26. 'background-color': css_whitelist_classes['color'],
  27. 'border-color': css_whitelist_classes['color'],
  28. 'border-image': css_whitelist_classes['image'],
  29. 'color': css_whitelist_classes['color'],
  30. 'icon': css_whitelist_classes['image'],
  31. 'list-style-image': css_whitelist_classes['image'],
  32. 'outline-color': css_whitelist_classes['color']
  33. };
  34. // In addition to whitelist filtering for proper encoding - there are some things that should just simply be
  35. // considered to be unsafe. Setting javascript events or style properties with the encodeHTMLAttribute method and
  36. // using javascript: urls should be looked at as bad form all the way around and should be avoided. The blacklisting
  37. // feature of the plugin can be disabled by calling $.encoder.disableBlacklist() prior to the first call encoding
  38. // takes place (ES5 Compatibility Only)
  39. var unsafeKeys = {
  40. // Style and JS Event attributes should be set through the appropriate methods encodeForCSS, encodeForURL, or
  41. // encodeForJavascript
  42. 'attr_name' : ['on[a-z]{1,}', 'style', 'href', 'src'],
  43. // Allowing Javascript url's in untrusted data is a bad idea.
  44. 'attr_val' : ['javascript:'],
  45. // These css keys and values are considered to be unsafe to pass in untrusted data into.
  46. 'css_key' : ['behavior', '-moz-behavior', '-ms-behavior'],
  47. 'css_val' : ['expression']
  48. };
  49. var options = {
  50. blacklist: true
  51. };
  52. var hasBeenInitialized = false;
  53. /**
  54. * Encoder is the static container for the encodeFor* series and canonicalize methods. They are contained within
  55. * the encoder object so the plugin can take advantage of object freezing provided in ES5 to protect these methods
  56. * from being tampered with at runtime.
  57. */
  58. $.encoder = {
  59. author: 'Chris Schmidt (chris.schmidt@owasp.org)',
  60. version: '${project.version}',
  61. /**
  62. * Allows configuration of runtime options prior to using the plugin. Once the plugin has been initialized,
  63. * options cannot be changed.
  64. *
  65. * Possible Options:
  66. * <pre>
  67. * Options Description Default
  68. * ----------------------------------------------------------------------------
  69. * blacklist Enable blacklist validation true
  70. * </pre>
  71. *
  72. * @param opts
  73. */
  74. init: function(opts) {
  75. if ( hasBeenInitialized )
  76. throw "jQuery Encoder has already been initialized - cannot set options after initialization";
  77. hasBeenInitialized = true;
  78. $.extend( options, opts );
  79. },
  80. /**
  81. * Encodes the provided input in a manner safe to place between to HTML tags
  82. * @param input The untrusted input to be encoded
  83. */
  84. encodeForHTML: function(input) {
  85. hasBeenInitialized = true;
  86. var div = document.createElement('div');
  87. $(div).text(input);
  88. return $(div).html();
  89. },
  90. /**
  91. * Encodes the provided input in a manner safe to place in the value (between to "'s) in an HTML attribute.
  92. *
  93. * Unless directed not to, this method will return the full <code>attr="value"</code> as a string. If
  94. * <code>omitAttributeName</code> is true, the method will only return the <code>value</code>. Both the attribute
  95. * name and value are canonicalized and verified with whitelist and blacklist prior to returning.
  96. *
  97. * Example:
  98. * <pre>
  99. * $('#container').html('&lt;div ' + $.encoder.encodeForHTMLAttribute('class', untrustedData) + '/>');
  100. * </pre>
  101. *
  102. * @param attr The attribute to encode for
  103. * @param input The untrusted input to be encoded
  104. * @param omitAttributeName Whether to omit the attribute name and the enclosing quotes or not from the encoded
  105. * output.
  106. * @throws String Reports error when an unsafe attribute name or value is used (unencoded)
  107. * @throws String Reports error when attribute name contains invalid characters (unencoded)
  108. */
  109. encodeForHTMLAttribute: function(attr,input,omitAttributeName) {
  110. hasBeenInitialized = true;
  111. // Check for unsafe attributes
  112. attr = $.encoder.canonicalize(attr).toLowerCase();
  113. input = $.encoder.canonicalize(input);
  114. if ( $.inArray(attr, unsafeKeys['attr_name']) >= 0 ) {
  115. throw "Unsafe attribute name used: " + attr;
  116. }
  117. for ( var a=0; a < unsafeKeys['attr_val']; a++ ) {
  118. if ( input.toLowerCase().match(unsafeKeys['attr_val'][a]) ) {
  119. throw "Unsafe attribute value used: " + input;
  120. }
  121. }
  122. immune = attr_whitelist[attr];
  123. // If no whitelist exists for the attribute, use the minimal default whitelist
  124. if ( !immune ) immune = attr_whitelist_classes['default'];
  125. var encoded = '';
  126. if (!omitAttributeName) {
  127. for (var p = 0; p < attr.length; p++ ) {
  128. var pc = attr.charAt(p);
  129. if (!pc.match(/[a-zA-Z\-0-9]/)) {
  130. throw "Invalid attribute name specified";
  131. }
  132. encoded += pc;
  133. }
  134. encoded += '="';
  135. }
  136. for (var i = 0; i < input.length; i++) {
  137. var ch = input.charAt(i), cc = input.charCodeAt(i);
  138. if (!ch.match(/[a-zA-Z0-9]/) && $.inArray(ch, immune) < 0) {
  139. var hex = cc.toString(16);
  140. encoded += '&#x' + hex + ';';
  141. } else {
  142. encoded += ch;
  143. }
  144. }
  145. if (!omitAttributeName) {
  146. encoded += '"';
  147. }
  148. return encoded;
  149. },
  150. /**
  151. * Encodes the provided input in a manner safe to place in the value of an elements <code>style</code> attribute
  152. *
  153. * Unless directed not to, this method will return the full <code>property: value</code> as a string. If
  154. * <code>omitPropertyName</code> is <code>true</code>, the method will only return the <code>value</code>. Both
  155. * the property name and value are canonicalized and verified with whitelist and blacklist prior to returning.
  156. *
  157. * Example:
  158. * <pre>
  159. * $('#container').html('&lt;div style="' + $.encoder.encodeForCSS('background-image', untrustedData) + '"/>');
  160. * </pre>
  161. *
  162. * @param propName The property name that is being set
  163. * @param input The untrusted input to be encoded
  164. * @param omitPropertyName Whether to omit the property name from the encoded output
  165. *
  166. * @throws String Reports error when an unsafe property name or value is used
  167. * @throws String Reports error when illegal characters passed in property name
  168. */
  169. encodeForCSS: function(propName,input,omitPropertyName) {
  170. hasBeenInitialized = true;
  171. // Check for unsafe properties
  172. propName = $.encoder.canonicalize(propName).toLowerCase();
  173. input = $.encoder.canonicalize(input);
  174. if ( $.inArray(propName, unsafeKeys['css_key'] ) >= 0 ) {
  175. throw "Unsafe property name used: " + propName;
  176. }
  177. for ( var a=0; a < unsafeKeys['css_val'].length; a++ ) {
  178. if ( input.toLowerCase().indexOf(unsafeKeys['css_val'][a]) >= 0 ) {
  179. throw "Unsafe property value used: " + input;
  180. }
  181. }
  182. immune = css_whitelist[propName];
  183. // If no whitelist exists for that property, use the minimal default whitelist
  184. if ( !immune ) immune = css_whitelist_classes['default'];
  185. var encoded = '';
  186. if (!omitPropertyName) {
  187. for (var p = 0; p < propName.length; p++) {
  188. var pc = propName.charAt(p);
  189. if (!pc.match(/[a-zA-Z\-]/)) {
  190. throw "Invalid Property Name specified";
  191. }
  192. encoded += pc;
  193. }
  194. encoded += ': ';
  195. }
  196. for (var i = 0; i < input.length; i++) {
  197. var ch = input.charAt(i), cc = input.charCodeAt(i);
  198. if (!ch.match(/[a-zA-Z0-9]/) && $.inArray(ch, immune) < 0) {
  199. var hex = cc.toString(16);
  200. var pad = '000000'.substr((hex.length));
  201. encoded += '\\' + pad + hex;
  202. } else {
  203. encoded += ch;
  204. }
  205. }
  206. return encoded;
  207. },
  208. /**
  209. * Encodes the provided input in a manner safe to place in the value of a POST or GET parameter on a request. This
  210. * is primarily used to mitigate parameter-splitting attacks and ensure that parameter values are within specification
  211. *
  212. * @param input The untrusted data to be encoded
  213. * @param attr (optional) If passed in, the method will return the full string <code>attr="value"</code> where
  214. * the value will be encoded for a URL and both the attribute and value will be canonicalized prior
  215. * to encoding the value.
  216. */
  217. encodeForURL: function(input,attr) {
  218. hasBeenInitialized = true;
  219. var encoded = '';
  220. if (attr) {
  221. if (attr.match(/^[A-Za-z\-0-9]{1,}$/)) {
  222. encoded += $.encoder.canonicalize(attr).toLowerCase();
  223. } else {
  224. throw "Illegal Attribute Name Specified";
  225. }
  226. encoded += '="';
  227. }
  228. encoded += encodeURIComponent(input);
  229. encoded += attr ? '"' : '';
  230. return encoded;
  231. },
  232. /**
  233. * Encodes the provided input in a manner safe to place in a javascript context, such as the value of an entity
  234. * event like onmouseover. This encoding is slightly different than just encoding for an html attribute value as
  235. * it follows the escaping rules of javascript. Use this method when dynamically writing out html to an element
  236. * as opposed to building an element up using the DOM - as with the .html() method.
  237. *
  238. * Example $('#element').html('&lt;a onclick=somefunction(\'"' + $.encodeForJavascript($('#input').val()) + '\');">Blargh&lt;/a>');
  239. *
  240. * @param input The untrusted input to be encoded
  241. */
  242. encodeForJavascript: function(input) {
  243. hasBeenInitialized = true;
  244. if ( !immune ) immune = default_immune['js'];
  245. var encoded = '';
  246. for (var i=0; i < input.length; i++ ) {
  247. var ch = input.charAt(i), cc = input.charCodeAt(i);
  248. if ($.inArray(ch, immune) >= 0 || hex[cc] == null ) {
  249. encoded += ch;
  250. continue;
  251. }
  252. var temp = cc.toString(16), pad;
  253. if ( cc < 256 ) {
  254. pad = '00'.substr(temp.length);
  255. encoded += '\\x' + pad + temp.toUpperCase();
  256. } else {
  257. pad = '0000'.substr(temp.length);
  258. encoded += '\\u' + pad + temp.toUpperCase();
  259. }
  260. }
  261. return encoded;
  262. },
  263. /**
  264. * Encodes the provided input to allow only alphanumeric characters, '-' and '_'. Other charactesr are replaced with '_'.
  265. * This encoding allows for using the resulting value as a CSS or jQuery selector, but it cannot be reversed.
  266. *
  267. * @param input The untrusted input to be encoded
  268. */
  269. encodeForAlphaNumeric: function(input) {
  270. hasBeenInitialized = true;
  271. input = $.encoder.canonicalize(input);
  272. var encoded = '';
  273. for (var i = 0; i < input.length; i++) {
  274. var ch = input.charAt(i), cc = input.charCodeAt(i);
  275. if (!ch.match(/[a-zA-Z0-9-_]/)) {
  276. encoded += '_';
  277. } else {
  278. encoded += ch;
  279. }
  280. }
  281. return encoded;
  282. },
  283. canonicalize: function(input,strict) {
  284. hasBeenInitialized = true;
  285. if (input===null) return null;
  286. var out = input, cycle_out = input;
  287. var decodeCount = 0, cycles = 0;
  288. var codecs = [ new HTMLEntityCodec(), new PercentCodec(), new CSSCodec() ];
  289. while (true) {
  290. cycle_out = out;
  291. for (var i=0; i < codecs.length; i++ ) {
  292. var new_out = codecs[i].decode(out);
  293. if (new_out != out) {
  294. decodeCount++;
  295. out = new_out;
  296. }
  297. }
  298. if (cycle_out == out) {
  299. break;
  300. }
  301. cycles++;
  302. }
  303. if (strict && decodeCount > 1) {
  304. throw "Attack Detected - Multiple/Double Encodings used in input";
  305. }
  306. return out;
  307. }
  308. };
  309. var hex = [];
  310. for ( var c = 0; c < 0xFF; c++ ) {
  311. if ( c >= 0x30 && c <= 0x39 || c >= 0x41 && c <= 0x5a || c >= 0x61 && c <= 0x7a ) {
  312. hex[c] = null;
  313. } else {
  314. hex[c] = c.toString(16);
  315. }
  316. }
  317. var methods = {
  318. html: function(opts) {
  319. return $.encoder.encodeForHTML(opts.unsafe);
  320. },
  321. css: function(opts) {
  322. var work = [];
  323. var out = [];
  324. if (opts.map) {
  325. work = opts.map;
  326. } else {
  327. work[opts.name] = opts.unsafe;
  328. }
  329. for (var k in work) {
  330. if ( !(typeof work[k] == 'function') && work.hasOwnProperty(k) ) {
  331. out[k] = $.encoder.encodeForCSS(k, work[k], true);
  332. }
  333. }
  334. return out;
  335. },
  336. attr: function(opts) {
  337. var work = [];
  338. var out = [];
  339. if (opts.map) {
  340. work = opts.map;
  341. } else {
  342. work[opts.name] = opts.unsafe;
  343. }
  344. for (var k in work) {
  345. if ( ! (typeof work[k] == 'function') && work.hasOwnProperty(k) ) {
  346. out[k] = $.encoder.encodeForHTMLAttribute(k,work[k],true);
  347. }
  348. }
  349. return out;
  350. }
  351. };
  352. /**
  353. * Use this instead of setting the content of an element manually with untrusted user supplied data. The context can
  354. * be one of 'html', 'css', or 'attr'
  355. */
  356. $.fn.encode = function() {
  357. hasBeenInitialized = true;
  358. var argCount = arguments.length;
  359. var opts = {
  360. 'context' : 'html',
  361. 'unsafe' : null,
  362. 'name' : null,
  363. 'map' : null,
  364. 'setter' : null,
  365. 'strict' : true
  366. };
  367. if (argCount == 1 && typeof arguments[0] == 'object') {
  368. $.extend(opts, arguments[0]);
  369. } else {
  370. opts.context = arguments[0];
  371. if (arguments.length == 2) {
  372. if (opts.context == 'html') {
  373. opts.unsafe = arguments[1];
  374. }
  375. else if (opts.content == 'attr' || opts.content == 'css') {
  376. opts.map = arguments[1];
  377. }
  378. } else {
  379. opts.name = arguments[1];
  380. opts.unsafe = arguments[2];
  381. }
  382. }
  383. if (opts.context == 'html') {
  384. opts.setter = this.html;
  385. }
  386. else if (opts.context == 'css') {
  387. opts.setter = this.css;
  388. }
  389. else if (opts.context == 'attr') {
  390. opts.setter = this.attr;
  391. }
  392. return opts.setter.call(this, methods[opts.context].call(this, opts));
  393. };
  394. /**
  395. * The pushback string is used by Codecs to allow them to push decoded characters back onto a string for further
  396. * decoding. This is necessary to detect double-encoding.
  397. */
  398. var PushbackString = Class.extend({
  399. _input: null,
  400. _pushback: null,
  401. _temp: null,
  402. _index: 0,
  403. _mark: 0,
  404. _hasNext: function() {
  405. if ( this._input == null ) return false;
  406. if ( this._input.length == 0 ) return false;
  407. return this._index < this._input.length;
  408. },
  409. init: function(input) {
  410. this._input = input;
  411. },
  412. pushback: function(c) {
  413. this._pushback = c;
  414. },
  415. index: function() {
  416. return this._index;
  417. },
  418. hasNext: function() {
  419. if ( this._pushback != null ) return true;
  420. return this._hasNext();
  421. },
  422. next: function() {
  423. if ( this._pushback != null ) {
  424. var save = this._pushback;
  425. this._pushback = null;
  426. return save;
  427. }
  428. return ( this._hasNext() ) ? this._input.charAt( this._index++ ) : null;
  429. },
  430. nextHex: function() {
  431. var c = this.next();
  432. if ( c == null ) return null;
  433. if ( c.match(/[0-9A-Fa-f]/) ) return c;
  434. return null;
  435. },
  436. peek: function(c) {
  437. if (c) {
  438. if ( this._pushback && this._pushback == c ) return true;
  439. return this._hasNext() ? this._input.charAt(this._index) == c : false;
  440. }
  441. if ( this._pushback ) return this._pushback;
  442. return this._hasNext() ? this._input.charAt(this._index) : null;
  443. },
  444. mark: function() {
  445. this._temp = this._pushback;
  446. this._mark = this._index;
  447. },
  448. reset: function() {
  449. this._pushback = this._temp;
  450. this._index = this._mark;
  451. },
  452. remainder: function() {
  453. var out = this._input.substr( this._index );
  454. if ( this._pushback != null ) {
  455. out = this._pushback + out;
  456. }
  457. return out;
  458. }
  459. });
  460. /**
  461. * Base class for all codecs to extend. This class defines the default behavior or codecs
  462. */
  463. var Codec = Class.extend({
  464. decode: function(input) {
  465. var out = '', pbs = new PushbackString(input);
  466. while(pbs.hasNext()) {
  467. var c = this.decodeCharacter(pbs);
  468. if (c != null) {
  469. out += c;
  470. } else {
  471. out += pbs.next();
  472. }
  473. }
  474. return out;
  475. },
  476. /** @Abstract */
  477. decodeCharacter: function(pbs) {
  478. return pbs.next();
  479. }
  480. });
  481. /**
  482. * Codec for decoding HTML Entities in strings. This codec will decode named entities as well as numeric and hex
  483. * entities even with padding. For named entities, it interally uses a Trie to locate the 'best-match' and speed
  484. * up the search.
  485. */
  486. var HTMLEntityCodec = Codec.extend({
  487. decodeCharacter: function(input) {
  488. input.mark();
  489. var first = input.next();
  490. // If there is no input, or this is not an entity - return null
  491. if ( first == null || first != '&' ) {
  492. input.reset();
  493. return null;
  494. }
  495. var second = input.next();
  496. if ( second == null ) {
  497. input.reset();
  498. return null;
  499. }
  500. var c;
  501. if ( second == '#' ) {
  502. c = this._getNumericEntity(input);
  503. if ( c != null ) return c;
  504. } else if ( second.match(/[A-Za-z]/) ) {
  505. input.pushback(second);
  506. c = this._getNamedEntity(input);
  507. if ( c != null ) return c;
  508. }
  509. input.reset();
  510. return null;
  511. },
  512. _getNamedEntity: function(input) {
  513. var possible = '', entry, len;
  514. len = Math.min(input.remainder().length, ENTITY_TO_CHAR_TRIE.getMaxKeyLength());
  515. for(var i=0;i<len;i++) {
  516. possible += input.next().toLowerCase();
  517. }
  518. entry = ENTITY_TO_CHAR_TRIE.getLongestMatch(possible);
  519. if (entry == null)
  520. return null;
  521. input.reset();
  522. input.next();
  523. len = entry.getKey().length;
  524. for(var j=0;j<len;j++) {
  525. input.next();
  526. }
  527. if(input.peek(';'))
  528. input.next();
  529. return entry.getValue();
  530. },
  531. _getNumericEntity: function(input) {
  532. var first = input.peek();
  533. if ( first == null ) return null;
  534. if (first == 'x' || first == 'X' ) {
  535. input.next();
  536. return this._parseHex(input);
  537. }
  538. return this._parseNumber(input);
  539. },
  540. _parseHex: function(input) {
  541. var out = '';
  542. while (input.hasNext()) {
  543. var c = input.peek();
  544. if ( !isNaN( parseInt(c, 16) ) ) {
  545. out += c;
  546. input.next();
  547. } else if ( c == ';' ) {
  548. input.next();
  549. break;
  550. } else {
  551. break;
  552. }
  553. }
  554. var i = parseInt(out,16);
  555. if ( !isNaN(i) && isValidCodePoint(i) ) return String.fromCharCode(i);
  556. return null;
  557. },
  558. _parseNumber: function(input) {
  559. var out = '';
  560. while (input.hasNext()) {
  561. var ch = input.peek();
  562. if ( !isNaN( parseInt(ch,10) ) ) {
  563. out += ch;
  564. input.next();
  565. } else if ( ch == ';' ) {
  566. input.next();
  567. break;
  568. } else {
  569. break;
  570. }
  571. }
  572. var i = parseInt(out,10);
  573. if ( !isNaN(i) && isValidCodePoint(i) ) return String.fromCharCode(i);
  574. return null;
  575. }
  576. });
  577. /**
  578. * Codec for decoding url-encoded strings.
  579. */
  580. var PercentCodec = Codec.extend({
  581. decodeCharacter: function(input) {
  582. input.mark();
  583. var first = input.next();
  584. if ( first == null ) {
  585. input.reset();
  586. return null;
  587. }
  588. if ( first != '%' ) {
  589. input.reset();
  590. return null;
  591. }
  592. var out = '';
  593. for (var i=0;i<2;i++) {
  594. var c = input.nextHex();
  595. if( c != null ) out += c;
  596. }
  597. if (out.length == 2) {
  598. var p = parseInt(out, 16);
  599. if ( isValidCodePoint(p) )
  600. return String.fromCharCode(p);
  601. }
  602. input.reset();
  603. return null;
  604. }
  605. });
  606. /**
  607. * Codec for decoding CSS escaped text. This codec will decode both decimal and hex values.
  608. */
  609. var CSSCodec = Codec.extend({
  610. decodeCharacter: function(input) {
  611. input.mark();
  612. var first = input.next();
  613. if (first==null || first != '\\') {
  614. input.reset();
  615. return null;
  616. }
  617. var second = input.next();
  618. if (second==null) {
  619. input.reset();
  620. return null;
  621. }
  622. // fallthrough logic is intentional here
  623. // noinspection FallthroughInSwitchStatementJS
  624. switch(second) {
  625. case '\r':
  626. if (input.peek('\n')) {
  627. input.next();
  628. }
  629. case '\n':
  630. case '\f':
  631. case '\u0000':
  632. return this.decodeCharacter(input);
  633. }
  634. if ( parseInt(second,16) == 'NaN' ) {
  635. return second;
  636. }
  637. var out = second;
  638. for(var j=0;j<5;j++) {
  639. var c = input.next();
  640. if (c==null || isWhiteSpace(c)) {
  641. break;
  642. }
  643. if (parseInt(c,16) != 'NaN') {
  644. out += c;
  645. } else {
  646. input.pushback(c);
  647. break;
  648. }
  649. }
  650. var p = parseInt(out,16);
  651. if (isValidCodePoint(p))
  652. return String.fromCharCode(p);
  653. return '\ufffd';
  654. }
  655. });
  656. /**
  657. * Trie implementation for Javascript for fast querying and longest matching string lookups.
  658. */
  659. var Trie = Class.extend({
  660. root: null,
  661. maxKeyLen: 0,
  662. size: 0,
  663. init: function() { this.clear(); },
  664. getLongestMatch: function(key) {
  665. return ( this.root == null && key == null ) ? null : this.root.getLongestMatch(key,0);
  666. },
  667. getMaxKeyLength: function() { return this.maxKeyLen; },
  668. clear: function() { this.root = null, this.maxKeyLen = 0, this.size = 0; },
  669. put: function(key,val) {
  670. var len, old;
  671. if (this.root==null)
  672. this.root = new Trie.Node();
  673. if ((old=this.root.put(key,0,val))!=null)
  674. return old;
  675. if ((len=key.length) > this.maxKeyLen )
  676. this.maxKeyLen=key.length;
  677. this.size++;
  678. return null;
  679. }
  680. });
  681. Trie.Entry = Class.extend({
  682. _key: null,
  683. _value: null,
  684. init: function(key,value) { this._key = key, this._value = value; },
  685. getKey: function() { return this._key; },
  686. getValue: function() { return this._value; },
  687. equals: function(other) {
  688. if ( !(other instanceof Trie.Entry) ) {
  689. return false;
  690. }
  691. return this._key == other._key && this._value == other._value;
  692. }
  693. });
  694. Trie.Node = Class.extend({
  695. _value: null,
  696. _nextMap: null,
  697. setValue: function(value) { this._value = value; },
  698. getNextNode: function(ch) {
  699. if ( !this._nextMap ) return null;
  700. return this._nextMap[ch];
  701. },
  702. /**
  703. * Recursively add a key
  704. * @param key The key being added
  705. * @param pos The position in key that is being handled in this recursion
  706. * @param value The value of what that key points to
  707. */
  708. put: function(key,pos,value) {
  709. var nextNode, ch, old;
  710. // Terminating Node Clause (break out of recursion)
  711. if (key.length == pos) {
  712. old = this._value;
  713. this.setValue(value);
  714. return old;
  715. }
  716. ch = key.charAt(pos);
  717. if (this._nextMap==null) {
  718. this._nextMap = Trie.Node.newNodeMap();
  719. nextNode = new Trie.Node();
  720. this._nextMap[ch] = nextNode;
  721. } else if ((nextNode=this._nextMap[ch]) == null) {
  722. nextNode = new Trie.Node();
  723. this._nextMap[ch] = nextNode;
  724. }
  725. return nextNode.put(key,pos+1,value);
  726. },
  727. /**
  728. * Recursively lookup a key's value
  729. * @param key The key being looked up
  730. * @param pos The position in key that is being handled in this recursion
  731. */
  732. get: function(key,pos) {
  733. var nextNode;
  734. if (key.length <= pos)
  735. return this._value;
  736. if ((nextNode=this.getNextNode(key.charAt(pos))) == null)
  737. return null;
  738. return nextNode.get(key,pos+1);
  739. },
  740. /**
  741. * Recusrsively lookup the longest key match
  742. * @param key The key being looked up
  743. * @param pos The position in the key for the current recursion
  744. */
  745. getLongestMatch: function(key,pos) {
  746. var nextNode, ret;
  747. if (key.length <= pos) {
  748. return Trie.Entry.newInstanceIfNeeded(key,this._value);
  749. }
  750. if ((nextNode=this.getNextNode(key.charAt(pos)))==null) {
  751. // Last in Trie - return this value
  752. return Trie.Entry.newInstanceIfNeeded(key,pos,this._value);
  753. }
  754. if ((ret=nextNode.getLongestMatch(key,pos+1))!=null) {
  755. return ret;
  756. }
  757. return Trie.Entry.newInstanceIfNeeded(key,pos,this._value);
  758. }
  759. });
  760. Trie.Entry.newInstanceIfNeeded = function() {
  761. var key = arguments[0], value, keyLength;
  762. if ( typeof arguments[1] == 'string' ) {
  763. value = arguments[1];
  764. keyLength = key.length;
  765. } else {
  766. keyLength = arguments[1];
  767. value = arguments[2];
  768. }
  769. if (value==null || key==null) {
  770. return null;
  771. }
  772. if (key.length > keyLength) {
  773. key = key.substr(0,keyLength);
  774. }
  775. return new Trie.Entry(key,value);
  776. };
  777. Trie.Node.newNodeMap = function() {
  778. return {};
  779. };
  780. /**
  781. * Match the Java implementation of the isValidCodePoint check
  782. * @param codepoint codepoint to check
  783. */
  784. var isValidCodePoint = function(codepoint) {
  785. return codepoint >= 0x0000 && codepoint <= 0x10FFFF;
  786. };
  787. /**
  788. * Perform a quick whitespace check on the supplied string.
  789. * @param input string to check
  790. */
  791. var isWhiteSpace = function(input) {
  792. return input.match(/[\s]/);
  793. };
  794. // TODO: There has to be a better way to do this. These are only here for canonicalization
  795. var MAP_ENTITY_TO_CHAR = [];
  796. var MAP_CHAR_TO_ENTITY = [];
  797. var ENTITY_TO_CHAR_TRIE = new Trie();
  798. (function(){
  799. MAP_ENTITY_TO_CHAR["&quot"] = "34";
  800. /* 34 : quotation mark */
  801. MAP_ENTITY_TO_CHAR["&amp"] = "38";
  802. /* 38 : ampersand */
  803. MAP_ENTITY_TO_CHAR["&lt"] = "60";
  804. /* 60 : less-than sign */
  805. MAP_ENTITY_TO_CHAR["&gt"] = "62";
  806. /* 62 : greater-than sign */
  807. MAP_ENTITY_TO_CHAR["&nbsp"] = "160";
  808. /* 160 : no-break space */
  809. MAP_ENTITY_TO_CHAR["&iexcl"] = "161";
  810. /* 161 : inverted exclamation mark */
  811. MAP_ENTITY_TO_CHAR["&cent"] = "162";
  812. /* 162 : cent sign */
  813. MAP_ENTITY_TO_CHAR["&pound"] = "163";
  814. /* 163 : pound sign */
  815. MAP_ENTITY_TO_CHAR["&curren"] = "164";
  816. /* 164 : currency sign */
  817. MAP_ENTITY_TO_CHAR["&yen"] = "165";
  818. /* 165 : yen sign */
  819. MAP_ENTITY_TO_CHAR["&brvbar"] = "166";
  820. /* 166 : broken bar */
  821. MAP_ENTITY_TO_CHAR["&sect"] = "167";
  822. /* 167 : section sign */
  823. MAP_ENTITY_TO_CHAR["&uml"] = "168";
  824. /* 168 : diaeresis */
  825. MAP_ENTITY_TO_CHAR["&copy"] = "169";
  826. /* 169 : copyright sign */
  827. MAP_ENTITY_TO_CHAR["&ordf"] = "170";
  828. /* 170 : feminine ordinal indicator */
  829. MAP_ENTITY_TO_CHAR["&laquo"] = "171";
  830. /* 171 : left-pointing double angle quotation mark */
  831. MAP_ENTITY_TO_CHAR["&not"] = "172";
  832. /* 172 : not sign */
  833. MAP_ENTITY_TO_CHAR["&shy"] = "173";
  834. /* 173 : soft hyphen */
  835. MAP_ENTITY_TO_CHAR["&reg"] = "174";
  836. /* 174 : registered sign */
  837. MAP_ENTITY_TO_CHAR["&macr"] = "175";
  838. /* 175 : macron */
  839. MAP_ENTITY_TO_CHAR["&deg"] = "176";
  840. /* 176 : degree sign */
  841. MAP_ENTITY_TO_CHAR["&plusmn"] = "177";
  842. /* 177 : plus-minus sign */
  843. MAP_ENTITY_TO_CHAR["&sup2"] = "178";
  844. /* 178 : superscript two */
  845. MAP_ENTITY_TO_CHAR["&sup3"] = "179";
  846. /* 179 : superscript three */
  847. MAP_ENTITY_TO_CHAR["&acute"] = "180";
  848. /* 180 : acute accent */
  849. MAP_ENTITY_TO_CHAR["&micro"] = "181";
  850. /* 181 : micro sign */
  851. MAP_ENTITY_TO_CHAR["&para"] = "182";
  852. /* 182 : pilcrow sign */
  853. MAP_ENTITY_TO_CHAR["&middot"] = "183";
  854. /* 183 : middle dot */
  855. MAP_ENTITY_TO_CHAR["&cedil"] = "184";
  856. /* 184 : cedilla */
  857. MAP_ENTITY_TO_CHAR["&sup1"] = "185";
  858. /* 185 : superscript one */
  859. MAP_ENTITY_TO_CHAR["&ordm"] = "186";
  860. /* 186 : masculine ordinal indicator */
  861. MAP_ENTITY_TO_CHAR["&raquo"] = "187";
  862. /* 187 : right-pointing double angle quotation mark */
  863. MAP_ENTITY_TO_CHAR["&frac14"] = "188";
  864. /* 188 : vulgar fraction one quarter */
  865. MAP_ENTITY_TO_CHAR["&frac12"] = "189";
  866. /* 189 : vulgar fraction one half */
  867. MAP_ENTITY_TO_CHAR["&frac34"] = "190";
  868. /* 190 : vulgar fraction three quarters */
  869. MAP_ENTITY_TO_CHAR["&iquest"] = "191";
  870. /* 191 : inverted question mark */
  871. MAP_ENTITY_TO_CHAR["&Agrave"] = "192";
  872. /* 192 : Latin capital letter a with grave */
  873. MAP_ENTITY_TO_CHAR["&Aacute"] = "193";
  874. /* 193 : Latin capital letter a with acute */
  875. MAP_ENTITY_TO_CHAR["&Acirc"] = "194";
  876. /* 194 : Latin capital letter a with circumflex */
  877. MAP_ENTITY_TO_CHAR["&Atilde"] = "195";
  878. /* 195 : Latin capital letter a with tilde */
  879. MAP_ENTITY_TO_CHAR["&Auml"] = "196";
  880. /* 196 : Latin capital letter a with diaeresis */
  881. MAP_ENTITY_TO_CHAR["&Aring"] = "197";
  882. /* 197 : Latin capital letter a with ring above */
  883. MAP_ENTITY_TO_CHAR["&AElig"] = "198";
  884. /* 198 : Latin capital letter ae */
  885. MAP_ENTITY_TO_CHAR["&Ccedil"] = "199";
  886. /* 199 : Latin capital letter c with cedilla */
  887. MAP_ENTITY_TO_CHAR["&Egrave"] = "200";
  888. /* 200 : Latin capital letter e with grave */
  889. MAP_ENTITY_TO_CHAR["&Eacute"] = "201";
  890. /* 201 : Latin capital letter e with acute */
  891. MAP_ENTITY_TO_CHAR["&Ecirc"] = "202";
  892. /* 202 : Latin capital letter e with circumflex */
  893. MAP_ENTITY_TO_CHAR["&Euml"] = "203";
  894. /* 203 : Latin capital letter e with diaeresis */
  895. MAP_ENTITY_TO_CHAR["&Igrave"] = "204";
  896. /* 204 : Latin capital letter i with grave */
  897. MAP_ENTITY_TO_CHAR["&Iacute"] = "205";
  898. /* 205 : Latin capital letter i with acute */
  899. MAP_ENTITY_TO_CHAR["&Icirc"] = "206";
  900. /* 206 : Latin capital letter i with circumflex */
  901. MAP_ENTITY_TO_CHAR["&Iuml"] = "207";
  902. /* 207 : Latin capital letter i with diaeresis */
  903. MAP_ENTITY_TO_CHAR["&ETH"] = "208";
  904. /* 208 : Latin capital letter eth */
  905. MAP_ENTITY_TO_CHAR["&Ntilde"] = "209";
  906. /* 209 : Latin capital letter n with tilde */
  907. MAP_ENTITY_TO_CHAR["&Ograve"] = "210";
  908. /* 210 : Latin capital letter o with grave */
  909. MAP_ENTITY_TO_CHAR["&Oacute"] = "211";
  910. /* 211 : Latin capital letter o with acute */
  911. MAP_ENTITY_TO_CHAR["&Ocirc"] = "212";
  912. /* 212 : Latin capital letter o with circumflex */
  913. MAP_ENTITY_TO_CHAR["&Otilde"] = "213";
  914. /* 213 : Latin capital letter o with tilde */
  915. MAP_ENTITY_TO_CHAR["&Ouml"] = "214";
  916. /* 214 : Latin capital letter o with diaeresis */
  917. MAP_ENTITY_TO_CHAR["&times"] = "215";
  918. /* 215 : multiplication sign */
  919. MAP_ENTITY_TO_CHAR["&Oslash"] = "216";
  920. /* 216 : Latin capital letter o with stroke */
  921. MAP_ENTITY_TO_CHAR["&Ugrave"] = "217";
  922. /* 217 : Latin capital letter u with grave */
  923. MAP_ENTITY_TO_CHAR["&Uacute"] = "218";
  924. /* 218 : Latin capital letter u with acute */
  925. MAP_ENTITY_TO_CHAR["&Ucirc"] = "219";
  926. /* 219 : Latin capital letter u with circumflex */
  927. MAP_ENTITY_TO_CHAR["&Uuml"] = "220";
  928. /* 220 : Latin capital letter u with diaeresis */
  929. MAP_ENTITY_TO_CHAR["&Yacute"] = "221";
  930. /* 221 : Latin capital letter y with acute */
  931. MAP_ENTITY_TO_CHAR["&THORN"] = "222";
  932. /* 222 : Latin capital letter thorn */
  933. MAP_ENTITY_TO_CHAR["&szlig"] = "223";
  934. /* 223 : Latin small letter sharp s, German Eszett */
  935. MAP_ENTITY_TO_CHAR["&agrave"] = "224";
  936. /* 224 : Latin small letter a with grave */
  937. MAP_ENTITY_TO_CHAR["&aacute"] = "225";
  938. /* 225 : Latin small letter a with acute */
  939. MAP_ENTITY_TO_CHAR["&acirc"] = "226";
  940. /* 226 : Latin small letter a with circumflex */
  941. MAP_ENTITY_TO_CHAR["&atilde"] = "227";
  942. /* 227 : Latin small letter a with tilde */
  943. MAP_ENTITY_TO_CHAR["&auml"] = "228";
  944. /* 228 : Latin small letter a with diaeresis */
  945. MAP_ENTITY_TO_CHAR["&aring"] = "229";
  946. /* 229 : Latin small letter a with ring above */
  947. MAP_ENTITY_TO_CHAR["&aelig"] = "230";
  948. /* 230 : Latin lowercase ligature ae */
  949. MAP_ENTITY_TO_CHAR["&ccedil"] = "231";
  950. /* 231 : Latin small letter c with cedilla */
  951. MAP_ENTITY_TO_CHAR["&egrave"] = "232";
  952. /* 232 : Latin small letter e with grave */
  953. MAP_ENTITY_TO_CHAR["&eacute"] = "233";
  954. /* 233 : Latin small letter e with acute */
  955. MAP_ENTITY_TO_CHAR["&ecirc"] = "234";
  956. /* 234 : Latin small letter e with circumflex */
  957. MAP_ENTITY_TO_CHAR["&euml"] = "235";
  958. /* 235 : Latin small letter e with diaeresis */
  959. MAP_ENTITY_TO_CHAR["&igrave"] = "236";
  960. /* 236 : Latin small letter i with grave */
  961. MAP_ENTITY_TO_CHAR["&iacute"] = "237";
  962. /* 237 : Latin small letter i with acute */
  963. MAP_ENTITY_TO_CHAR["&icirc"] = "238";
  964. /* 238 : Latin small letter i with circumflex */
  965. MAP_ENTITY_TO_CHAR["&iuml"] = "239";
  966. /* 239 : Latin small letter i with diaeresis */
  967. MAP_ENTITY_TO_CHAR["&eth"] = "240";
  968. /* 240 : Latin small letter eth */
  969. MAP_ENTITY_TO_CHAR["&ntilde"] = "241";
  970. /* 241 : Latin small letter n with tilde */
  971. MAP_ENTITY_TO_CHAR["&ograve"] = "242";
  972. /* 242 : Latin small letter o with grave */
  973. MAP_ENTITY_TO_CHAR["&oacute"] = "243";
  974. /* 243 : Latin small letter o with acute */
  975. MAP_ENTITY_TO_CHAR["&ocirc"] = "244";
  976. /* 244 : Latin small letter o with circumflex */
  977. MAP_ENTITY_TO_CHAR["&otilde"] = "245";
  978. /* 245 : Latin small letter o with tilde */
  979. MAP_ENTITY_TO_CHAR["&ouml"] = "246";
  980. /* 246 : Latin small letter o with diaeresis */
  981. MAP_ENTITY_TO_CHAR["&divide"] = "247";
  982. /* 247 : division sign */
  983. MAP_ENTITY_TO_CHAR["&oslash"] = "248";
  984. /* 248 : Latin small letter o with stroke */
  985. MAP_ENTITY_TO_CHAR["&ugrave"] = "249";
  986. /* 249 : Latin small letter u with grave */
  987. MAP_ENTITY_TO_CHAR["&uacute"] = "250";
  988. /* 250 : Latin small letter u with acute */
  989. MAP_ENTITY_TO_CHAR["&ucirc"] = "251";
  990. /* 251 : Latin small letter u with circumflex */
  991. MAP_ENTITY_TO_CHAR["&uuml"] = "252";
  992. /* 252 : Latin small letter u with diaeresis */
  993. MAP_ENTITY_TO_CHAR["&yacute"] = "253";
  994. /* 253 : Latin small letter y with acute */
  995. MAP_ENTITY_TO_CHAR["&thorn"] = "254";
  996. /* 254 : Latin small letter thorn */
  997. MAP_ENTITY_TO_CHAR["&yuml"] = "255";
  998. /* 255 : Latin small letter y with diaeresis */
  999. MAP_ENTITY_TO_CHAR["&OElig"] = "338";
  1000. /* 338 : Latin capital ligature oe */
  1001. MAP_ENTITY_TO_CHAR["&oelig"] = "339";
  1002. /* 339 : Latin small ligature oe */
  1003. MAP_ENTITY_TO_CHAR["&Scaron"] = "352";
  1004. /* 352 : Latin capital letter s with caron */
  1005. MAP_ENTITY_TO_CHAR["&scaron"] = "353";
  1006. /* 353 : Latin small letter s with caron */
  1007. MAP_ENTITY_TO_CHAR["&Yuml"] = "376";
  1008. /* 376 : Latin capital letter y with diaeresis */
  1009. MAP_ENTITY_TO_CHAR["&fnof"] = "402";
  1010. /* 402 : Latin small letter f with hook */
  1011. MAP_ENTITY_TO_CHAR["&circ"] = "710";
  1012. /* 710 : modifier letter circumflex accent */
  1013. MAP_ENTITY_TO_CHAR["&tilde"] = "732";
  1014. /* 732 : small tilde */
  1015. MAP_ENTITY_TO_CHAR["&Alpha"] = "913";
  1016. /* 913 : Greek capital letter alpha */
  1017. MAP_ENTITY_TO_CHAR["&Beta"] = "914";
  1018. /* 914 : Greek capital letter beta */
  1019. MAP_ENTITY_TO_CHAR["&Gamma"] = "915";
  1020. /* 915 : Greek capital letter gamma */
  1021. MAP_ENTITY_TO_CHAR["&Delta"] = "916";
  1022. /* 916 : Greek capital letter delta */
  1023. MAP_ENTITY_TO_CHAR["&Epsilon"] = "917";
  1024. /* 917 : Greek capital letter epsilon */
  1025. MAP_ENTITY_TO_CHAR["&Zeta"] = "918";
  1026. /* 918 : Greek capital letter zeta */
  1027. MAP_ENTITY_TO_CHAR["&Eta"] = "919";
  1028. /* 919 : Greek capital letter eta */
  1029. MAP_ENTITY_TO_CHAR["&Theta"] = "920";
  1030. /* 920 : Greek capital letter theta */
  1031. MAP_ENTITY_TO_CHAR["&Iota"] = "921";
  1032. /* 921 : Greek capital letter iota */
  1033. MAP_ENTITY_TO_CHAR["&Kappa"] = "922";
  1034. /* 922 : Greek capital letter kappa */
  1035. MAP_ENTITY_TO_CHAR["&Lambda"] = "923";
  1036. /* 923 : Greek capital letter lambda */
  1037. MAP_ENTITY_TO_CHAR["&Mu"] = "924";
  1038. /* 924 : Greek capital letter mu */
  1039. MAP_ENTITY_TO_CHAR["&Nu"] = "925";
  1040. /* 925 : Greek capital letter nu */
  1041. MAP_ENTITY_TO_CHAR["&Xi"] = "926";
  1042. /* 926 : Greek capital letter xi */
  1043. MAP_ENTITY_TO_CHAR["&Omicron"] = "927";
  1044. /* 927 : Greek capital letter omicron */
  1045. MAP_ENTITY_TO_CHAR["&Pi"] = "928";
  1046. /* 928 : Greek capital letter pi */
  1047. MAP_ENTITY_TO_CHAR["&Rho"] = "929";
  1048. /* 929 : Greek capital letter rho */
  1049. MAP_ENTITY_TO_CHAR["&Sigma"] = "931";
  1050. /* 931 : Greek capital letter sigma */
  1051. MAP_ENTITY_TO_CHAR["&Tau"] = "932";
  1052. /* 932 : Greek capital letter tau */
  1053. MAP_ENTITY_TO_CHAR["&Upsilon"] = "933";
  1054. /* 933 : Greek capital letter upsilon */
  1055. MAP_ENTITY_TO_CHAR["&Phi"] = "934";
  1056. /* 934 : Greek capital letter phi */
  1057. MAP_ENTITY_TO_CHAR["&Chi"] = "935";
  1058. /* 935 : Greek capital letter chi */
  1059. MAP_ENTITY_TO_CHAR["&Psi"] = "936";
  1060. /* 936 : Greek capital letter psi */
  1061. MAP_ENTITY_TO_CHAR["&Omega"] = "937";
  1062. /* 937 : Greek capital letter omega */
  1063. MAP_ENTITY_TO_CHAR["&alpha"] = "945";
  1064. /* 945 : Greek small letter alpha */
  1065. MAP_ENTITY_TO_CHAR["&beta"] = "946";
  1066. /* 946 : Greek small letter beta */
  1067. MAP_ENTITY_TO_CHAR["&gamma"] = "947";
  1068. /* 947 : Greek small letter gamma */
  1069. MAP_ENTITY_TO_CHAR["&delta"] = "948";
  1070. /* 948 : Greek small letter delta */
  1071. MAP_ENTITY_TO_CHAR["&epsilon"] = "949";
  1072. /* 949 : Greek small letter epsilon */
  1073. MAP_ENTITY_TO_CHAR["&zeta"] = "950";
  1074. /* 950 : Greek small letter zeta */
  1075. MAP_ENTITY_TO_CHAR["&eta"] = "951";
  1076. /* 951 : Greek small letter eta */
  1077. MAP_ENTITY_TO_CHAR["&theta"] = "952";
  1078. /* 952 : Greek small letter theta */
  1079. MAP_ENTITY_TO_CHAR["&iota"] = "953";
  1080. /* 953 : Greek small letter iota */
  1081. MAP_ENTITY_TO_CHAR["&kappa"] = "954";
  1082. /* 954 : Greek small letter kappa */
  1083. MAP_ENTITY_TO_CHAR["&lambda"] = "955";
  1084. /* 955 : Greek small letter lambda */
  1085. MAP_ENTITY_TO_CHAR["&mu"] = "956";
  1086. /* 956 : Greek small letter mu */
  1087. MAP_ENTITY_TO_CHAR["&nu"] = "957";
  1088. /* 957 : Greek small letter nu */
  1089. MAP_ENTITY_TO_CHAR["&xi"] = "958";
  1090. /* 958 : Greek small letter xi */
  1091. MAP_ENTITY_TO_CHAR["&omicron"] = "959";
  1092. /* 959 : Greek small letter omicron */
  1093. MAP_ENTITY_TO_CHAR["&pi"] = "960";
  1094. /* 960 : Greek small letter pi */
  1095. MAP_ENTITY_TO_CHAR["&rho"] = "961";
  1096. /* 961 : Greek small letter rho */
  1097. MAP_ENTITY_TO_CHAR["&sigmaf"] = "962";
  1098. /* 962 : Greek small letter final sigma */
  1099. MAP_ENTITY_TO_CHAR["&sigma"] = "963";
  1100. /* 963 : Greek small letter sigma */
  1101. MAP_ENTITY_TO_CHAR["&tau"] = "964";
  1102. /* 964 : Greek small letter tau */
  1103. MAP_ENTITY_TO_CHAR["&upsilon"] = "965";
  1104. /* 965 : Greek small letter upsilon */
  1105. MAP_ENTITY_TO_CHAR["&phi"] = "966";
  1106. /* 966 : Greek small letter phi */
  1107. MAP_ENTITY_TO_CHAR["&chi"] = "967";
  1108. /* 967 : Greek small letter chi */
  1109. MAP_ENTITY_TO_CHAR["&psi"] = "968";
  1110. /* 968 : Greek small letter psi */
  1111. MAP_ENTITY_TO_CHAR["&omega"] = "969";
  1112. /* 969 : Greek small letter omega */
  1113. MAP_ENTITY_TO_CHAR["&thetasym"] = "977";
  1114. /* 977 : Greek theta symbol */
  1115. MAP_ENTITY_TO_CHAR["&upsih"] = "978";
  1116. /* 978 : Greek upsilon with hook symbol */
  1117. MAP_ENTITY_TO_CHAR["&piv"] = "982";
  1118. /* 982 : Greek pi symbol */
  1119. MAP_ENTITY_TO_CHAR["&ensp"] = "8194";
  1120. /* 8194 : en space */
  1121. MAP_ENTITY_TO_CHAR["&emsp"] = "8195";
  1122. /* 8195 : em space */
  1123. MAP_ENTITY_TO_CHAR["&thinsp"] = "8201";
  1124. /* 8201 : thin space */
  1125. MAP_ENTITY_TO_CHAR["&zwnj"] = "8204";
  1126. /* 8204 : zero width non-joiner */
  1127. MAP_ENTITY_TO_CHAR["&zwj"] = "8205";
  1128. /* 8205 : zero width joiner */
  1129. MAP_ENTITY_TO_CHAR["&lrm"] = "8206";
  1130. /* 8206 : left-to-right mark */
  1131. MAP_ENTITY_TO_CHAR["&rlm"] = "8207";
  1132. /* 8207 : right-to-left mark */
  1133. MAP_ENTITY_TO_CHAR["&ndash"] = "8211";
  1134. /* 8211 : en dash */
  1135. MAP_ENTITY_TO_CHAR["&mdash"] = "8212";
  1136. /* 8212 : em dash */
  1137. MAP_ENTITY_TO_CHAR["&lsquo"] = "8216";
  1138. /* 8216 : left single quotation mark */
  1139. MAP_ENTITY_TO_CHAR["&rsquo"] = "8217";
  1140. /* 8217 : right single quotation mark */
  1141. MAP_ENTITY_TO_CHAR["&sbquo"] = "8218";
  1142. /* 8218 : single low-9 quotation mark */
  1143. MAP_ENTITY_TO_CHAR["&ldquo"] = "8220";
  1144. /* 8220 : left double quotation mark */
  1145. MAP_ENTITY_TO_CHAR["&rdquo"] = "8221";
  1146. /* 8221 : right double quotation mark */
  1147. MAP_ENTITY_TO_CHAR["&bdquo"] = "8222";
  1148. /* 8222 : double low-9 quotation mark */
  1149. MAP_ENTITY_TO_CHAR["&dagger"] = "8224";
  1150. /* 8224 : dagger */
  1151. MAP_ENTITY_TO_CHAR["&Dagger"] = "8225";
  1152. /* 8225 : double dagger */
  1153. MAP_ENTITY_TO_CHAR["&bull"] = "8226";
  1154. /* 8226 : bullet */
  1155. MAP_ENTITY_TO_CHAR["&hellip"] = "8230";
  1156. /* 8230 : horizontal ellipsis */
  1157. MAP_ENTITY_TO_CHAR["&permil"] = "8240";
  1158. /* 8240 : per mille sign */
  1159. MAP_ENTITY_TO_CHAR["&prime"] = "8242";
  1160. /* 8242 : prime */
  1161. MAP_ENTITY_TO_CHAR["&Prime"] = "8243";
  1162. /* 8243 : double prime */
  1163. MAP_ENTITY_TO_CHAR["&lsaquo"] = "8249";
  1164. /* 8249 : single left-pointing angle quotation mark */
  1165. MAP_ENTITY_TO_CHAR["&rsaquo"] = "8250";
  1166. /* 8250 : single right-pointing angle quotation mark */
  1167. MAP_ENTITY_TO_CHAR["&oline"] = "8254";
  1168. /* 8254 : overline */
  1169. MAP_ENTITY_TO_CHAR["&frasl"] = "8260";
  1170. /* 8260 : fraction slash */
  1171. MAP_ENTITY_TO_CHAR["&euro"] = "8364";
  1172. /* 8364 : euro sign */
  1173. MAP_ENTITY_TO_CHAR["&image"] = "8365";
  1174. /* 8465 : black-letter capital i */
  1175. MAP_ENTITY_TO_CHAR["&weierp"] = "8472";
  1176. /* 8472 : script capital p, Weierstrass p */
  1177. MAP_ENTITY_TO_CHAR["&real"] = "8476";
  1178. /* 8476 : black-letter capital r */
  1179. MAP_ENTITY_TO_CHAR["&trade"] = "8482";
  1180. /* 8482 : trademark sign */
  1181. MAP_ENTITY_TO_CHAR["&alefsym"] = "8501";
  1182. /* 8501 : alef symbol */
  1183. MAP_ENTITY_TO_CHAR["&larr"] = "8592";
  1184. /* 8592 : leftwards arrow */
  1185. MAP_ENTITY_TO_CHAR["&uarr"] = "8593";
  1186. /* 8593 : upwards arrow */
  1187. MAP_ENTITY_TO_CHAR["&rarr"] = "8594";
  1188. /* 8594 : rightwards arrow */
  1189. MAP_ENTITY_TO_CHAR["&darr"] = "8595";
  1190. /* 8595 : downwards arrow */
  1191. MAP_ENTITY_TO_CHAR["&harr"] = "8596";
  1192. /* 8596 : left right arrow */
  1193. MAP_ENTITY_TO_CHAR["&crarr"] = "8629";
  1194. /* 8629 : downwards arrow with corner leftwards */
  1195. MAP_ENTITY_TO_CHAR["&lArr"] = "8656";
  1196. /* 8656 : leftwards double arrow */
  1197. MAP_ENTITY_TO_CHAR["&uArr"] = "8657";
  1198. /* 8657 : upwards double arrow */
  1199. MAP_ENTITY_TO_CHAR["&rArr"] = "8658";
  1200. /* 8658 : rightwards double arrow */
  1201. MAP_ENTITY_TO_CHAR["&dArr"] = "8659";
  1202. /* 8659 : downwards double arrow */
  1203. MAP_ENTITY_TO_CHAR["&hArr"] = "8660";
  1204. /* 8660 : left right double arrow */
  1205. MAP_ENTITY_TO_CHAR["&forall"] = "8704";
  1206. /* 8704 : for all */
  1207. MAP_ENTITY_TO_CHAR["&part"] = "8706";
  1208. /* 8706 : partial differential */
  1209. MAP_ENTITY_TO_CHAR["&exist"] = "8707";
  1210. /* 8707 : there exists */
  1211. MAP_ENTITY_TO_CHAR["&empty"] = "8709";
  1212. /* 8709 : empty set */
  1213. MAP_ENTITY_TO_CHAR["&nabla"] = "8711";
  1214. /* 8711 : nabla */
  1215. MAP_ENTITY_TO_CHAR["&isin"] = "8712";
  1216. /* 8712 : element of */
  1217. MAP_ENTITY_TO_CHAR["&notin"] = "8713";
  1218. /* 8713 : not an element of */
  1219. MAP_ENTITY_TO_CHAR["&ni"] = "8715";
  1220. /* 8715 : contains as member */
  1221. MAP_ENTITY_TO_CHAR["&prod"] = "8719";
  1222. /* 8719 : n-ary product */
  1223. MAP_ENTITY_TO_CHAR["&sum"] = "8721";
  1224. /* 8721 : n-ary summation */
  1225. MAP_ENTITY_TO_CHAR["&minus"] = "8722";
  1226. /* 8722 : minus sign */
  1227. MAP_ENTITY_TO_CHAR["&lowast"] = "8727";
  1228. /* 8727 : asterisk operator */
  1229. MAP_ENTITY_TO_CHAR["&radic"] = "8730";
  1230. /* 8730 : square root */
  1231. MAP_ENTITY_TO_CHAR["&prop"] = "8733";
  1232. /* 8733 : proportional to */
  1233. MAP_ENTITY_TO_CHAR["&infin"] = "8734";
  1234. /* 8734 : infinity */
  1235. MAP_ENTITY_TO_CHAR["&ang"] = "8736";
  1236. /* 8736 : angle */
  1237. MAP_ENTITY_TO_CHAR["&and"] = "8743";
  1238. /* 8743 : logical and */
  1239. MAP_ENTITY_TO_CHAR["&or"] = "8744";
  1240. /* 8744 : logical or */
  1241. MAP_ENTITY_TO_CHAR["&cap"] = "8745";
  1242. /* 8745 : intersection */
  1243. MAP_ENTITY_TO_CHAR["&cup"] = "8746";
  1244. /* 8746 : union */
  1245. MAP_ENTITY_TO_CHAR["&int"] = "8747";
  1246. /* 8747 : integral */
  1247. MAP_ENTITY_TO_CHAR["&there4"] = "8756";
  1248. /* 8756 : therefore */
  1249. MAP_ENTITY_TO_CHAR["&sim"] = "8764";
  1250. /* 8764 : tilde operator */
  1251. MAP_ENTITY_TO_CHAR["&cong"] = "8773";
  1252. /* 8773 : congruent to */
  1253. MAP_ENTITY_TO_CHAR["&asymp"] = "8776";
  1254. /* 8776 : almost equal to */
  1255. MAP_ENTITY_TO_CHAR["&ne"] = "8800";
  1256. /* 8800 : not equal to */
  1257. MAP_ENTITY_TO_CHAR["&equiv"] = "8801";
  1258. /* 8801 : identical to, equivalent to */
  1259. MAP_ENTITY_TO_CHAR["&le"] = "8804";
  1260. /* 8804 : less-than or equal to */
  1261. MAP_ENTITY_TO_CHAR["&ge"] = "8805";
  1262. /* 8805 : greater-than or equal to */
  1263. MAP_ENTITY_TO_CHAR["&sub"] = "8834";
  1264. /* 8834 : subset of */
  1265. MAP_ENTITY_TO_CHAR["&sup"] = "8835";
  1266. /* 8835 : superset of */
  1267. MAP_ENTITY_TO_CHAR["&nsub"] = "8836";
  1268. /* 8836 : not a subset of */
  1269. MAP_ENTITY_TO_CHAR["&sube"] = "8838";
  1270. /* 8838 : subset of or equal to */
  1271. MAP_ENTITY_TO_CHAR["&supe"] = "8839";
  1272. /* 8839 : superset of or equal to */
  1273. MAP_ENTITY_TO_CHAR["&oplus"] = "8853";
  1274. /* 8853 : circled plus */
  1275. MAP_ENTITY_TO_CHAR["&otimes"] = "8855";
  1276. /* 8855 : circled times */
  1277. MAP_ENTITY_TO_CHAR["&perp"] = "8869";
  1278. /* 8869 : up tack */
  1279. MAP_ENTITY_TO_CHAR["&sdot"] = "8901";
  1280. /* 8901 : dot operator */
  1281. MAP_ENTITY_TO_CHAR["&lceil"] = "8968";
  1282. /* 8968 : left ceiling */
  1283. MAP_ENTITY_TO_CHAR["&rceil"] = "8969";
  1284. /* 8969 : right ceiling */
  1285. MAP_ENTITY_TO_CHAR["&lfloor"] = "8970";
  1286. /* 8970 : left floor */
  1287. MAP_ENTITY_TO_CHAR["&rfloor"] = "8971";
  1288. /* 8971 : right floor */
  1289. MAP_ENTITY_TO_CHAR["&lang"] = "9001";
  1290. /* 9001 : left-pointing angle bracket */
  1291. MAP_ENTITY_TO_CHAR["&rang"] = "9002";
  1292. /* 9002 : right-pointing angle bracket */
  1293. MAP_ENTITY_TO_CHAR["&loz"] = "9674";
  1294. /* 9674 : lozenge */
  1295. MAP_ENTITY_TO_CHAR["&spades"] = "9824";
  1296. /* 9824 : black spade suit */
  1297. MAP_ENTITY_TO_CHAR["&clubs"] = "9827";
  1298. /* 9827 : black club suit */
  1299. MAP_ENTITY_TO_CHAR["&hearts"] = "9829";
  1300. /* 9829 : black heart suit */
  1301. MAP_ENTITY_TO_CHAR["&diams"] = "9830";
  1302. /* 9830 : black diamond suit */
  1303. for (var entity in MAP_ENTITY_TO_CHAR) {
  1304. if ( !(typeof MAP_ENTITY_TO_CHAR[entity] == 'function') && MAP_ENTITY_TO_CHAR.hasOwnProperty(entity) ) {
  1305. MAP_CHAR_TO_ENTITY[MAP_ENTITY_TO_CHAR[entity]] = entity;
  1306. }
  1307. }
  1308. for (var c in MAP_CHAR_TO_ENTITY) {
  1309. if ( !(typeof MAP_CHAR_TO_ENTITY[c] == 'function') && MAP_CHAR_TO_ENTITY.hasOwnProperty(c) ) {
  1310. var ent = MAP_CHAR_TO_ENTITY[c].toLowerCase().substr(1);
  1311. ENTITY_TO_CHAR_TRIE.put(ent,String.fromCharCode(c));
  1312. }
  1313. }
  1314. })();
  1315. // If ES5 Enabled Browser - Lock the encoder down as much as possible
  1316. if ( Object.freeze ) {
  1317. $.encoder = Object.freeze($.encoder);
  1318. $.fn.encode = Object.freeze($.fn.encode);
  1319. } else if ( Object.seal ) {
  1320. $.encoder = Object.seal($.encoder);
  1321. $.fn.encode = Object.seal($.fn.encode);
  1322. } else if ( Object.preventExtensions ) {
  1323. $.encoder = Object.preventExtensions($.encoder);
  1324. $.fn.encode = Object.preventExtensions($.fn.encode);
  1325. }
  1326. })(jQuery);