@@ -143,6 +143,7 @@ static void handle(TruffleEncoder encoder, String errorAction, Object inputObjec
143
143
@ Cached ConditionProfile strictProfile ,
144
144
@ Cached ConditionProfile backslashreplaceProfile ,
145
145
@ Cached ConditionProfile surrogatepassProfile ,
146
+ @ Cached ConditionProfile surrogateescapeProfile ,
146
147
@ Cached RaiseEncodingErrorNode raiseEncodingErrorNode ,
147
148
@ Cached PRaiseNode raiseNode ) {
148
149
boolean fixed ;
@@ -154,6 +155,8 @@ static void handle(TruffleEncoder encoder, String errorAction, Object inputObjec
154
155
fixed = backslashreplace (encoder );
155
156
} else if (surrogatepassProfile .profile (SURROGATEPASS .equals (errorAction ))) {
156
157
fixed = surrogatepass (encoder );
158
+ } else if (surrogateescapeProfile .profile (SURROGATEESCAPE .equals (errorAction ))) {
159
+ fixed = surrogateescape (encoder );
157
160
} else {
158
161
throw raiseNode .raise (LookupError , ErrorMessages .UNKNOWN_ERROR_HANDLER , errorAction );
159
162
}
@@ -213,6 +216,24 @@ private static boolean surrogatepass(TruffleEncoder encoder) {
213
216
return false ;
214
217
}
215
218
219
+ @ TruffleBoundary
220
+ private static boolean surrogateescape (TruffleEncoder encoder ) {
221
+ String p = new String (encoder .getInputChars (encoder .getErrorLength ()));
222
+ byte [] replacement = new byte [p .length ()];
223
+ int outp = 0 ;
224
+ for (int i = 0 ; i < p .length ();) {
225
+ int ch = p .codePointAt (i );
226
+ if (!(0xDC80 <= ch && ch <= 0xDCFF )) {
227
+ // Not a surrogate
228
+ return false ;
229
+ }
230
+ replacement [outp ++] = (byte ) (ch - 0xdc00 );
231
+ i += Character .charCount (ch );
232
+ }
233
+ encoder .replace (encoder .getErrorLength (), replacement , 0 , outp );
234
+ return true ;
235
+ }
236
+
216
237
public static HandleEncodingErrorNode create () {
217
238
return CodecsModuleBuiltinsFactory .HandleEncodingErrorNodeGen .create ();
218
239
}
@@ -250,6 +271,7 @@ static void doStrict(TruffleDecoder decoder, String errorAction, Object inputObj
250
271
@ Cached ConditionProfile strictProfile ,
251
272
@ Cached ConditionProfile backslashreplaceProfile ,
252
273
@ Cached ConditionProfile surrogatepassProfile ,
274
+ @ Cached ConditionProfile surrogateescapeProfile ,
253
275
@ Cached RaiseDecodingErrorNode raiseDecodingErrorNode ,
254
276
@ Cached PRaiseNode raiseNode ) {
255
277
boolean fixed ;
@@ -261,6 +283,8 @@ static void doStrict(TruffleDecoder decoder, String errorAction, Object inputObj
261
283
fixed = backslashreplace (decoder );
262
284
} else if (surrogatepassProfile .profile (SURROGATEPASS .equals (errorAction ))) {
263
285
fixed = surrogatepass (decoder );
286
+ } else if (surrogateescapeProfile .profile (SURROGATEESCAPE .equals (errorAction ))) {
287
+ fixed = surrogateescape (decoder );
264
288
} else {
265
289
throw raiseNode .raise (LookupError , ErrorMessages .UNKNOWN_ERROR_HANDLER , errorAction );
266
290
}
@@ -308,6 +332,27 @@ private static boolean surrogatepass(TruffleDecoder decoder) {
308
332
return false ;
309
333
}
310
334
335
+ @ TruffleBoundary
336
+ private static boolean surrogateescape (TruffleDecoder decoder ) {
337
+ int errorLength = decoder .getErrorLength ();
338
+ // decode up to 4 bytes
339
+ int consumed = 0 ;
340
+ boolean replaced = false ;
341
+ byte [] inputBytes = decoder .getInputBytes (errorLength );
342
+ while (consumed < 4 && consumed < errorLength ) {
343
+ int b = inputBytes [consumed ] & 0xff ;
344
+ // Refuse to escape ASCII bytes.
345
+ if (b < 128 ) {
346
+ break ;
347
+ }
348
+ int codePoint = 0xdc00 + b ;
349
+ decoder .replace (1 , Character .toChars (codePoint ));
350
+ replaced = true ;
351
+ consumed += 1 ;
352
+ }
353
+ return replaced ;
354
+ }
355
+
311
356
public static HandleDecodingErrorNode create () {
312
357
return CodecsModuleBuiltinsFactory .HandleDecodingErrorNodeGen .create ();
313
358
}
@@ -323,14 +368,14 @@ protected static CodingErrorAction convertCodingErrorAction(String errors) {
323
368
errorAction = CodingErrorAction .IGNORE ;
324
369
break ;
325
370
case REPLACE :
326
- case SURROGATEESCAPE :
327
371
case NAMEREPLACE :
328
372
case XMLCHARREFREPLACE :
329
373
errorAction = CodingErrorAction .REPLACE ;
330
374
break ;
331
375
case STRICT :
332
376
case BACKSLASHREPLACE :
333
377
case SURROGATEPASS :
378
+ case SURROGATEESCAPE :
334
379
default :
335
380
// Everything else will be handled by our Handle nodes
336
381
errorAction = CodingErrorAction .REPORT ;
0 commit comments