@@ -155,6 +155,11 @@ exports.validate = function (xmlData, options) {
155155 } else {
156156 break ;
157157 }
158+ } else if ( xmlData [ i ] === '&' ) {
159+ const afterAmp = validateAmpersand ( xmlData , i ) ;
160+ if ( afterAmp == - 1 )
161+ return getErrorObject ( 'InvalidChar' , `char '&' is not expected.` , getLineNumberForPosition ( xmlData , i ) ) ;
162+ i = afterAmp ;
158163 }
159164 } //end of reading tag text value
160165 if ( xmlData [ i ] === '<' ) {
@@ -332,6 +337,41 @@ function validateAttributeString(attrStr, options, regxAttrName) {
332337 return true ;
333338}
334339
340+ function validateNumberAmpersand ( xmlData , i ) {
341+ let re = / \d / ;
342+ if ( xmlData [ i ] === 'x' ) {
343+ i ++ ;
344+ re = / [ \d a - f A - F ] / ;
345+ }
346+ for ( ; i < xmlData . length ; i ++ ) {
347+ if ( xmlData [ i ] === ';' )
348+ return i ;
349+ if ( ! xmlData [ i ] . match ( re ) )
350+ break ;
351+ }
352+ return - 1 ;
353+ }
354+
355+ function validateAmpersand ( xmlData , i ) {
356+ // https://www.w3.org/TR/xml/#dt-charref
357+ i ++ ;
358+ if ( xmlData [ i ] === ';' )
359+ return - 1 ;
360+ if ( xmlData [ i ] === '#' ) {
361+ i ++ ;
362+ return validateNumberAmpersand ( xmlData , i ) ;
363+ }
364+ let count = 0 ;
365+ for ( ; i < xmlData . length ; i ++ , count ++ ) {
366+ if ( xmlData [ i ] . match ( / \w / ) && count < 20 )
367+ continue ;
368+ if ( xmlData [ i ] === ';' )
369+ break ;
370+ return - 1 ;
371+ }
372+ return i ;
373+ }
374+
335375function getErrorObject ( code , message , lineNumber ) {
336376 return {
337377 err : {
0 commit comments