Repository: fonttools/fonttools

Issue:
[name] addMultilingualName fails with one-character names
This bug seems to have been introduced between 4.10 and 4.11. @justvanrossum I think you changed something there?

```python
from fontTools.ttLib.tables._n_a_m_e import table__n_a_m_e

t = table__n_a_m_e()

t.addMultilingualName({"en": "A"})
t.addMultilingualName({"en": "B"})
```

Traceback:
```
Traceback (most recent call last):
  File "./test.py", line 8, in <module>
    t.addMultilingualName({"en": "B"})
  File "/Users/kuti/Quellen/fonttools-github/Lib/fontTools/ttLib/tables/_n_a_m_e.py", line 273, in addMultilingualName
    names, windows=windows, mac=mac, minNameID=minNameID)
  File "/Users/kuti/Quellen/fonttools-github/Lib/fontTools/ttLib/tables/_n_a_m_e.py", line 229, in findMultilingualName
    key = (name.toUnicode(), name.platformID,
  File "/Users/kuti/Quellen/fonttools-github/Lib/fontTools/ttLib/tables/_n_a_m_e.py", line 456, in toUnicode
    string = b'\0' + string
TypeError: can't concat str to bytes
```
[name] addMultilingualName fails with one-character names
This bug seems to have been introduced between 4.10 and 4.11. @justvanrossum I think you changed something there?

```python
from fontTools.ttLib.tables._n_a_m_e import table__n_a_m_e

t = table__n_a_m_e()

t.addMultilingualName({"en": "A"})
t.addMultilingualName({"en": "B"})
```

Traceback:
```
Traceback (most recent call last):
  File "./test.py", line 8, in <module>
    t.addMultilingualName({"en": "B"})
  File "/Users/kuti/Quellen/fonttools-github/Lib/fontTools/ttLib/tables/_n_a_m_e.py", line 273, in addMultilingualName
    names, windows=windows, mac=mac, minNameID=minNameID)
  File "/Users/kuti/Quellen/fonttools-github/Lib/fontTools/ttLib/tables/_n_a_m_e.py", line 229, in findMultilingualName
    key = (name.toUnicode(), name.platformID,
  File "/Users/kuti/Quellen/fonttools-github/Lib/fontTools/ttLib/tables/_n_a_m_e.py", line 456, in toUnicode
    string = b'\0' + string
TypeError: can't concat str to bytes
```


Discussion:
Confirmed. Yes, that indeed seems to be a regression introduced with my changes. Looking into it.
Actually, it's not 100% a regression, the following fails in 4.10.0 as well:
```python
from fontTools.ttLib import newTable
t = newTable("name")
nameID = t.addMultilingualName({"en": "A"})
rec = t.getName(nameID, 3, 1)
print(rec.toUnicode())
```
Confirmed. Yes, that indeed seems to be a regression introduced with my changes. Looking into it.
Actually, it's not 100% a regression, the following fails in 4.10.0 as well:
```python
from fontTools.ttLib import newTable
t = newTable("name")
nameID = t.addMultilingualName({"en": "A"})
rec = t.getName(nameID, 3, 1)
print(rec.toUnicode())
```

Resolving patch:
diff --git a/Lib/fontTools/ttLib/tables/_n_a_m_e.py b/Lib/fontTools/ttLib/tables/_n_a_m_e.py
--- a/Lib/fontTools/ttLib/tables/_n_a_m_e.py
+++ b/Lib/fontTools/ttLib/tables/_n_a_m_e.py
@@ -441,7 +441,7 @@ def isascii(b):
 		encoding = self.getEncoding()
 		string = self.string
 
-		if encoding == 'utf_16_be' and len(string) % 2 == 1:
+		if isinstance(string, bytes) and encoding == 'utf_16_be' and len(string) % 2 == 1:
 			# Recover badly encoded UTF-16 strings that have an odd number of bytes:
 			# - If the last byte is zero, drop it.  Otherwise,
 			# - If all the odd bytes are zero and all the even bytes are ASCII,


Test patch:
diff --git a/Tests/ttLib/tables/_n_a_m_e_test.py b/Tests/ttLib/tables/_n_a_m_e_test.py
--- a/Tests/ttLib/tables/_n_a_m_e_test.py
+++ b/Tests/ttLib/tables/_n_a_m_e_test.py
@@ -345,6 +345,11 @@ def test_toUnicode_UnicodeDecodeError(self):
 		self.assertEqual("utf_16_be", name.getEncoding())
 		self.assertRaises(UnicodeDecodeError, name.toUnicode)
 
+	def test_toUnicode_singleChar(self):
+		# https://github.com/fonttools/fonttools/issues/1997
+		name = makeName("A", 256, 3, 1, 0x409)
+		self.assertEqual(name.toUnicode(), "A")
+
 	def toXML(self, name):
 		writer = XMLWriter(BytesIO())
 		name.toXML(writer, ttFont=None)