| 
									
										
										
										
											2015-05-14 12:29:41 +02:00
										 |  |  | // Copyright 2013 The Go Authors. All rights reserved. | 
					
						
							|  |  |  | // Use of this source code is governed by a BSD-style | 
					
						
							|  |  |  | // license that can be found in the LICENSE file. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package simplifiedchinese | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"errors" | 
					
						
							|  |  |  | 	"unicode/utf8" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"golang.org/x/text/encoding" | 
					
						
							|  |  |  | 	"golang.org/x/text/encoding/internal" | 
					
						
							|  |  |  | 	"golang.org/x/text/encoding/internal/identifier" | 
					
						
							|  |  |  | 	"golang.org/x/text/transform" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var ( | 
					
						
							|  |  |  | 	// GB18030 is the GB18030 encoding. | 
					
						
							|  |  |  | 	GB18030 encoding.Encoding = &gbk18030 | 
					
						
							|  |  |  | 	// GBK is the GBK encoding. It encodes an extension of the GB2312 character set | 
					
						
							|  |  |  | 	// and is also known as Code Page 936. | 
					
						
							|  |  |  | 	GBK encoding.Encoding = &gbk | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var gbk = internal.Encoding{ | 
					
						
							|  |  |  | 	&internal.SimpleEncoding{ | 
					
						
							|  |  |  | 		gbkDecoder{gb18030: false}, | 
					
						
							|  |  |  | 		gbkEncoder{gb18030: false}, | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 	"GBK", | 
					
						
							|  |  |  | 	identifier.GBK, | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var gbk18030 = internal.Encoding{ | 
					
						
							|  |  |  | 	&internal.SimpleEncoding{ | 
					
						
							|  |  |  | 		gbkDecoder{gb18030: true}, | 
					
						
							|  |  |  | 		gbkEncoder{gb18030: true}, | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 	"GB18030", | 
					
						
							|  |  |  | 	identifier.GB18030, | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var ( | 
					
						
							|  |  |  | 	errInvalidGB18030 = errors.New("simplifiedchinese: invalid GB18030 encoding") | 
					
						
							|  |  |  | 	errInvalidGBK     = errors.New("simplifiedchinese: invalid GBK encoding") | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type gbkDecoder struct { | 
					
						
							|  |  |  | 	transform.NopResetter | 
					
						
							|  |  |  | 	gb18030 bool | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (d gbkDecoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { | 
					
						
							|  |  |  | 	r, size := rune(0), 0 | 
					
						
							|  |  |  | loop: | 
					
						
							|  |  |  | 	for ; nSrc < len(src); nSrc += size { | 
					
						
							|  |  |  | 		switch c0 := src[nSrc]; { | 
					
						
							|  |  |  | 		case c0 < utf8.RuneSelf: | 
					
						
							|  |  |  | 			r, size = rune(c0), 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Microsoft's Code Page 936 extends GBK 1.0 to encode the euro sign U+20AC | 
					
						
							|  |  |  | 		// as 0x80. The HTML5 specification at http://encoding.spec.whatwg.org/#gbk | 
					
						
							|  |  |  | 		// says to treat "gbk" as Code Page 936. | 
					
						
							|  |  |  | 		case c0 == 0x80: | 
					
						
							|  |  |  | 			r, size = '€', 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case c0 < 0xff: | 
					
						
							|  |  |  | 			if nSrc+1 >= len(src) { | 
					
						
							|  |  |  | 				err = transform.ErrShortSrc | 
					
						
							|  |  |  | 				break loop | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			c1 := src[nSrc+1] | 
					
						
							|  |  |  | 			switch { | 
					
						
							|  |  |  | 			case 0x40 <= c1 && c1 < 0x7f: | 
					
						
							|  |  |  | 				c1 -= 0x40 | 
					
						
							|  |  |  | 			case 0x80 <= c1 && c1 < 0xff: | 
					
						
							|  |  |  | 				c1 -= 0x41 | 
					
						
							|  |  |  | 			case d.gb18030 && 0x30 <= c1 && c1 < 0x40: | 
					
						
							|  |  |  | 				if nSrc+3 >= len(src) { | 
					
						
							|  |  |  | 					err = transform.ErrShortSrc | 
					
						
							|  |  |  | 					break loop | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				c2 := src[nSrc+2] | 
					
						
							|  |  |  | 				if c2 < 0x81 || 0xff <= c2 { | 
					
						
							|  |  |  | 					err = errInvalidGB18030 | 
					
						
							|  |  |  | 					break loop | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				c3 := src[nSrc+3] | 
					
						
							|  |  |  | 				if c3 < 0x30 || 0x3a <= c3 { | 
					
						
							|  |  |  | 					err = errInvalidGB18030 | 
					
						
							|  |  |  | 					break loop | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				size = 4 | 
					
						
							|  |  |  | 				r = ((rune(c0-0x81)*10+rune(c1-0x30))*126+rune(c2-0x81))*10 + rune(c3-0x30) | 
					
						
							|  |  |  | 				if r < 39420 { | 
					
						
							|  |  |  | 					i, j := 0, len(gb18030) | 
					
						
							|  |  |  | 					for i < j { | 
					
						
							|  |  |  | 						h := i + (j-i)/2 | 
					
						
							|  |  |  | 						if r >= rune(gb18030[h][0]) { | 
					
						
							|  |  |  | 							i = h + 1 | 
					
						
							|  |  |  | 						} else { | 
					
						
							|  |  |  | 							j = h | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					dec := &gb18030[i-1] | 
					
						
							|  |  |  | 					r += rune(dec[1]) - rune(dec[0]) | 
					
						
							|  |  |  | 					goto write | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				r -= 189000 | 
					
						
							|  |  |  | 				if 0 <= r && r < 0x100000 { | 
					
						
							|  |  |  | 					r += 0x10000 | 
					
						
							|  |  |  | 					goto write | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				err = errInvalidGB18030 | 
					
						
							|  |  |  | 				break loop | 
					
						
							|  |  |  | 			default: | 
					
						
							|  |  |  | 				if d.gb18030 { | 
					
						
							|  |  |  | 					err = errInvalidGB18030 | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					err = errInvalidGBK | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				break loop | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			r, size = '\ufffd', 2 | 
					
						
							|  |  |  | 			if i := int(c0-0x81)*190 + int(c1); i < len(decode) { | 
					
						
							|  |  |  | 				r = rune(decode[i]) | 
					
						
							|  |  |  | 				if r == 0 { | 
					
						
							|  |  |  | 					r = '\ufffd' | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			if d.gb18030 { | 
					
						
							|  |  |  | 				err = errInvalidGB18030 | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				err = errInvalidGBK | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			break loop | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	write: | 
					
						
							|  |  |  | 		if nDst+utf8.RuneLen(r) > len(dst) { | 
					
						
							|  |  |  | 			err = transform.ErrShortDst | 
					
						
							|  |  |  | 			break loop | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		nDst += utf8.EncodeRune(dst[nDst:], r) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if atEOF && err == transform.ErrShortSrc { | 
					
						
							|  |  |  | 		if d.gb18030 { | 
					
						
							|  |  |  | 			err = errInvalidGB18030 | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			err = errInvalidGBK | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nDst, nSrc, err | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type gbkEncoder struct { | 
					
						
							|  |  |  | 	transform.NopResetter | 
					
						
							|  |  |  | 	gb18030 bool | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (e gbkEncoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { | 
					
						
							|  |  |  | 	r, r2, size := rune(0), rune(0), 0 | 
					
						
							|  |  |  | 	for ; nSrc < len(src); nSrc += size { | 
					
						
							|  |  |  | 		r = rune(src[nSrc]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Decode a 1-byte rune. | 
					
						
							|  |  |  | 		if r < utf8.RuneSelf { | 
					
						
							|  |  |  | 			size = 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			// Decode a multi-byte rune. | 
					
						
							|  |  |  | 			r, size = utf8.DecodeRune(src[nSrc:]) | 
					
						
							|  |  |  | 			if size == 1 { | 
					
						
							|  |  |  | 				// All valid runes of size 1 (those below utf8.RuneSelf) were | 
					
						
							|  |  |  | 				// handled above. We have invalid UTF-8 or we haven't seen the | 
					
						
							|  |  |  | 				// full character yet. | 
					
						
							|  |  |  | 				if !atEOF && !utf8.FullRune(src[nSrc:]) { | 
					
						
							|  |  |  | 					err = transform.ErrShortSrc | 
					
						
							|  |  |  | 					break | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// func init checks that the switch covers all tables. | 
					
						
							|  |  |  | 			switch { | 
					
						
							|  |  |  | 			case encode0Low <= r && r < encode0High: | 
					
						
							|  |  |  | 				if r2 = rune(encode0[r-encode0Low]); r2 != 0 { | 
					
						
							|  |  |  | 					goto write2 | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			case encode1Low <= r && r < encode1High: | 
					
						
							|  |  |  | 				// Microsoft's Code Page 936 extends GBK 1.0 to encode the euro sign U+20AC | 
					
						
							|  |  |  | 				// as 0x80. The HTML5 specification at http://encoding.spec.whatwg.org/#gbk | 
					
						
							|  |  |  | 				// says to treat "gbk" as Code Page 936. | 
					
						
							|  |  |  | 				if r == '€' { | 
					
						
							|  |  |  | 					r = 0x80 | 
					
						
							|  |  |  | 					goto write1 | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				if r2 = rune(encode1[r-encode1Low]); r2 != 0 { | 
					
						
							|  |  |  | 					goto write2 | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			case encode2Low <= r && r < encode2High: | 
					
						
							|  |  |  | 				if r2 = rune(encode2[r-encode2Low]); r2 != 0 { | 
					
						
							|  |  |  | 					goto write2 | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			case encode3Low <= r && r < encode3High: | 
					
						
							|  |  |  | 				if r2 = rune(encode3[r-encode3Low]); r2 != 0 { | 
					
						
							|  |  |  | 					goto write2 | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			case encode4Low <= r && r < encode4High: | 
					
						
							|  |  |  | 				if r2 = rune(encode4[r-encode4Low]); r2 != 0 { | 
					
						
							|  |  |  | 					goto write2 | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if e.gb18030 { | 
					
						
							|  |  |  | 				if r < 0x10000 { | 
					
						
							|  |  |  | 					i, j := 0, len(gb18030) | 
					
						
							|  |  |  | 					for i < j { | 
					
						
							|  |  |  | 						h := i + (j-i)/2 | 
					
						
							|  |  |  | 						if r >= rune(gb18030[h][1]) { | 
					
						
							|  |  |  | 							i = h + 1 | 
					
						
							|  |  |  | 						} else { | 
					
						
							|  |  |  | 							j = h | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					dec := &gb18030[i-1] | 
					
						
							|  |  |  | 					r += rune(dec[0]) - rune(dec[1]) | 
					
						
							|  |  |  | 					goto write4 | 
					
						
							|  |  |  | 				} else if r < 0x110000 { | 
					
						
							|  |  |  | 					r += 189000 - 0x10000 | 
					
						
							|  |  |  | 					goto write4 | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-02-11 16:16:52 +02:00
										 |  |  | 			err = internal.ErrASCIIReplacement | 
					
						
							|  |  |  | 			break | 
					
						
							| 
									
										
										
										
											2015-05-14 12:29:41 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	write1: | 
					
						
							|  |  |  | 		if nDst >= len(dst) { | 
					
						
							|  |  |  | 			err = transform.ErrShortDst | 
					
						
							|  |  |  | 			break | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		dst[nDst] = uint8(r) | 
					
						
							|  |  |  | 		nDst++ | 
					
						
							|  |  |  | 		continue | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	write2: | 
					
						
							|  |  |  | 		if nDst+2 > len(dst) { | 
					
						
							|  |  |  | 			err = transform.ErrShortDst | 
					
						
							|  |  |  | 			break | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		dst[nDst+0] = uint8(r2 >> 8) | 
					
						
							|  |  |  | 		dst[nDst+1] = uint8(r2) | 
					
						
							|  |  |  | 		nDst += 2 | 
					
						
							|  |  |  | 		continue | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	write4: | 
					
						
							|  |  |  | 		if nDst+4 > len(dst) { | 
					
						
							|  |  |  | 			err = transform.ErrShortDst | 
					
						
							|  |  |  | 			break | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		dst[nDst+3] = uint8(r%10 + 0x30) | 
					
						
							|  |  |  | 		r /= 10 | 
					
						
							|  |  |  | 		dst[nDst+2] = uint8(r%126 + 0x81) | 
					
						
							|  |  |  | 		r /= 126 | 
					
						
							|  |  |  | 		dst[nDst+1] = uint8(r%10 + 0x30) | 
					
						
							|  |  |  | 		r /= 10 | 
					
						
							|  |  |  | 		dst[nDst+0] = uint8(r + 0x81) | 
					
						
							|  |  |  | 		nDst += 4 | 
					
						
							|  |  |  | 		continue | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nDst, nSrc, err | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func init() { | 
					
						
							|  |  |  | 	// Check that the hard-coded encode switch covers all tables. | 
					
						
							|  |  |  | 	if numEncodeTables != 5 { | 
					
						
							|  |  |  | 		panic("bad numEncodeTables") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |