~vtuson/scopecreator/twitter-template

« back to all changes in this revision

Viewing changes to src/go/src/code.google.com/p/go.text/encoding/charmap/charmap.go

  • Committer: Victor Palau
  • Date: 2015-03-11 14:24:42 UTC
  • Revision ID: vtuson@gmail.com-20150311142442-f2pxp111c8ynv232
public release

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2013 The Go Authors. All rights reserved.
 
2
// Use of this source code is governed by a BSD-style
 
3
// license that can be found in the LICENSE file.
 
4
 
 
5
// Package charmap provides simple character encodings such as IBM Code Page 437
 
6
// and Windows 1252.
 
7
package charmap
 
8
 
 
9
import (
 
10
        "unicode/utf8"
 
11
 
 
12
        "code.google.com/p/go.text/transform"
 
13
)
 
14
 
 
15
// utf8Enc holds a rune's UTF-8 encoding in data[:len].
 
16
type utf8Enc struct {
 
17
        len  uint8
 
18
        data [3]byte
 
19
}
 
20
 
 
21
// charmap describes an 8-bit character set encoding.
 
22
type charmap struct {
 
23
        // name is the encoding's name.
 
24
        name string
 
25
        // asciiSuperset states whether the encoding is a superset of ASCII.
 
26
        asciiSuperset bool
 
27
        // low is the lower bound of the encoded byte for a non-ASCII rune. If
 
28
        // charmap.asciiSuperset is true then this will be 0x80, otherwise 0x00.
 
29
        low uint8
 
30
        // replacement is the encoded replacement character.
 
31
        replacement byte
 
32
        // decode is the map from encoded byte to UTF-8.
 
33
        decode [256]utf8Enc
 
34
        // encoding is the map from runes to encoded bytes. Each entry is a
 
35
        // uint32: the high 8 bits are the encoded byte and the low 24 bits are
 
36
        // the rune. The table entries are sorted by ascending rune.
 
37
        encode [256]uint32
 
38
}
 
39
 
 
40
func (m *charmap) NewDecoder() transform.Transformer {
 
41
        return charmapDecoder{charmap: m}
 
42
}
 
43
 
 
44
func (m *charmap) NewEncoder() transform.Transformer {
 
45
        return charmapEncoder{charmap: m}
 
46
}
 
47
 
 
48
func (m *charmap) String() string {
 
49
        return m.name
 
50
}
 
51
 
 
52
// charmapDecoder implements transform.Transformer by decoding to UTF-8.
 
53
type charmapDecoder struct {
 
54
        charmap *charmap
 
55
}
 
56
 
 
57
func (m charmapDecoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
 
58
        for i, c := range src {
 
59
                if m.charmap.asciiSuperset && c < utf8.RuneSelf {
 
60
                        if nDst >= len(dst) {
 
61
                                err = transform.ErrShortDst
 
62
                                break
 
63
                        }
 
64
                        dst[nDst] = c
 
65
                        nDst++
 
66
                        nSrc = i + 1
 
67
                        continue
 
68
                }
 
69
 
 
70
                decode := &m.charmap.decode[c]
 
71
                n := int(decode.len)
 
72
                if nDst+n > len(dst) {
 
73
                        err = transform.ErrShortDst
 
74
                        break
 
75
                }
 
76
                // It's 15% faster to avoid calling copy for these tiny slices.
 
77
                for j := 0; j < n; j++ {
 
78
                        dst[nDst] = decode.data[j]
 
79
                        nDst++
 
80
                }
 
81
                nSrc = i + 1
 
82
        }
 
83
        return nDst, nSrc, err
 
84
}
 
85
 
 
86
// charmapEncoder implements transform.Transformer by encoding from UTF-8.
 
87
type charmapEncoder struct {
 
88
        charmap *charmap
 
89
}
 
90
 
 
91
func (m charmapEncoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
 
92
        r, size := rune(0), 0
 
93
        for nSrc < len(src) {
 
94
                if nDst >= len(dst) {
 
95
                        err = transform.ErrShortDst
 
96
                        break
 
97
                }
 
98
                r = rune(src[nSrc])
 
99
 
 
100
                // Decode a 1-byte rune.
 
101
                if r < utf8.RuneSelf {
 
102
                        nSrc++
 
103
                        if m.charmap.asciiSuperset {
 
104
                                dst[nDst] = uint8(r)
 
105
                                nDst++
 
106
                                continue
 
107
                        }
 
108
 
 
109
                } else {
 
110
                        // Decode a multi-byte rune.
 
111
                        r, size = utf8.DecodeRune(src[nSrc:])
 
112
                        if size == 1 {
 
113
                                // All valid runes of size 1 (those below utf8.RuneSelf) were
 
114
                                // handled above. We have invalid UTF-8 or we haven't seen the
 
115
                                // full character yet.
 
116
                                if !atEOF && !utf8.FullRune(src[nSrc:]) {
 
117
                                        err = transform.ErrShortSrc
 
118
                                        break
 
119
                                }
 
120
                        }
 
121
                        nSrc += size
 
122
                        if r == utf8.RuneError {
 
123
                                dst[nDst] = m.charmap.replacement
 
124
                                nDst++
 
125
                                continue
 
126
                        }
 
127
                }
 
128
 
 
129
                // Binary search in [low, high) for that rune in the m.charmap.encode table.
 
130
                for low, high := int(m.charmap.low), 0x100; ; {
 
131
                        if low >= high {
 
132
                                dst[nDst] = m.charmap.replacement
 
133
                                nDst++
 
134
                                break
 
135
                        }
 
136
                        mid := (low + high) / 2
 
137
                        got := m.charmap.encode[mid]
 
138
                        gotRune := rune(got & (1<<24 - 1))
 
139
                        if gotRune < r {
 
140
                                low = mid + 1
 
141
                        } else if gotRune > r {
 
142
                                high = mid
 
143
                        } else {
 
144
                                dst[nDst] = byte(got >> 24)
 
145
                                nDst++
 
146
                                break
 
147
                        }
 
148
                }
 
149
        }
 
150
        return nDst, nSrc, err
 
151
}