sanitizeForLog function

String sanitizeForLog(
  1. String text
)

Rewrites U+FFFD (the replacement character) and unpaired UTF-16 surrogates to the literal text U+FFFD.

Both encode to the bytes 0xEF 0xBF 0xBD on stdout, which flutter run's reader treats as malformed output and aborts on (issue #306). A lone surrogate appears when a substring/chunk boundary splits an emoji or other astral character mid-pair.

Implementation

String sanitizeForLog(String text) {
  var needsWork = false;
  for (var i = 0; i < text.length; i++) {
    final u = text.codeUnitAt(i);
    if (u == 0xFFFD || (u >= 0xD800 && u <= 0xDFFF)) {
      needsWork = true;
      break;
    }
  }
  if (!needsWork) return text;

  final out = StringBuffer();
  for (var i = 0; i < text.length; i++) {
    final u = text.codeUnitAt(i);
    if (u == 0xFFFD) {
      out.write('U+FFFD');
    } else if (u >= 0xD800 && u <= 0xDBFF) {
      final hasLow = i + 1 < text.length &&
          text.codeUnitAt(i + 1) >= 0xDC00 &&
          text.codeUnitAt(i + 1) <= 0xDFFF;
      if (hasLow) {
        out.writeCharCode(u);
        out.writeCharCode(text.codeUnitAt(i + 1));
        i++;
      } else {
        out.write('U+FFFD');
      }
    } else if (u >= 0xDC00 && u <= 0xDFFF) {
      out.write('U+FFFD');
    } else {
      out.writeCharCode(u);
    }
  }
  return out.toString();
}