@@ -56,6 +56,42 @@ if (!Array.prototype.contains) {
5656 } ;
5757}
5858
59+ if ( ! Array . prototype . getLongestKeyLength ) {
60+ Array . prototype . getLongestKeyLength = function ( ) {
61+ var len = 0 ;
62+ for ( var key in this ) {
63+ if ( ! key instanceof String ) {
64+ throw new RuntimeException ( "getLongestKeyMatch only works with Map<String,Object>" ) ;
65+ }
66+
67+ len = Math . max ( len , key . length ) ;
68+ }
69+ return len ;
70+ } ;
71+ }
72+
73+ if ( ! Array . prototype . containsKey ) {
74+ Array . prototype . containsKey = function ( srch ) {
75+ for ( var key in this ) {
76+ if ( key . toLowerCase ( ) == srch . toLowerCase ( ) ) {
77+ return true ;
78+ }
79+ }
80+ return false ;
81+ } ;
82+ }
83+
84+ if ( ! Array . prototype . getCaseInsensitive ) {
85+ Array . prototype . getCaseInsensitive = function ( key ) {
86+ for ( var k in this ) {
87+ if ( k . toLowerCase ( ) == key . toLowerCase ( ) ) {
88+ return this [ k ] ;
89+ }
90+ }
91+ return null ;
92+ } ;
93+ }
94+
5995if ( ! String . prototype . charCodeAt ) {
6096 String . prototype . charCodeAt = function ( idx ) {
6197 var c = this . charAt ( idx ) ;
@@ -67,6 +103,12 @@ if (!String.prototype.charCodeAt) {
67103 } ;
68104}
69105
106+ if ( ! String . prototype . endsWith ) {
107+ String . prototype . endsWith = function ( test ) {
108+ return this . substr ( ( this . length - test . length ) , test . length ) == test ;
109+ } ;
110+ }
111+
70112// Declare some Core Exceptions
71113if ( ! RuntimeException ) {
72114 var RuntimeException = function ( sMsg ) {
@@ -271,41 +313,138 @@ org.owasp.esapi.codecs.Codec.getHexForNonAlphanumeric = function(c) {
271313org . owasp . esapi . codecs . HTMLEntityCodec = function ( ) {
272314 var _super = new org . owasp . esapi . codecs . Codec ( ) ;
273315
274- return {
275- encode : function ( aImmune , sInput ) {
276- var out = '' ;
277- for ( var i = 0 ; i < sInput . length ; i ++ ) {
278- var c = sInput . charCodeAt ( i ) ;
279- if ( characterToEntityMap [ c . toString ( ) ] ) {
280- out += characterToEntityMap [ c . toString ( ) ] + ';' ;
281- }
282- else {
283- out += String . fromCharCode ( c ) ;
316+ var getNumericEntity = function ( input ) {
317+ var first = input . peek ( ) ;
318+ if ( first == null ) {
319+ return null ;
320+ }
321+
322+ if ( first == 'x' || first == 'X' ) {
323+ input . next ( ) ;
324+ return parseHex ( input ) ;
325+ }
326+ return parseNumber ( input ) ;
327+ } ;
328+
329+ var parseNumber = function ( input ) {
330+ var out = '' ;
331+ while ( input . hasNext ( ) ) {
332+ var c = input . peek ( ) ;
333+ if ( c . match ( / [ 0 - 9 ] / ) ) {
334+ out += c ;
335+ input . next ( ) ;
336+ } else if ( c == ';' ) {
337+ input . next ( ) ;
338+ break ;
339+ } else {
340+ break ;
341+ }
342+ }
343+
344+ try {
345+ return parseInt ( out ) ;
346+ } catch ( e ) {
347+ return null ;
348+ }
349+ } ;
350+
351+ var parseHex = function ( input ) {
352+ var out = '' ;
353+ while ( input . hasNext ( ) ) {
354+ var c = input . peek ( ) ;
355+ if ( c . match ( / [ 0 - 9 A - F a - f ] / ) ) {
356+ out += c ;
357+ input . next ( ) ;
358+ } else if ( c == ';' ) {
359+ input . next ( ) ;
360+ break ;
361+ } else {
362+ break ;
363+ }
364+ }
365+ try {
366+ return parseInt ( out , 16 ) ;
367+ } catch ( e ) {
368+ return null ;
369+ }
370+ } ;
371+
372+ var getNamedEntity = function ( input ) {
373+ var entity = '' ;
374+ while ( input . hasNext ( ) ) {
375+ var c = input . peek ( ) ;
376+ if ( c . match ( / [ A - Z a - z ] / ) ) {
377+ entity += c ;
378+ input . next ( ) ;
379+ if ( entityToCharacterMap . containsKey ( '&' + entity ) ) {
380+ if ( input . peek ( ';' ) ) input . next ( ) ;
381+ break ;
284382 }
383+ } else if ( c == ';' ) {
384+ input . next ( ) ;
385+ } else {
386+ break ;
285387 }
286- return out ;
388+ }
389+
390+ return String . fromCharCode ( entityToCharacterMap . getCaseInsensitive ( '&' + entity ) ) ;
391+ } ;
392+
393+ return {
394+ encode : _super . encode ,
395+
396+ decode : _super . decode ,
397+
398+ encodeCharacter : function ( aImmune , c ) {
399+ if ( aImmune . contains ( c ) ) {
400+ return c ;
401+ }
402+
403+ var hex = org . owasp . esapi . codecs . Codec . getHexForNonAlphanumeric ( c ) ;
404+ if ( hex == null ) {
405+ return c ;
406+ }
407+
408+ var cc = c . charCodeAt ( 0 ) ;
409+ if ( ( cc <= 0x1f && c != '\t' && c != '\n' && c != '\r' ) || ( cc >= 0x7f && cc <= 0x9f ) || c == ' ' ) {
410+ return " " ;
411+ }
412+
413+ var entityName = characterToEntityMap [ cc ] ;
414+ if ( entityName != null ) {
415+ return entityName + ";" ;
416+ }
417+
418+ return "&#x" + hex + ";" ;
287419 } ,
288420
289- decode : function ( sInput ) {
290- var out = '' ;
291- for ( var i = 0 ; i < sInput . length ; i ++ ) {
292- var c = sInput . charAt ( i ) ;
293- if ( c == '&' ) {
294- var end = sInput . indexOf ( ';' , i ) ;
295- var entity = sInput . substr ( i , end - i ) ;
296- if ( entityToCharacterMap [ entity ] ) {
297- out += String . fromCharCode ( entityToCharacterMap [ entity ] ) ;
298- i = end ;
299- }
300- else {
301- out += c ;
302- }
303- }
304- else {
305- out += c ;
421+ decodeCharacter : function ( oPushbackString ) {
422+ var input = oPushbackString ;
423+ input . mark ( ) ;
424+ var first = input . next ( ) ;
425+ if ( first == null || first != '&' ) {
426+ input . reset ( ) ;
427+ return null ;
428+ }
429+
430+ var second = input . next ( ) ;
431+ if ( second == null ) {
432+ input . reset ( ) ;
433+ return null ;
434+ }
435+
436+ if ( second == '#' ) {
437+ var c = getNumericEntity ( input ) ;
438+ if ( c != null ) { return c ; }
439+ } else if ( second . match ( / [ A - Z a - z ] / ) ) {
440+ input . pushback ( second ) ;
441+ var c = getNamedEntity ( input ) ;
442+ if ( c != null ) {
443+ return c ;
306444 }
307445 }
308- return out ;
446+ input . reset ( ) ;
447+ return null ;
309448 }
310449 } ;
311450} ;
0 commit comments