Blame SOURCES/0001-unistr.c-Enable-encoding-broken-UTF-16-into-broken-U.patch

70298e
From d9c61dd60ec484909f70b7a916ada3a93af94b60 Mon Sep 17 00:00:00 2001
70298e
From: Erik Larsson <mechie@users.sourceforge.net>
70298e
Date: Fri, 8 Apr 2016 05:39:48 +0200
70298e
Subject: [PATCH 1/2] unistr.c: Enable encoding broken UTF-16 into broken
70298e
 UTF-8, A.K.A. WTF-8.
70298e
70298e
Windows filenames may contain invalid UTF-16 sequences (specifically
70298e
broken surrogate pairs), which cannot be converted to UTF-8 if we do
70298e
strict conversion.
70298e
70298e
This patch enables encoding broken UTF-16 into similarly broken UTF-8 by
70298e
encoding any surrogate character that don't have a match into a separate
70298e
3-byte UTF-8 sequence.
70298e
70298e
This is "sort of" valid UTF-8, but not valid Unicode since the code
70298e
points used for surrogate pair encoding are not supposed to occur in a
70298e
valid Unicode string... but on the other hand the source UTF-16 data is
70298e
also broken, so we aren't really making things any worse.
70298e
70298e
This format is sometimes referred to as WTF-8 (Wobbly Translation
70298e
Format, 8-bit encoding) and is a common solution to represent broken
70298e
UTF-16 as UTF-8.
70298e
70298e
It is a lossless round-trip conversion, i.e converting from broken
70298e
UTF-16 to "WTF-8" and back to UTF-16 yields the same broken UTF-16
70298e
sequence. Because of this property it enables accessing these files
70298e
by filename through ntfs-3g and the ntfsprogs (e.g. ls -la works as
70298e
expected).
70298e
70298e
To disable this behaviour you can pass the preprocessor/compiler flag
70298e
'-DALLOW_BROKEN_SURROGATES=0' when building ntfs-3g.
70298e
---
70298e
 libntfs-3g/unistr.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++--
70298e
 1 file changed, 65 insertions(+), 2 deletions(-)
70298e
70298e
diff --git a/libntfs-3g/unistr.c b/libntfs-3g/unistr.c
70298e
index 7f278cd..71802aa 100644
70298e
--- a/libntfs-3g/unistr.c
70298e
+++ b/libntfs-3g/unistr.c
70298e
@@ -61,6 +61,11 @@
70298e
 
70298e
 #define NOREVBOM 0  /* JPA rejecting U+FFFE and U+FFFF, open to debate */
70298e
 
70298e
+#ifndef ALLOW_BROKEN_SURROGATES
70298e
+/* Erik allowing broken UTF-16 surrogate pairs by default, open to debate. */
70298e
+#define ALLOW_BROKEN_SURROGATES 1
70298e
+#endif /* !defined(ALLOW_BROKEN_SURROGATES) */
70298e
+
70298e
 /*
70298e
  * IMPORTANT
70298e
  * =========
70298e
@@ -462,8 +467,22 @@ static int utf16_to_utf8_size(const ntfschar *ins, const int ins_len, int outs_l
70298e
 			if ((c >= 0xdc00) && (c < 0xe000)) {
70298e
 				surrog = FALSE;
70298e
 				count += 4;
70298e
-			} else 
70298e
+			} else {
70298e
+#if ALLOW_BROKEN_SURROGATES
70298e
+				/* The first UTF-16 unit of a surrogate pair has
70298e
+				 * a value between 0xd800 and 0xdc00. It can be
70298e
+				 * encoded as an individual UTF-8 sequence if we
70298e
+				 * cannot combine it with the next UTF-16 unit
70298e
+				 * unit as a surrogate pair. */
70298e
+				surrog = FALSE;
70298e
+				count += 3;
70298e
+
70298e
+				--i;
70298e
+				continue;
70298e
+#else
70298e
 				goto fail;
70298e
+#endif /* ALLOW_BROKEN_SURROGATES */
70298e
+			}
70298e
 		} else
70298e
 			if (c < 0x80)
70298e
 				count++;
70298e
@@ -473,6 +492,10 @@ static int utf16_to_utf8_size(const ntfschar *ins, const int ins_len, int outs_l
70298e
 				count += 3;
70298e
 			else if (c < 0xdc00)
70298e
 				surrog = TRUE;
70298e
+#if ALLOW_BROKEN_SURROGATES
70298e
+			else if (c < 0xe000)
70298e
+				count += 3;
70298e
+#endif /* ALLOW_BROKEN_SURROGATES */
70298e
 #if NOREVBOM
70298e
 			else if ((c >= 0xe000) && (c < 0xfffe))
70298e
 #else
70298e
@@ -487,7 +510,11 @@ static int utf16_to_utf8_size(const ntfschar *ins, const int ins_len, int outs_l
70298e
 		}
70298e
 	}
70298e
 	if (surrog) 
70298e
+#if ALLOW_BROKEN_SURROGATES
70298e
+		count += 3; /* ending with a single surrogate */
70298e
+#else
70298e
 		goto fail;
70298e
+#endif /* ALLOW_BROKEN_SURROGATES */
70298e
 
70298e
 	ret = count;
70298e
 out:
70298e
@@ -548,8 +575,24 @@ static int ntfs_utf16_to_utf8(const ntfschar *ins, const int ins_len,
70298e
 				*t++ = 0x80 + ((c >> 6) & 15) + ((halfpair & 3) << 4);
70298e
 				*t++ = 0x80 + (c & 63);
70298e
 				halfpair = 0;
70298e
-			} else 
70298e
+			} else {
70298e
+#if ALLOW_BROKEN_SURROGATES
70298e
+				/* The first UTF-16 unit of a surrogate pair has
70298e
+				 * a value between 0xd800 and 0xdc00. It can be
70298e
+				 * encoded as an individual UTF-8 sequence if we
70298e
+				 * cannot combine it with the next UTF-16 unit
70298e
+				 * unit as a surrogate pair. */
70298e
+				*t++ = 0xe0 | (halfpair >> 12);
70298e
+				*t++ = 0x80 | ((halfpair >> 6) & 0x3f);
70298e
+				*t++ = 0x80 | (halfpair & 0x3f);
70298e
+				halfpair = 0;
70298e
+
70298e
+				--i;
70298e
+				continue;
70298e
+#else
70298e
 				goto fail;
70298e
+#endif /* ALLOW_BROKEN_SURROGATES */
70298e
+			}
70298e
 		} else if (c < 0x80) {
70298e
 			*t++ = c;
70298e
 	    	} else {
70298e
@@ -562,6 +605,13 @@ static int ntfs_utf16_to_utf8(const ntfschar *ins, const int ins_len,
70298e
 		        	*t++ = 0x80 | (c & 0x3f);
70298e
 			} else if (c < 0xdc00)
70298e
 				halfpair = c;
70298e
+#if ALLOW_BROKEN_SURROGATES
70298e
+			else if (c < 0xe000) {
70298e
+				*t++ = 0xe0 | (c >> 12);
70298e
+				*t++ = 0x80 | ((c >> 6) & 0x3f);
70298e
+				*t++ = 0x80 | (c & 0x3f);
70298e
+			}
70298e
+#endif /* ALLOW_BROKEN_SURROGATES */
70298e
 			else if (c >= 0xe000) {
70298e
 				*t++ = 0xe0 | (c >> 12);
70298e
 				*t++ = 0x80 | ((c >> 6) & 0x3f);
70298e
@@ -570,6 +620,13 @@ static int ntfs_utf16_to_utf8(const ntfschar *ins, const int ins_len,
70298e
 				goto fail;
70298e
 	        }
70298e
 	}
70298e
+#if ALLOW_BROKEN_SURROGATES
70298e
+	if (halfpair) { /* ending with a single surrogate */
70298e
+		*t++ = 0xe0 | (halfpair >> 12);
70298e
+		*t++ = 0x80 | ((halfpair >> 6) & 0x3f);
70298e
+		*t++ = 0x80 | (halfpair & 0x3f);
70298e
+	}
70298e
+#endif /* ALLOW_BROKEN_SURROGATES */
70298e
 	*t = '\0';
70298e
 	
70298e
 #if defined(__APPLE__) || defined(__DARWIN__)
70298e
@@ -693,10 +750,16 @@ static int utf8_to_unicode(u32 *wc, const char *s)
70298e
 			/* Check valid ranges */
70298e
 #if NOREVBOM
70298e
 			if (((*wc >= 0x800) && (*wc <= 0xD7FF))
70298e
+#if ALLOW_BROKEN_SURROGATES
70298e
+			  || ((*wc >= 0xD800) && (*wc <= 0xDFFF))
70298e
+#endif /* ALLOW_BROKEN_SURROGATES */
70298e
 			  || ((*wc >= 0xe000) && (*wc <= 0xFFFD)))
70298e
 				return 3;
70298e
 #else
70298e
 			if (((*wc >= 0x800) && (*wc <= 0xD7FF))
70298e
+#if ALLOW_BROKEN_SURROGATES
70298e
+			  || ((*wc >= 0xD800) && (*wc <= 0xDFFF))
70298e
+#endif /* ALLOW_BROKEN_SURROGATES */
70298e
 			  || ((*wc >= 0xe000) && (*wc <= 0xFFFF)))
70298e
 				return 3;
70298e
 #endif
70298e
-- 
70298e
2.10.2
70298e