| File | File |  | 
|  |  | @@ -0,0 +1,438 @@
 | 
|  | 1 | package woff2
 | 
|  | 2 | 
 | 
|  | 3 | import (
 | 
|  | 4 | 	"bytes"
 | 
|  | 5 | 	"encoding/binary"
 | 
|  | 6 | 	"fmt"
 | 
|  | 7 | 	"io"
 | 
|  | 8 | 
 | 
|  | 9 | 	"github.com/dsnet/compress/brotli"
 | 
|  | 10 | )
 | 
|  | 11 | 
 | 
|  | 12 | // File represents a parsed WOFF2 file.
 | 
|  | 13 | type File struct {
 | 
|  | 14 | 	Header         Header
 | 
|  | 15 | 	TableDirectory TableDirectory
 | 
|  | 16 | 	// CollectionDirectory is present only if the font is a collection,
 | 
|  | 17 | 	// as reported by Header.IsCollection.
 | 
|  | 18 | 	CollectionDirectory *CollectionDirectory
 | 
|  | 19 | 
 | 
|  | 20 | 	// FontData is the concatenation of data for each table in the font.
 | 
|  | 21 | 	// During storage, it's compressed using Brotli.
 | 
|  | 22 | 	FontData []byte
 | 
|  | 23 | 
 | 
|  | 24 | 	ExtendedMetadata *ExtendedMetadata
 | 
|  | 25 | 
 | 
|  | 26 | 	// PrivateData is an optional block of private data for the font designer,
 | 
|  | 27 | 	// foundry, or vendor to use.
 | 
|  | 28 | 	PrivateData []byte
 | 
|  | 29 | }
 | 
|  | 30 | 
 | 
|  | 31 | // Parse parses the WOFF2 data from r.
 | 
|  | 32 | func Parse(r io.Reader) (File, error) {
 | 
|  | 33 | 	hdr, err := parseHeader(r)
 | 
|  | 34 | 	if err != nil {
 | 
|  | 35 | 		return File{}, err
 | 
|  | 36 | 	}
 | 
|  | 37 | 	td, err := parseTableDirectory(r, hdr)
 | 
|  | 38 | 	if err != nil {
 | 
|  | 39 | 		return File{}, err
 | 
|  | 40 | 	}
 | 
|  | 41 | 	cd, err := parseCollectionDirectory(r, hdr)
 | 
|  | 42 | 	if err != nil {
 | 
|  | 43 | 		return File{}, err
 | 
|  | 44 | 	}
 | 
|  | 45 | 	fd, err := parseCompressedFontData(r, hdr, td)
 | 
|  | 46 | 	if err != nil {
 | 
|  | 47 | 		return File{}, err
 | 
|  | 48 | 	}
 | 
|  | 49 | 	em, err := parseExtendedMetadata(r, hdr)
 | 
|  | 50 | 	if err != nil {
 | 
|  | 51 | 		return File{}, err
 | 
|  | 52 | 	}
 | 
|  | 53 | 	pd, err := parsePrivateData(r, hdr)
 | 
|  | 54 | 	if err != nil {
 | 
|  | 55 | 		return File{}, err
 | 
|  | 56 | 	}
 | 
|  | 57 | 
 | 
|  | 58 | 	n, err := io.Copy(discardZeroes{}, r)
 | 
|  | 59 | 	if err != nil {
 | 
|  | 60 | 		return File{}, fmt.Errorf("Parse: %v", err)
 | 
|  | 61 | 	}
 | 
|  | 62 | 	if n > 3 {
 | 
|  | 63 | 		return File{}, fmt.Errorf("Parse: %d bytes left remaining, want no more than 3", n)
 | 
|  | 64 | 	}
 | 
|  | 65 | 
 | 
|  | 66 | 	return File{
 | 
|  | 67 | 		Header:              hdr,
 | 
|  | 68 | 		TableDirectory:      td,
 | 
|  | 69 | 		CollectionDirectory: cd,
 | 
|  | 70 | 		FontData:            fd,
 | 
|  | 71 | 		ExtendedMetadata:    em,
 | 
|  | 72 | 		PrivateData:         pd,
 | 
|  | 73 | 	}, nil
 | 
|  | 74 | }
 | 
|  | 75 | 
 | 
|  | 76 | // discardZeroes is an io.Writer that returns an error if any non-zero bytes are written to it.
 | 
|  | 77 | type discardZeroes struct{}
 | 
|  | 78 | 
 | 
|  | 79 | func (discardZeroes) Write(p []byte) (int, error) {
 | 
|  | 80 | 	for _, b := range p {
 | 
|  | 81 | 		if b != 0 {
 | 
|  | 82 | 			return 0, fmt.Errorf("encountered non-zero byte %d", b)
 | 
|  | 83 | 		}
 | 
|  | 84 | 	}
 | 
|  | 85 | 	return len(p), nil
 | 
|  | 86 | }
 | 
|  | 87 | 
 | 
|  | 88 | // Header is the file header with basic font type and version,
 | 
|  | 89 | // along with offsets to metadata and private data blocks.
 | 
|  | 90 | type Header struct {
 | 
|  | 91 | 	Signature           uint32 // The identifying signature; must be 0x774F4632 ('wOF2').
 | 
|  | 92 | 	Flavor              uint32 // The "sfnt version" of the input font.
 | 
|  | 93 | 	Length              uint32 // Total size of the WOFF file.
 | 
|  | 94 | 	NumTables           uint16 // Number of entries in directory of font tables.
 | 
|  | 95 | 	Reserved            uint16 // Reserved; set to 0.
 | 
|  | 96 | 	TotalSfntSize       uint32 // Total size needed for the uncompressed font data, including the sfnt header, directory, and font tables (including padding).
 | 
|  | 97 | 	TotalCompressedSize uint32 // Total length of the compressed data block.
 | 
|  | 98 | 	MajorVersion        uint16 // Major version of the WOFF file.
 | 
|  | 99 | 	MinorVersion        uint16 // Minor version of the WOFF file.
 | 
|  | 100 | 	MetaOffset          uint32 // Offset to metadata block, from beginning of WOFF file.
 | 
|  | 101 | 	MetaLength          uint32 // Length of compressed metadata block.
 | 
|  | 102 | 	MetaOrigLength      uint32 // Uncompressed size of metadata block.
 | 
|  | 103 | 	PrivOffset          uint32 // Offset to private data block, from beginning of WOFF file.
 | 
|  | 104 | 	PrivLength          uint32 // Length of private data block.
 | 
|  | 105 | }
 | 
|  | 106 | 
 | 
|  | 107 | func parseHeader(r io.Reader) (Header, error) {
 | 
|  | 108 | 	var hdr Header
 | 
|  | 109 | 	err := binary.Read(r, order, &hdr)
 | 
|  | 110 | 	if err != nil {
 | 
|  | 111 | 		return Header{}, err
 | 
|  | 112 | 	}
 | 
|  | 113 | 	if hdr.Signature != signature {
 | 
|  | 114 | 		return Header{}, fmt.Errorf("parseHeader: invalid signature: got %#08x, want %#08x", hdr.Signature, signature)
 | 
|  | 115 | 	}
 | 
|  | 116 | 	return hdr, nil
 | 
|  | 117 | }
 | 
|  | 118 | 
 | 
|  | 119 | // IsCollection reports whether this is a font collection, i.e.,
 | 
|  | 120 | // if the value of Flavor field is set to the TrueType Collection flavor 'ttcf'.
 | 
|  | 121 | func (hdr Header) IsCollection() bool {
 | 
|  | 122 | 	return hdr.Flavor == ttcfFlavor
 | 
|  | 123 | }
 | 
|  | 124 | 
 | 
|  | 125 | // TableDirectory is the directory of font tables, containing size and other info.
 | 
|  | 126 | type TableDirectory []TableDirectoryEntry
 | 
|  | 127 | 
 | 
|  | 128 | func parseTableDirectory(r io.Reader, hdr Header) (TableDirectory, error) {
 | 
|  | 129 | 	var td TableDirectory
 | 
|  | 130 | 	for i := 0; i < int(hdr.NumTables); i++ {
 | 
|  | 131 | 		var e TableDirectoryEntry
 | 
|  | 132 | 
 | 
|  | 133 | 		err := readU8(r, &e.Flags)
 | 
|  | 134 | 		if err != nil {
 | 
|  | 135 | 			return nil, err
 | 
|  | 136 | 		}
 | 
|  | 137 | 		if e.Flags&0x3f == 0x3f {
 | 
|  | 138 | 			e.Tag = new(uint32)
 | 
|  | 139 | 			err := readU32(r, e.Tag)
 | 
|  | 140 | 			if err != nil {
 | 
|  | 141 | 				return nil, err
 | 
|  | 142 | 			}
 | 
|  | 143 | 		}
 | 
|  | 144 | 		err = readBase128(r, &e.OrigLength)
 | 
|  | 145 | 		if err != nil {
 | 
|  | 146 | 			return nil, err
 | 
|  | 147 | 		}
 | 
|  | 148 | 
 | 
|  | 149 | 		switch tag, transformVersion := e.tag(), e.transformVersion(); tag {
 | 
|  | 150 | 		case glyfTable, locaTable:
 | 
|  | 151 | 			// 0 means transform for glyf/loca tables.
 | 
|  | 152 | 			if transformVersion == 0 {
 | 
|  | 153 | 				e.TransformLength = new(uint32)
 | 
|  | 154 | 				err := readBase128(r, e.TransformLength)
 | 
|  | 155 | 				if err != nil {
 | 
|  | 156 | 					return nil, err
 | 
|  | 157 | 				}
 | 
|  | 158 | 
 | 
|  | 159 | 				// The transform length of the transformed loca table MUST always be zero.
 | 
|  | 160 | 				if tag == locaTable && *e.TransformLength != 0 {
 | 
|  | 161 | 					return nil, fmt.Errorf("parseTableDirectory: 'loca' table has non-zero transform length %d", *e.TransformLength)
 | 
|  | 162 | 				}
 | 
|  | 163 | 			}
 | 
|  | 164 | 		default:
 | 
|  | 165 | 			// Non-0 means transform for other tables.
 | 
|  | 166 | 			if transformVersion != 0 {
 | 
|  | 167 | 				e.TransformLength = new(uint32)
 | 
|  | 168 | 				err := readBase128(r, e.TransformLength)
 | 
|  | 169 | 				if err != nil {
 | 
|  | 170 | 					return nil, err
 | 
|  | 171 | 				}
 | 
|  | 172 | 			}
 | 
|  | 173 | 		}
 | 
|  | 174 | 
 | 
|  | 175 | 		td = append(td, e)
 | 
|  | 176 | 	}
 | 
|  | 177 | 	return td, nil
 | 
|  | 178 | }
 | 
|  | 179 | 
 | 
|  | 180 | // Table is a high-level representation of a table.
 | 
|  | 181 | type Table struct {
 | 
|  | 182 | 	Tag    uint32
 | 
|  | 183 | 	Offset int
 | 
|  | 184 | 	Length int
 | 
|  | 185 | }
 | 
|  | 186 | 
 | 
|  | 187 | // Tables returns the derived high-level information
 | 
|  | 188 | // about the tables in the table directory.
 | 
|  | 189 | func (td TableDirectory) Tables() []Table {
 | 
|  | 190 | 	var ts []Table
 | 
|  | 191 | 	var offset int
 | 
|  | 192 | 	for _, t := range td {
 | 
|  | 193 | 		length := int(t.length())
 | 
|  | 194 | 		ts = append(ts, Table{
 | 
|  | 195 | 			Tag:    t.tag(),
 | 
|  | 196 | 			Offset: offset,
 | 
|  | 197 | 			Length: length,
 | 
|  | 198 | 		})
 | 
|  | 199 | 		offset += length
 | 
|  | 200 | 	}
 | 
|  | 201 | 	return ts
 | 
|  | 202 | }
 | 
|  | 203 | 
 | 
|  | 204 | // uncompressedSize computes the total uncompressed size
 | 
|  | 205 | // of the tables in the table directory.
 | 
|  | 206 | func (td TableDirectory) uncompressedSize() int64 {
 | 
|  | 207 | 	var n int64
 | 
|  | 208 | 	for _, t := range td {
 | 
|  | 209 | 		n += int64(t.length())
 | 
|  | 210 | 	}
 | 
|  | 211 | 	return n
 | 
|  | 212 | }
 | 
|  | 213 | 
 | 
|  | 214 | // TableDirectoryEntry is a table directory entry.
 | 
|  | 215 | type TableDirectoryEntry struct {
 | 
|  | 216 | 	Flags           uint8   // Table type and flags.
 | 
|  | 217 | 	Tag             *uint32 // 4-byte tag (optional).
 | 
|  | 218 | 	OrigLength      uint32  // Length of original table.
 | 
|  | 219 | 	TransformLength *uint32 // Transformed length (optional).
 | 
|  | 220 | }
 | 
|  | 221 | 
 | 
|  | 222 | func (e TableDirectoryEntry) tag() uint32 {
 | 
|  | 223 | 	switch e.Tag {
 | 
|  | 224 | 	case nil:
 | 
|  | 225 | 		return knownTableTags[e.Flags&0x3f] // Bits [0..5].
 | 
|  | 226 | 	default:
 | 
|  | 227 | 		return *e.Tag
 | 
|  | 228 | 	}
 | 
|  | 229 | }
 | 
|  | 230 | 
 | 
|  | 231 | func (e TableDirectoryEntry) transformVersion() uint8 {
 | 
|  | 232 | 	return e.Flags >> 6 // Bits [6..7].
 | 
|  | 233 | }
 | 
|  | 234 | 
 | 
|  | 235 | func (e TableDirectoryEntry) length() uint32 {
 | 
|  | 236 | 	switch e.TransformLength {
 | 
|  | 237 | 	case nil:
 | 
|  | 238 | 		return e.OrigLength
 | 
|  | 239 | 	default:
 | 
|  | 240 | 		return *e.TransformLength
 | 
|  | 241 | 	}
 | 
|  | 242 | }
 | 
|  | 243 | 
 | 
|  | 244 | // CollectionDirectory is an optional table containing the font fragment descriptions
 | 
|  | 245 | // of font collection entries.
 | 
|  | 246 | type CollectionDirectory struct {
 | 
|  | 247 | 	Header  CollectionHeader
 | 
|  | 248 | 	Entries []CollectionFontEntry
 | 
|  | 249 | }
 | 
|  | 250 | 
 | 
|  | 251 | // CollectionHeader is a part of CollectionDirectory.
 | 
|  | 252 | type CollectionHeader struct {
 | 
|  | 253 | 	Version  uint32
 | 
|  | 254 | 	NumFonts uint16
 | 
|  | 255 | }
 | 
|  | 256 | 
 | 
|  | 257 | // CollectionFontEntry represents a CollectionFontEntry record.
 | 
|  | 258 | type CollectionFontEntry struct {
 | 
|  | 259 | 	NumTables    uint16   // The number of tables in this font.
 | 
|  | 260 | 	Flavor       uint32   // The "sfnt version" of the font.
 | 
|  | 261 | 	TableIndices []uint16 // The indicies identifying an entry in the Table Directory for each table in this font.
 | 
|  | 262 | }
 | 
|  | 263 | 
 | 
|  | 264 | func parseCollectionDirectory(r io.Reader, hdr Header) (*CollectionDirectory, error) {
 | 
|  | 265 | 	// CollectionDirectory is present only if the input font is a collection.
 | 
|  | 266 | 	if !hdr.IsCollection() {
 | 
|  | 267 | 		return nil, nil
 | 
|  | 268 | 	}
 | 
|  | 269 | 
 | 
|  | 270 | 	var cd CollectionDirectory
 | 
|  | 271 | 	err := readU32(r, &cd.Header.Version)
 | 
|  | 272 | 	if err != nil {
 | 
|  | 273 | 		return nil, err
 | 
|  | 274 | 	}
 | 
|  | 275 | 	err = read255UShort(r, &cd.Header.NumFonts)
 | 
|  | 276 | 	if err != nil {
 | 
|  | 277 | 		return nil, err
 | 
|  | 278 | 	}
 | 
|  | 279 | 	for i := 0; i < int(cd.Header.NumFonts); i++ {
 | 
|  | 280 | 		var e CollectionFontEntry
 | 
|  | 281 | 
 | 
|  | 282 | 		err := read255UShort(r, &e.NumTables)
 | 
|  | 283 | 		if err != nil {
 | 
|  | 284 | 			return nil, err
 | 
|  | 285 | 		}
 | 
|  | 286 | 		err = readU32(r, &e.Flavor)
 | 
|  | 287 | 		if err != nil {
 | 
|  | 288 | 			return nil, err
 | 
|  | 289 | 		}
 | 
|  | 290 | 		for j := 0; j < int(e.NumTables); j++ {
 | 
|  | 291 | 			var tableIndex uint16
 | 
|  | 292 | 			err := read255UShort(r, &tableIndex)
 | 
|  | 293 | 			if err != nil {
 | 
|  | 294 | 				return nil, err
 | 
|  | 295 | 			}
 | 
|  | 296 | 			if tableIndex >= hdr.NumTables {
 | 
|  | 297 | 				return nil, fmt.Errorf("parseCollectionDirectory: tableIndex >= hdr.NumTables")
 | 
|  | 298 | 			}
 | 
|  | 299 | 			e.TableIndices = append(e.TableIndices, tableIndex)
 | 
|  | 300 | 		}
 | 
|  | 301 | 
 | 
|  | 302 | 		cd.Entries = append(cd.Entries, e)
 | 
|  | 303 | 	}
 | 
|  | 304 | 	return &cd, nil
 | 
|  | 305 | }
 | 
|  | 306 | 
 | 
|  | 307 | func parseCompressedFontData(r io.Reader, hdr Header, td TableDirectory) ([]byte, error) {
 | 
|  | 308 | 	// Compressed font data.
 | 
|  | 309 | 	br, err := brotli.NewReader(io.LimitReader(r, int64(hdr.TotalCompressedSize)), nil)
 | 
|  | 310 | 	//br, err := brotli.NewReader(&exactReader{R: r, N: int64(hdr.TotalCompressedSize)}, nil)
 | 
|  | 311 | 	if err != nil {
 | 
|  | 312 | 		return nil, err
 | 
|  | 313 | 	}
 | 
|  | 314 | 	var buf bytes.Buffer
 | 
|  | 315 | 	n, err := io.Copy(&buf, br)
 | 
|  | 316 | 	if err != nil {
 | 
|  | 317 | 		return nil, fmt.Errorf("parseCompressedFontData: io.Copy: %v", err)
 | 
|  | 318 | 	}
 | 
|  | 319 | 	err = br.Close()
 | 
|  | 320 | 	if err != nil {
 | 
|  | 321 | 		return nil, fmt.Errorf("parseCompressedFontData: br.Close: %v", err)
 | 
|  | 322 | 	}
 | 
|  | 323 | 	if uncompressedSize := td.uncompressedSize(); n != uncompressedSize {
 | 
|  | 324 | 		return nil, fmt.Errorf("parseCompressedFontData: unexpected size of uncompressed data: got %d, want %d", n, uncompressedSize)
 | 
|  | 325 | 	}
 | 
|  | 326 | 	return buf.Bytes(), nil
 | 
|  | 327 | }
 | 
|  | 328 | 
 | 
|  | 329 | // ExtendedMetadata is an optional block of extended metadata,
 | 
|  | 330 | // represented in XML format and compressed for storage in the WOFF2 file.
 | 
|  | 331 | type ExtendedMetadata struct{}
 | 
|  | 332 | 
 | 
|  | 333 | func parseExtendedMetadata(r io.Reader, hdr Header) (*ExtendedMetadata, error) {
 | 
|  | 334 | 	if hdr.MetaLength == 0 {
 | 
|  | 335 | 		return nil, nil
 | 
|  | 336 | 	}
 | 
|  | 337 | 	return nil, fmt.Errorf("parseExtendedMetadata: not implemented")
 | 
|  | 338 | }
 | 
|  | 339 | 
 | 
|  | 340 | func parsePrivateData(r io.Reader, hdr Header) ([]byte, error) {
 | 
|  | 341 | 	if hdr.PrivLength == 0 {
 | 
|  | 342 | 		return nil, nil
 | 
|  | 343 | 	}
 | 
|  | 344 | 	return nil, fmt.Errorf("parsePrivateData: not implemented")
 | 
|  | 345 | }
 | 
|  | 346 | 
 | 
|  | 347 | // readU8 reads a UInt8 value.
 | 
|  | 348 | func readU8(r io.Reader, v *uint8) error {
 | 
|  | 349 | 	return binary.Read(r, order, v)
 | 
|  | 350 | }
 | 
|  | 351 | 
 | 
|  | 352 | // readU16 reads a UInt16 value.
 | 
|  | 353 | func readU16(r io.Reader, v *uint16) error {
 | 
|  | 354 | 	return binary.Read(r, order, v)
 | 
|  | 355 | }
 | 
|  | 356 | 
 | 
|  | 357 | // readU32 reads a UInt32 value.
 | 
|  | 358 | func readU32(r io.Reader, v *uint32) error {
 | 
|  | 359 | 	return binary.Read(r, order, v)
 | 
|  | 360 | }
 | 
|  | 361 | 
 | 
|  | 362 | // readBase128 reads a UIntBase128 value.
 | 
|  | 363 | func readBase128(r io.Reader, v *uint32) error {
 | 
|  | 364 | 	var accum uint32
 | 
|  | 365 | 	for i := 0; i < 5; i++ {
 | 
|  | 366 | 		var data uint8
 | 
|  | 367 | 		err := binary.Read(r, order, &data)
 | 
|  | 368 | 		if err != nil {
 | 
|  | 369 | 			return err
 | 
|  | 370 | 		}
 | 
|  | 371 | 
 | 
|  | 372 | 		// Leading zeros are invalid.
 | 
|  | 373 | 		if i == 0 && data == 0x80 {
 | 
|  | 374 | 			return fmt.Errorf("leading zero is invalid")
 | 
|  | 375 | 		}
 | 
|  | 376 | 
 | 
|  | 377 | 		// If any of top 7 bits are set then accum << 7 would overflow.
 | 
|  | 378 | 		if accum&0xfe000000 != 0 {
 | 
|  | 379 | 			return fmt.Errorf("top seven bits are set, about to overflow")
 | 
|  | 380 | 		}
 | 
|  | 381 | 
 | 
|  | 382 | 		accum = (accum << 7) | uint32(data)&0x7f
 | 
|  | 383 | 
 | 
|  | 384 | 		// Spin until most significant bit of data byte is false.
 | 
|  | 385 | 		if (data & 0x80) == 0 {
 | 
|  | 386 | 			*v = accum
 | 
|  | 387 | 			return nil
 | 
|  | 388 | 		}
 | 
|  | 389 | 	}
 | 
|  | 390 | 	return fmt.Errorf("UIntBase128 sequence exceeds 5 bytes")
 | 
|  | 391 | }
 | 
|  | 392 | 
 | 
|  | 393 | // read255UShort reads a 255UInt16 value.
 | 
|  | 394 | func read255UShort(r io.Reader, v *uint16) error {
 | 
|  | 395 | 	const (
 | 
|  | 396 | 		oneMoreByteCode1 = 255
 | 
|  | 397 | 		oneMoreByteCode2 = 254
 | 
|  | 398 | 		wordCode         = 253
 | 
|  | 399 | 		lowestUCode      = 253
 | 
|  | 400 | 	)
 | 
|  | 401 | 	var code uint8
 | 
|  | 402 | 	err := binary.Read(r, order, &code)
 | 
|  | 403 | 	if err != nil {
 | 
|  | 404 | 		return err
 | 
|  | 405 | 	}
 | 
|  | 406 | 	switch code {
 | 
|  | 407 | 	case wordCode:
 | 
|  | 408 | 		var value uint16
 | 
|  | 409 | 		err := binary.Read(r, order, &value)
 | 
|  | 410 | 		if err != nil {
 | 
|  | 411 | 			return err
 | 
|  | 412 | 		}
 | 
|  | 413 | 		*v = value
 | 
|  | 414 | 		return nil
 | 
|  | 415 | 	case oneMoreByteCode1:
 | 
|  | 416 | 		var value uint8
 | 
|  | 417 | 		err := binary.Read(r, order, &value)
 | 
|  | 418 | 		if err != nil {
 | 
|  | 419 | 			return err
 | 
|  | 420 | 		}
 | 
|  | 421 | 		*v = uint16(value) + lowestUCode
 | 
|  | 422 | 		return nil
 | 
|  | 423 | 	case oneMoreByteCode2:
 | 
|  | 424 | 		var value uint8
 | 
|  | 425 | 		err := binary.Read(r, order, &value)
 | 
|  | 426 | 		if err != nil {
 | 
|  | 427 | 			return err
 | 
|  | 428 | 		}
 | 
|  | 429 | 		*v = uint16(value) + lowestUCode*2
 | 
|  | 430 | 		return nil
 | 
|  | 431 | 	default:
 | 
|  | 432 | 		*v = uint16(code)
 | 
|  | 433 | 		return nil
 | 
|  | 434 | 	}
 | 
|  | 435 | }
 | 
|  | 436 | 
 | 
|  | 437 | // WOFF2 uses big endian encoding.
 | 
|  | 438 | var order binary.ByteOrder = binary.BigEndian
 |