1package psd
2
3import (
4	"io"
5	"io/ioutil"
6	"math"
7	"unicode/utf16"
8)
9
10func itoa(x int) string {
11	var b [32]byte
12	var minus bool
13	if x < 0 {
14		minus = true
15		x = -x
16	}
17	i := len(b) - 1
18	for x > 9 {
19		b[i] = byte(x%10 + '0')
20		x /= 10
21		i--
22	}
23	b[i] = byte(x + '0')
24	if minus {
25		i--
26		b[i] = '-'
27	}
28	return string(b[i:])
29}
30
31func readUint16(b []byte, offset int) uint16 {
32	return uint16(b[offset])<<8 | uint16(b[offset+1])
33}
34
35func writeUint16(b []byte, v uint16, offset int) {
36	b[offset] = uint8(v >> 8)
37	b[offset+1] = uint8(v)
38}
39
40func readUint32(b []byte, offset int) uint32 {
41	return uint32(b[offset])<<24 | uint32(b[offset+1])<<16 | uint32(b[offset+2])<<8 | uint32(b[offset+3])
42}
43
44func readUint64(b []byte, offset int) uint64 {
45	return uint64(b[offset])<<56 | uint64(b[offset+1])<<48 | uint64(b[offset+2])<<40 | uint64(b[offset+3])<<32 |
46		uint64(b[offset+4])<<24 | uint64(b[offset+5])<<16 | uint64(b[offset+6])<<8 | uint64(b[offset+7])
47}
48
49func get4or8(is64 bool) int {
50	if is64 {
51		return 8
52	}
53	return 4
54}
55
56func readUint(b []byte, offset int, size int) uint64 {
57	switch size {
58	case 8:
59		return readUint64(b, offset)
60	case 4:
61		return uint64(readUint32(b, offset))
62	case 2:
63		return uint64(readUint16(b, offset))
64	case 1:
65		return uint64(b[offset])
66	}
67	panic("psd: unexpected size")
68}
69
70func readFloat32(b []byte, offset int) float32 {
71	return math.Float32frombits(readUint32(b, offset))
72}
73
74func readFloat64(b []byte, offset int) float64 {
75	return math.Float64frombits(readUint64(b, offset))
76}
77
78func writeUint32(b []byte, v uint32, offset int) {
79	b[offset] = uint8(v >> 24)
80	b[offset+1] = uint8(v >> 16)
81	b[offset+2] = uint8(v >> 8)
82	b[offset+3] = uint8(v)
83}
84
85func readUnicodeString(b []byte) string {
86	ln := readUint32(b, 0)
87	if ln == 0 {
88		return ""
89	}
90	buf := make([]uint16, ln)
91	for i := range buf {
92		buf[i] = readUint16(b, 4+i<<1)
93	}
94	return string(utf16.Decode(buf))
95}
96
97func adjustAlign2(r io.Reader, l int) (read int, err error) {
98	if l&1 != 0 {
99		var b [1]byte
100		return r.Read(b[:])
101	}
102	return 0, nil
103}
104
105func adjustAlign4(r io.Reader, l int) (read int, err error) {
106	if gap := l & 3; gap > 0 {
107		var b [4]byte
108		return r.Read(b[:4-gap])
109	}
110	return 0, nil
111}
112
113func discard(r io.Reader, skip int) (read int, err error) {
114	type discarder interface {
115		Discard(n int) (discarded int, err error)
116	}
117	switch rr := r.(type) {
118	case discarder:
119		return rr.Discard(skip)
120	case io.Seeker:
121		if _, err = rr.Seek(int64(skip), 1); err != nil {
122			return 0, err
123		}
124		return skip, nil
125	default:
126		rd, err := io.CopyN(ioutil.Discard, r, int64(skip))
127		return int(rd), err
128	}
129}
130
131func readPascalString(r io.Reader) (str string, read int, err error) {
132	b := make([]byte, 1)
133	if _, err := io.ReadFull(r, b); err != nil {
134		return "", 0, err
135	}
136	if b[0] == 0 {
137		return "", 1, nil
138	}
139	buf := make([]byte, b[0])
140	if _, err := io.ReadFull(r, buf); err != nil {
141		return "", 1, err
142	}
143	return string(buf), len(buf) + 1, nil
144}
145
146func reportReaderPosition(format string, r io.Reader) error {
147	sk, ok := r.(io.Seeker)
148	if !ok {
149		return nil
150	}
151
152	pos, err := sk.Seek(0, 1)
153	if err != nil {
154		return err
155	}
156	Debug.Printf(format, pos)
157	return nil
158}
159