// Sfnt2Woff is a native go port of the JS library
// https://github.com/fontello/ttf2woff
// that converts sfnt fonts (.ttf and .otf) to .woff fonts

package font

import (
	
	
	
	
	
	
)

var (
	// sfnt2Woff offset
	SFNT_OFFSET_TAG      = 0
	SFNT_OFFSET_CHECKSUM = 4
	SFNT_OFFSET_OFFSET   = 8
	SFNT_OFFSET_LENGTH   = 12

	// sfnt2Woff entry offset
	SFNT_ENTRY_OFFSET_FLAVOR              = 0
	SFNT_ENTRY_OFFSET_VERSION_MAJ         = 4
	SFNT_ENTRY_OFFSET_VERSION_MIN         = 6
	SFNT_ENTRY_OFFSET_CHECKSUM_ADJUSTMENT = 8

	// woff offset
	WOFF_OFFSET_MAGIC            = 0
	WOFF_OFFSET_FLAVOR           = 4
	WOFF_OFFSET_SIZE             = 8
	WOFF_OFFSET_NUM_TABLES       = 12
	WOFF_OFFSET_RESERVED         = 14
	WOFF_OFFSET_SFNT_SIZE        = 16
	WOFF_OFFSET_VERSION_MAJ      = 20
	WOFF_OFFSET_VERSION_MIN      = 22
	WOFF_OFFSET_META_OFFSET      = 24
	WOFF_OFFSET_META_LENGTH      = 28
	WOFF_OFFSET_META_ORIG_LENGTH = 32
	WOFF_OFFSET_PRIV_OFFSET      = 36
	WOFF_OFFSET_PRIV_LENGTH      = 40

	// woff entry offset
	WOFF_ENTRY_OFFSET_TAG          = 0
	WOFF_ENTRY_OFFSET_OFFSET       = 4
	WOFF_ENTRY_OFFSET_COMPR_LENGTH = 8
	WOFF_ENTRY_OFFSET_LENGTH       = 12
	WOFF_ENTRY_OFFSET_CHECKSUM     = 16

	// magic
	MAGIC_WOFF                uint32 = 0x774f4646
	MAGIC_CHECKSUM_ADJUSTMENT uint32 = 0xb1b0afba

	// sizes
	SIZE_OF_WOFF_HEADER      = 44
	SIZE_OF_WOFF_ENTRY       = 20
	SIZE_OF_SFNT_HEADER      = 12
	SIZE_OF_SFNT_TABLE_ENTRY = 16
)

type TableEntry struct {
	Tag      []byte
	CheckSum uint32
	Offset   uint32
	Length   uint32
}

func longAlign( uint32) uint32 {
	return ( + 3) & ^uint32(3)
}

func calcChecksum( []byte) uint32 {
	var  uint32 = 0
	var  = len() / 4

	for  := 0;  < ; ++ {
		var  = binary.BigEndian.Uint32([*4:])
		 =  + 
	}
	return 
}

func ( []byte) ([]byte, error) {
	 := binary.BigEndian.Uint16([4:])

	 := make([]byte, SIZE_OF_WOFF_HEADER)
	binary.BigEndian.PutUint32([WOFF_OFFSET_MAGIC:], MAGIC_WOFF)
	binary.BigEndian.PutUint16([WOFF_OFFSET_NUM_TABLES:], )
	binary.BigEndian.PutUint16([WOFF_OFFSET_SFNT_SIZE:], 0)
	binary.BigEndian.PutUint32([WOFF_OFFSET_META_OFFSET:], 0)
	binary.BigEndian.PutUint32([WOFF_OFFSET_META_LENGTH:], 0)
	binary.BigEndian.PutUint32([WOFF_OFFSET_META_ORIG_LENGTH:], 0)
	binary.BigEndian.PutUint32([WOFF_OFFSET_PRIV_OFFSET:], 0)
	binary.BigEndian.PutUint32([WOFF_OFFSET_PRIV_LENGTH:], 0)

	var  []TableEntry

	for  := 0;  < int(); ++ {
		 := [SIZE_OF_SFNT_HEADER+*SIZE_OF_SFNT_TABLE_ENTRY:]

		 := TableEntry{
			Tag:      [SFNT_OFFSET_TAG : SFNT_OFFSET_TAG+4],
			CheckSum: binary.BigEndian.Uint32([SFNT_OFFSET_CHECKSUM:]),
			Offset:   binary.BigEndian.Uint32([SFNT_OFFSET_OFFSET:]),
			Length:   binary.BigEndian.Uint32([SFNT_OFFSET_LENGTH:]),
		}

		 = append(, )
	}
	sort.Slice(, func(,  int) bool {
		return string([].Tag) < string([].Tag)
	})

	 := uint32(SIZE_OF_SFNT_HEADER + int()*SIZE_OF_SFNT_TABLE_ENTRY)
	 := make([]byte, int()*SIZE_OF_WOFF_ENTRY)

	for  := 0;  < len(); ++ {
		 := []
		if string(.Tag) != "head" {
			 := [.Offset : .Offset+longAlign(.Length)]

			if calcChecksum() != .CheckSum {
				return nil, fmt.Errorf("checksum error in table: %v", string(.Tag))
			}
		}

		binary.BigEndian.PutUint32([*SIZE_OF_WOFF_ENTRY+WOFF_ENTRY_OFFSET_TAG:], binary.BigEndian.Uint32(.Tag))
		binary.BigEndian.PutUint32([*SIZE_OF_WOFF_ENTRY+WOFF_ENTRY_OFFSET_LENGTH:], .Length)
		binary.BigEndian.PutUint32([*SIZE_OF_WOFF_ENTRY+WOFF_ENTRY_OFFSET_CHECKSUM:], .CheckSum)

		 += longAlign(.Length)
	}

	 := uint32(SIZE_OF_SFNT_HEADER + len()*SIZE_OF_SFNT_TABLE_ENTRY)
	 := calcChecksum([:SIZE_OF_SFNT_HEADER])
	for  := 0;  < len(); ++ {
		 := []

		 := make([]byte, SIZE_OF_SFNT_TABLE_ENTRY)
		binary.BigEndian.PutUint32([SFNT_OFFSET_TAG:], binary.BigEndian.Uint32(.Tag))
		binary.BigEndian.PutUint32([SFNT_OFFSET_CHECKSUM:], .CheckSum)
		binary.BigEndian.PutUint32([SFNT_OFFSET_OFFSET:], )
		binary.BigEndian.PutUint32([SFNT_OFFSET_LENGTH:], .Length)

		 += longAlign(.Length)
		 += calcChecksum()
		 += .CheckSum
	}

	var  = MAGIC_CHECKSUM_ADJUSTMENT - 

	 := uint16(0)
	 := uint16(1)
	 := uint32(0)
	 := SIZE_OF_WOFF_HEADER + int()*SIZE_OF_WOFF_ENTRY
	var  []byte

	for  := 0;  < len(); ++ {
		 := []

		 := [.Offset : .Offset+.Length]
		if string(.Tag) == "head" {
			 = binary.BigEndian.Uint16([SFNT_ENTRY_OFFSET_VERSION_MAJ:])
			 = binary.BigEndian.Uint16([SFNT_ENTRY_OFFSET_VERSION_MIN:])
			 = binary.BigEndian.Uint32([SFNT_ENTRY_OFFSET_FLAVOR:])
			binary.BigEndian.PutUint32([SFNT_ENTRY_OFFSET_CHECKSUM_ADJUSTMENT:], uint32())
		}

		var  bytes.Buffer
		 := zlib.NewWriter(&)
		.Write()
		.Flush()
		.Close()

		 := math.Min(float64(len(.Bytes())), float64(len()))
		 := longAlign(uint32())

		 := make([]byte, )
		// only deflate data if the deflated data is actually smaller
		if len(.Bytes()) >= len() {
			copy(, )
		} else {
			copy(, .Bytes())
		}

		binary.BigEndian.PutUint32([*SIZE_OF_WOFF_ENTRY+WOFF_ENTRY_OFFSET_OFFSET:], uint32())

		 += len()

		binary.BigEndian.PutUint32([*SIZE_OF_WOFF_ENTRY+WOFF_ENTRY_OFFSET_COMPR_LENGTH:], uint32())

		 = append(, ...)

	}

	 := uint32(len() + len() + len())
	binary.BigEndian.PutUint32([WOFF_OFFSET_SIZE:], )
	binary.BigEndian.PutUint32([WOFF_OFFSET_SFNT_SIZE:], )
	binary.BigEndian.PutUint16([WOFF_OFFSET_VERSION_MAJ:], )
	binary.BigEndian.PutUint16([WOFF_OFFSET_VERSION_MIN:], )
	binary.BigEndian.PutUint32([WOFF_OFFSET_FLAVOR:], )

	var  []byte
	 = append(, ...)
	 = append(, ...)
	 = append(, ...)

	return , nil
}