Add 'SVG ' table implementation from Read Roberts (Adobe)
diff --git a/Lib/fontTools/ttLib/tables/S_V_G_.py b/Lib/fontTools/ttLib/tables/S_V_G_.py
new file mode 100644
index 0000000..9474fcf
--- /dev/null
+++ b/Lib/fontTools/ttLib/tables/S_V_G_.py
@@ -0,0 +1,370 @@
+__doc__="""
+Compiles/decompiles version 0 and 1 SVG tables from/to XML.
+
+Version 1 is the first SVG definition, implemented in Mozilla before Aug 2013, now deprecated.
+This module will decompile this correctly, but will compile a version 1 table
+only if you add the secret element "<version1/>" to the SVG element in the TTF file.
+
+Version 0 is the joint Adobe-Mozilla proposal, which supports color palettes.
+
+The XML format is:
+  <SVG>
+    <svgDoc endGlyphID="1" startGlyphID="1">
+      <![CDATA[ <complete SVG doc> ]]
+    </svgDoc>
+...
+	<svgDoc endGlyphID="n" startGlyphID="m">
+      <![CDATA[ <complete SVG doc> ]]
+    </svgDoc>
+
+    <colorPalettes>
+    	<colorParamUINameID>n</colorParamUINameID>
+    	...
+    	<colorParamUINameID>m</colorParamUINameID>
+    	<colorPalette uiNameID="n">
+    		<colorRecord red="<int>" green="<int>" blue="<int>" alpha="<int>" />
+    		...
+    		<colorRecord red="<int>" green="<int>" blue="<int>" alpha="<int>" />
+    	</colorPalette>
+    	...
+    	<colorPalette uiNameID="m">
+    		<colorRecord red="<int> green="<int>" blue="<int>" alpha="<int>" />
+    		...
+    		<colorRecord red=<int>" green="<int>" blue="<int>" alpha="<int>" />
+    	</colorPalette>
+    </colorPalettes>
+</SVG>
+
+Color values must be less than 256. 
+
+The number of color records in each </colorPalette> must be the same as
+the number of <colorParamUINameID> elements.
+
+"""
+
+import DefaultTable
+import struct, sstruct
+from fontTools.misc.textTools import safeEval
+try:
+    import xml.etree.cElementTree as ET
+except ImportError:
+    import xml.etree.ElementTree as ET
+import string
+import types
+import re
+
+XML = ET.XML
+XMLElement = ET.Element
+xmlToString = ET.tostring
+
+SVG_format_0 = """
+	>   # big endian
+	version:                  H
+	offsetToSVGDocIndex:      L
+	offsetToColorPalettes:    L
+"""
+
+SVG_format_0Size = sstruct.calcsize(SVG_format_0)
+
+SVG_format_1 = """
+	>   # big endian
+	version:                  H
+	numIndicies:              H
+"""
+
+SVG_format_1Size = sstruct.calcsize(SVG_format_1)
+
+doc_index_entry_format_0 = """
+	>   # big endian
+	startGlyphID:             H
+	endGlyphID:               H
+	svgDocOffset:             L
+	svgDocLength:             L
+"""
+
+doc_index_entry_format_0Size = sstruct.calcsize(doc_index_entry_format_0)
+
+colorRecord_format_0 = """
+	red:                      B
+	green:                    B
+	blue:                     B
+	alpha:                    B
+"""
+
+
+class table_S_V_G_(DefaultTable.DefaultTable):
+	
+	def decompile(self, data, ttFont):
+		self.docList = None
+		self.colorPalettes = None
+		pos = 0
+		self.version = struct.unpack(">H", data[pos:pos+2])[0]
+		
+		if self.version == 1:
+			self.decompile_format_1(data, ttFont)
+		else:
+			if self.version != 0:
+				print "Unknown SVG table version '%s'. Decompiling as version 0." % (self.version)
+			self.decompile_format_0(data, ttFont)
+
+
+	def decompile_format_0(self, data, ttFont):
+		dummy, data2 = sstruct.unpack2(SVG_format_0, data, self)
+		# read in SVG Documents Index
+		pos = self.offsetToSVGDocIndex
+		self.numEntries = numEntries = struct.unpack(">H", data[pos:pos+2])[0]
+		self.decompileEntryList(data, pos+2)
+
+		# read in colorPalettes table.
+		self.colorPalettes = colorPalettes = ColorPalettes()
+		pos = self.offsetToColorPalettes
+		if pos > 0:
+			colorPalettes.numColorParams = numColorParams = struct.unpack(">H", data[pos:pos+2])[0]
+			if numColorParams > 0:
+				colorPalettes.colorParamUINameIDs = colorParamUINameIDs = []
+				pos = pos + 2
+				i = 0
+				while i < numColorParams:
+					nameID = struct.unpack(">H", data[pos:pos+2])[0]
+					colorParamUINameIDs.append(nameID)
+					pos = pos + 2
+					i += 1
+
+				colorPalettes.numColorPalettes = numColorPalettes = struct.unpack(">H", data[pos:pos+2])[0]
+				pos = pos + 2
+				if numColorPalettes > 0:
+					colorPalettes.colorPaletteList = colorPaletteList = []
+					i = 0
+					while i < numColorPalettes:
+						colorPalette = ColorPalette()
+						colorPaletteList.append(colorPalette)
+						colorPalette.uiNameID = struct.unpack(">H", data[pos:pos+2])[0]
+						pos = pos + 2
+						colorPalette.paletteColors = paletteColors = []
+						j = 0
+						while j < numColorParams:
+							colorRecord, colorPaletteData = sstruct.unpack2(colorRecord_format_0, data[pos:], ColorRecord())
+							paletteColors.append(colorRecord)
+							j += 1
+							pos += 4
+						i += 1
+
+	def decompile_format_1(self, data, ttFont):
+		pos = 2
+		self.numEntries = struct.unpack(">H", data[pos:pos+2])[0]
+		pos += 2
+		self.decompileEntryList(data, pos)
+
+	def decompileEntryList(self, data, pos):
+		# data starts with the first entry of the entry list.
+		if self.numEntries > 0:
+			data2 = data[pos:]
+			self.docList = []
+			self.entries = entries = []
+			i = 0
+			while i < self.numEntries:
+				docIndexEntry, data2 = sstruct.unpack2(doc_index_entry_format_0, data2, DocumentIndexEntry())
+				entries.append(docIndexEntry)
+				i += 1
+
+			for entry in entries:
+				start = entry.svgDocOffset
+				end = start + entry.svgDocLength
+				doc = data[start:end]
+				self.docList.append( [doc, entry.startGlyphID, entry.endGlyphID] )
+
+	def compile(self, ttFont):
+		if hasattr(self, "version1"):
+			data = self.compileFormat1(ttFont)
+		else:
+			data = self.compileFormat0(ttFont)
+		return data
+
+	def compileFormat0(self, ttFont):
+		version = 0
+		offsetToSVGDocIndex = SVG_format_0Size # I start the SVGDocIndex right after the header.
+
+		# get SGVDoc info.
+		docList = []
+		entryList = []
+		numEntries = len(self.docList)
+		datum = struct.pack(">H",numEntries)
+		entryList.append(datum)
+		curOffset = offsetToSVGDocIndex + len(datum) + doc_index_entry_format_0Size*numEntries
+		for doc, startGlyphID, endGlyphID in self.docList:
+			docOffset = curOffset
+			docLength = len(doc)
+			curOffset += docLength
+		 	entry = struct.pack(">HHLL", startGlyphID, endGlyphID, docOffset, docLength)
+		 	entryList.append(entry)
+		 	docList.append(doc)
+		entryList.extend(docList)
+		svgDocData = "".join(entryList)
+
+		# get colorpalette info.
+		if self.colorPalettes == None:
+			offsetToColorPalettes = 0
+			palettesData = ""
+		else:
+			offsetToColorPalettes = SVG_format_0Size + len(svgDocData)
+			dataList = []
+			numColorParams = len(self.colorPalettes.colorParamUINameIDs)
+			datum = struct.pack(">H", numColorParams)
+			dataList.append(datum)
+			for uiNameId in self.colorPalettes.colorParamUINameIDs:
+				datum = struct.pack(">H", uiNameId)
+				dataList.append(datum)
+			numColorPalettes = len(self.colorPalettes.colorPaletteList)
+			datum = struct.pack(">H", numColorPalettes)
+			dataList.append(datum)
+			for colorPalette in self.colorPalettes.colorPaletteList:
+				datum = struct.pack(">H", colorPalette.uiNameID)
+				dataList.append(datum)
+				for colorRecord in colorPalette.paletteColors:
+					data = struct.pack(">BBBB", colorRecord.red, colorRecord.green, colorRecord.blue, colorRecord.alpha)
+					dataList.append(data)
+			palettesData = "".join(dataList)
+
+		header = struct.pack(">HLL", version, offsetToSVGDocIndex, offsetToColorPalettes)
+		data = [header, svgDocData, palettesData]
+		data = "".join(data)
+		return data
+
+	def compileFormat1(self, ttFont):
+		version = 1
+		numEntries = len(self.docList)
+		header = struct.pack(">HH", version, numEntries)
+		dataList = [header]
+		docList = []
+		curOffset = SVG_format_1Size + doc_index_entry_format_0Size*numEntries
+		for doc, startGlyphID, endGlyphID in self.docList:
+			docOffset = curOffset
+			docLength = len(doc)
+			curOffset += docLength
+		 	entry = struct.pack(">HHLL", startGlyphID, endGlyphID, docOffset, docLength)
+		 	dataList.append(entry)
+		 	docList.append(doc)
+		dataList.extend(docList)
+		data = "".join(dataList)
+		return data
+
+	def toXML(self, writer, ttFont):
+		writer.newline()
+		for doc, startGID, endGID in self.docList:
+			writer.begintag("svgDoc", startGlyphID=startGID, endGlyphID=endGID)
+			writer.newline()
+			writer.writeraw("<![CDATA["+ doc + "]]>")
+			writer.newline()
+			writer.endtag("svgDoc")
+			writer.newline()
+
+		if self.colorPalettes.numColorParams != None:
+			writer.begintag("colorPalettes")
+			writer.newline()
+			for uiNameID in self.colorPalettes.colorParamUINameIDs:
+				writer.begintag("colorParamUINameID")
+				writer.writeraw(str(uiNameID))
+				writer.endtag("colorParamUINameID")
+				writer.newline()
+			for colorPalette in self.colorPalettes.colorPaletteList:
+				writer.begintag("colorPalette", [("uiNameID", str(colorPalette.uiNameID))])
+				writer.newline()
+				for colorRecord in colorPalette.paletteColors:
+					colorAttributes = [
+							("red", hex(colorRecord.red)),
+							("green", hex(colorRecord.green)),
+							("blue", hex(colorRecord.blue)),
+							("alpha", hex(colorRecord.alpha)),
+						]
+					writer.begintag("colorRecord", colorAttributes)
+					writer.endtag("colorRecord")
+					writer.newline()
+				writer.endtag("colorPalette")
+				writer.newline()
+
+			writer.endtag("colorPalettes")
+			writer.newline()
+		else:
+			writer.begintag("colorPalettes")
+			writer.endtag("colorPalettes")
+			writer.newline()
+
+	def fromXML(self, (name, attrs, content), ttFont):
+		import re
+		if name == "svgDoc":
+			if not hasattr(self, "docList"):
+				self.docList = []
+			doc = "".join(content)
+			doc = doc.strip()
+			startGID = int(attrs["startGlyphID"])
+			endGID = int(attrs["endGlyphID"])
+			self.docList.append( [doc, startGID, endGID] )
+		elif  name == "colorPalettes":
+			self.colorPalettes = ColorPalettes()
+			self.colorPalettes.fromXML((name, attrs, content), ttFont)
+			if self.colorPalettes.numColorParams == 0:
+				self.colorPalettes = None
+		else:
+			print "Unknown", name, content
+
+class DocumentIndexEntry:
+	def __init__(self):
+		self.startGlyphID = None # USHORT
+		self.endGlyphID = None # USHORT
+		self.svgDocOffset = None # ULONG
+		self.svgDocLength = None # ULONG
+
+	def __repr__(self):
+		return "startGlyphID: %s, endGlyphID: %s, svgDocOffset: %s, svgDocLength: %s" % (self.startGlyphID, self.endGlyphID, self.svgDocOffset, self.svgDocLength)
+
+class ColorPalettes:
+	def __init__(self):
+		self.numColorParams = None # USHORT
+		self.colorParamUINameIDs = [] # list of name table name ID values that provide UI description of each color palette.
+		self.numColorPalettes = None # USHORT
+		self.colorPaletteList = [] # list of ColorPalette records
+
+	def fromXML(self, (name, attrs, content), ttFont):
+		for element in content:
+			if type(element) == type(""):
+				continue
+			name, attrib, content = element
+			if name == "colorParamUINameID":
+				uiNameID = int(content[0])
+				self.colorParamUINameIDs.append(uiNameID)
+			elif name == "colorPalette":
+				colorPalette = ColorPalette()
+				self.colorPaletteList.append(colorPalette)
+				colorPalette.fromXML((name, attrib, content), ttFont)
+
+		self.numColorParams = len(self.colorParamUINameIDs)
+		self.numColorPalettes = len(self.colorPaletteList)
+		for colorPalette in self.colorPaletteList:
+			if len(colorPalette.paletteColors) != self.numColorParams:
+				raise ValueError("Number of color records in a colorPalette ('%s') does not match the number of colorParamUINameIDs elements ('%s')." % (len(colorPalette.paletteColors), self.numColorParams))
+
+class ColorPalette:
+	def __init__(self):
+		self.uiNameID = None # USHORT. name table ID that describes user interface strings associated with this color palette. 
+		self.paletteColors = [] # list of ColorRecords
+
+	def fromXML(self, (name, attrs, content), ttFont):
+		self.uiNameID = int(attrs["uiNameID"])
+		for element in content:
+			if type(element) == type(""):
+				continue
+			name, attrib, content = element
+			if name == "colorRecord":
+				colorRecord = ColorRecord()
+				self.paletteColors.append(colorRecord)
+				colorRecord.red = eval(attrib["red"])
+				colorRecord.green = eval(attrib["green"])
+				colorRecord.blue = eval(attrib["blue"])
+				colorRecord.alpha = eval(attrib["alpha"])
+
+class ColorRecord:
+	def __init__(self):
+		self.red = 255 # all are one byte values.
+		self.green = 255
+		self.blue = 255
+		self.alpha = 255