'From Cuis 5.0 [latest update: #4887] on 27 September 2021 at 7:42:35 am'!

!String methodsFor: 'converting' stamp: 'jmv 9/26/2021 21:14:58'!
convertEmbeddedAsciiNCRs
	"Answer a String. Convert any NCR for an ASCII character to the actual Character.
	See http://en.wikipedia.org/wiki/Numeric_character_reference

'a&#9;b&#13;c' convertEmbeddedAsciiNCRs
'&#913;&#945; 	Only for ASCII characters (i.e. code points < 128)' convertEmbeddedAsciiNCRs
'&# 937;&# 969; 	Not a NCR, just regular ASCII chars!!' convertEmbeddedAsciiNCRs
	"

	| str |
	^String streamContents: [ :outStream | | inStream nextChar prevPos maybeNCR ncrEnd codePoint |
		inStream _ self readStream.
		[ inStream atEnd ] whileFalse: [
			nextChar _ inStream next.
			nextChar = $&
				ifTrue: [
					prevPos _ inStream position.
					ncrEnd _ 0.
					maybeNCR _ inStream next: 6.
					(maybeNCR notEmpty and: [ maybeNCR first = $# ]) ifTrue: [
						ncrEnd _ maybeNCR indexOf: $; ].
					ncrEnd = 0 ifFalse: [
						codePoint _ nil.
						maybeNCR second = $x
							ifTrue: [
								str _ (maybeNCR copyFrom: 3 to: ncrEnd) asUppercase.
								(str first isDigit or: [ str first asciiValue between: $A asciiValue and: $F asciiValue]) ifTrue: [
									codePoint _  ('16r', str) asNumber.
									codePoint > 127 ifTrue: [ codePoint _ nil ]]]
							ifFalse: [
								str _ maybeNCR copyFrom: 2 to: ncrEnd.
								str first isDigit ifTrue: [
									codePoint _  codePoint _ str asNumber.
									codePoint > 127 ifTrue: [ codePoint _ nil ]]]].
					codePoint
						ifNotNil: [nextChar _ Character numericValue: codePoint]
						ifNil: [ncrEnd _ 0].
					inStream position: prevPos + ncrEnd ].
					outStream nextPut: nextChar
			]]! !

