@@ -35,31 +35,57 @@ SOFTWARE.
3535 <xsl : param name =" o" as =" element()" />
3636 <xsl : sequence select =" $o/@base='∅'" />
3737 </xsl : function >
38- <xsl : function name =" eo:hex-to-utf8" as =" xs:string" >
39- <xsl : param name =" hex" as =" xs:string" />
40- <xsl : variable name =" hex-upper" select =" upper-case(normalize-space($hex))" />
41- <xsl : variable name =" length" select =" string-length($hex-upper)" />
42- <xsl : variable name =" hex-digits" select =" string-to-codepoints('0123456789ABCDEF')" />
43- <xsl : variable name =" decimal" select =" sum(for $i in 1 to $length return (index-of($hex-digits, string-to-codepoints(substring($hex-upper, $i, 1))) - 1) * math:pow(16, $length - $i))" />
44- <xsl : value-of select =" codepoints-to-string(xs:int($decimal))" />
45- </xsl : function >
38+ <!-- BYTES TO STRING -->
4639 <xsl : function name =" eo:bytes-to-string" as =" xs:string" >
4740 <xsl : param name =" bytes" as =" xs:string" />
4841 <xsl : choose >
4942 <xsl : when test =" $bytes = '--'" >
5043 <xsl : sequence select =" ''" />
5144 </xsl : when >
5245 <xsl : otherwise >
53- <xsl : variable name =" byte-values" select =" for $byte in tokenize($bytes, '-') return eo:hex-to-utf8($byte)" />
54-
55-
56- <xsl : sequence select =" string-join(for $byte in tokenize($bytes, '-') return eo:hex-to-utf8($byte), '')" />
46+ <xsl : variable name =" decoded" >
47+ <xsl : for-each select =" eo:decode-bytes(for $byte in (if (ends-with($bytes, '-')) then substring-before($bytes, '-') else tokenize($bytes, '-')) return eo:hex-to-utf8($byte))" >
48+ <xsl : choose >
49+ <xsl : when test =" .=10" >
50+ <xsl : value-of select =" '\n'" />
51+ </xsl : when >
52+ <xsl : when test =" .=9" >
53+ <xsl : value-of select =" '\t'" />
54+ </xsl : when >
55+ <xsl : when test =" .=13" >
56+ <xsl : value-of select =" '\r'" />
57+ </xsl : when >
58+ <!-- Keep ASCII characters -->
59+ <xsl : when test =" . ge 32 and . le 126" >
60+ <xsl : variable name =" char" select =" codepoints-to-string(.)" />
61+ <xsl : if test =" $char='\' or $char='" '" >
62+ <xsl : text >\</xsl : text >
63+ </xsl : if >
64+ <xsl : value-of select =" $char" />
65+ </xsl : when >
66+ <!-- Convert non-ASCII to \uXXXX -->
67+ <xsl : when test =" . le 65535" >
68+ <xsl : value-of select =" concat('\u', eo:int-to-hex(xs:int(.)))" />
69+ </xsl : when >
70+ <!-- Handle surrogate pairs for code points above U+FFFF -->
71+ <xsl : otherwise >
72+ <!-- 55296 = 0xD800 -->
73+ <xsl : variable name =" cp1" select =" xs:int(floor((. - 65536) div 1024) + 55296)" />
74+ <!-- 56320 = 0xDC00 -->
75+ <xsl : variable name =" cp2" select =" xs:int(((. - 65536) mod 1024) + 56320)" />
76+ <xsl : value-of select =" concat('\u', eo:int-to-hex($cp1), '\u', eo:int-to-hex($cp2))" />
77+ </xsl : otherwise >
78+ </xsl : choose >
79+ </xsl : for-each >
80+ </xsl : variable >
81+ <xsl : sequence select =" $decoded" />
5782 </xsl : otherwise >
5883 </xsl : choose >
5984 </xsl : function >
60- <!-- Convert string bytes sequence to double number , e.g. 40-14-00-00-00-00-00-00 => 5 -->
85+ <!-- BYTES TO NUMBER , e.g. 40-14-00-00-00-00-00-00 => 5 -->
6186 <xsl : function name =" eo:bytes-to-number" as =" xs:anyAtomicType" >
6287 <xsl : param name =" bytes" />
88+ <!-- Undash -->
6389 <xsl : variable name =" hex" select =" translate($bytes, '-', '')" />
6490 <xsl : variable name =" map" as =" element()*" >
6591 <entry h =" 0" b =" 0000" />
@@ -80,13 +106,64 @@ SOFTWARE.
80106 <entry h =" F" b =" 1111" />
81107 </xsl : variable >
82108 <xsl : variable name =" bin" as =" xs:string" select =" string-join(for $c in string-to-codepoints(upper-case($hex)) return $map[@h = codepoints-to-string($c)]/@b, '')" />
109+ <!-- Sign bit (1 for negative, 0 for positive) -->
83110 <xsl : variable name =" sign" select =" if (substring($bin, 1, 1) = '1') then -1 else 1" />
111+ <!-- Extract exponent (11 bits) and convert to integer -->
84112 <xsl : variable name =" exponentBits" select =" substring($bin, 2, 11)" />
85113 <xsl : variable name =" exponent" select =" sum(for $i in 1 to string-length($exponentBits) return xs:double(substring($exponentBits, $i, 1)) * math:pow(2, string-length($exponentBits) - $i)) - 1023" />
114+ <!-- Extract mantissa (52 bits) -->
86115 <xsl : variable name =" mantissaBits" select =" substring($bin, 13, 52)" />
87116 <xsl : variable name =" mantissaValue" >
88- <xsl : sequence select =" sum(for $i in 1 to string-length($mantissaBits) return xs:double(substring($mantissaBits, $i, 1)) * math:pow(2, - $i))" />
117+ <xsl : sequence select =" sum(for $i in 1 to string-length($mantissaBits) return xs:double(substring($mantissaBits, $i, 1)) div math:pow(2, $i))" />
89118 </xsl : variable >
119+ <!-- Compute final double value -->
90120 <xsl : sequence select =" $sign * (1 + $mantissaValue) * math:pow(2, $exponent)" />
91121 </xsl : function >
122+ <!-- HELPER FUNCTIONS -->
123+ <!-- Function to decode UTF-8 bytes into Unicode code points -->
124+ <xsl : function name =" eo:decode-bytes" as =" xs:integer*" >
125+ <xsl : param name =" bytes" as =" xs:integer*" />
126+ <xsl : choose >
127+ <!-- 1-byte sequence: 0xxxxxxx -->
128+ <xsl : when test =" $bytes[1] lt 128" >
129+ <xsl : sequence select =" $bytes[1]" />
130+ <xsl : sequence select =" eo:decode-bytes(subsequence($bytes, 2))" />
131+ </xsl : when >
132+ <!-- 2-byte sequence: 110xxxxx 10xxxxxx -->
133+ <xsl : when test =" $bytes[1] ge 192 and $bytes[1] lt 224" >
134+ <xsl : variable name =" code-point" select =" (($bytes[1] - 192) * 64) + ($bytes[2] - 128)" />
135+ <xsl : sequence select =" $code-point" />
136+ <xsl : sequence select =" eo:decode-bytes(subsequence($bytes, 3))" />
137+ </xsl : when >
138+ <!-- 3-byte sequence: 1110xxxx 10xxxxxx 10xxxxxx -->
139+ <xsl : when test =" $bytes[1] ge 224 and $bytes[1] lt 240" >
140+ <xsl : variable name =" code-point" select =" (($bytes[1] - 224) * 4096) + (($bytes[2] - 128) * 64) + ($bytes[3] - 128)" />
141+ <xsl : sequence select =" $code-point" />
142+ <xsl : sequence select =" eo:decode-bytes(subsequence($bytes, 4))" />
143+ </xsl : when >
144+ <!-- 4-byte sequence: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx -->
145+ <xsl : when test =" $bytes[1] ge 240 and $bytes[1] lt 248" >
146+ <xsl : variable name =" code-point" select =" (($bytes[1] - 240) * 262144) + (($bytes[2] - 128) * 4096) + (($bytes[3] - 128) * 64) + ($bytes[4] - 128)" />
147+ <xsl : sequence select =" $code-point" />
148+ <xsl : sequence select =" eo:decode-bytes(subsequence($bytes, 5))" />
149+ </xsl : when >
150+ <!-- Otherwise, return empty (should not occur if input is valid UTF-8) -->
151+ <xsl : otherwise />
152+ </xsl : choose >
153+ </xsl : function >
154+ <!-- Function to convert integer to 4-digit hex string -->
155+ <xsl : function name =" eo:int-to-hex" as =" xs:string" >
156+ <xsl : param name =" value" as =" xs:integer" />
157+ <xsl : variable name =" hex-chars" select =" '0123456789ABCDEF'" />
158+ <xsl : variable name =" hex" select =" concat(substring($hex-chars, floor($value idiv 4096) + 1, 1), substring($hex-chars, floor(($value mod 4096) idiv 256) + 1, 1), substring($hex-chars, floor(($value mod 256) idiv 16) + 1, 1), substring($hex-chars, ($value mod 16) + 1, 1))" />
159+ <xsl : sequence select =" $hex" />
160+ </xsl : function >
161+ <xsl : function name =" eo:hex-to-utf8" as =" xs:integer" >
162+ <xsl : param name =" hex" as =" xs:string" />
163+ <xsl : variable name =" hex-upper" select =" upper-case(normalize-space($hex))" />
164+ <xsl : variable name =" length" select =" string-length($hex-upper)" />
165+ <xsl : variable name =" hex-digits" select =" string-to-codepoints('0123456789ABCDEF')" />
166+ <xsl : variable name =" decimal" select =" sum(for $i in 1 to $length return (index-of($hex-digits, string-to-codepoints(substring($hex-upper, $i, 1))) - 1) * math:pow(16, $length - $i))" />
167+ <xsl : value-of select =" xs:int($decimal)" />
168+ </xsl : function >
92169</xsl : stylesheet >
0 commit comments