mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-31 21:28:11 +09:00 
			
		
		
		
	Convert files to utf-8 for indexing (#7814)
* Convert files to utf-8 for indexing * Move utf8 functions to modules/base * Bump repoIndexerLatestVersion to 3 * Add tests for base/encoding.go * Changes to pass gosimple * Move UTF8 funcs into new modules/charset package
This commit is contained in:
		| @@ -20,6 +20,7 @@ import ( | |||||||
| 	"code.gitea.io/gitea/models" | 	"code.gitea.io/gitea/models" | ||||||
| 	"code.gitea.io/gitea/models/migrations" | 	"code.gitea.io/gitea/models/migrations" | ||||||
| 	"code.gitea.io/gitea/modules/base" | 	"code.gitea.io/gitea/modules/base" | ||||||
|  | 	"code.gitea.io/gitea/modules/charset" | ||||||
| 	"code.gitea.io/gitea/modules/setting" | 	"code.gitea.io/gitea/modules/setting" | ||||||
|  |  | ||||||
| 	"github.com/go-xorm/xorm" | 	"github.com/go-xorm/xorm" | ||||||
| @@ -106,7 +107,7 @@ func readSQLFromFile(version string) (string, error) { | |||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return "", err | 		return "", err | ||||||
| 	} | 	} | ||||||
| 	return string(base.RemoveBOMIfPresent(bytes)), nil | 	return string(charset.RemoveBOMIfPresent(bytes)), nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func restoreOldDB(t *testing.T, version string) bool { | func restoreOldDB(t *testing.T, version string) bool { | ||||||
|   | |||||||
| @@ -19,7 +19,7 @@ import ( | |||||||
| 	"strconv" | 	"strconv" | ||||||
| 	"strings" | 	"strings" | ||||||
|  |  | ||||||
| 	"code.gitea.io/gitea/modules/base" | 	"code.gitea.io/gitea/modules/charset" | ||||||
| 	"code.gitea.io/gitea/modules/git" | 	"code.gitea.io/gitea/modules/git" | ||||||
| 	"code.gitea.io/gitea/modules/highlight" | 	"code.gitea.io/gitea/modules/highlight" | ||||||
| 	"code.gitea.io/gitea/modules/log" | 	"code.gitea.io/gitea/modules/log" | ||||||
| @@ -27,7 +27,7 @@ import ( | |||||||
| 	"code.gitea.io/gitea/modules/setting" | 	"code.gitea.io/gitea/modules/setting" | ||||||
| 	"github.com/Unknwon/com" | 	"github.com/Unknwon/com" | ||||||
| 	"github.com/sergi/go-diff/diffmatchpatch" | 	"github.com/sergi/go-diff/diffmatchpatch" | ||||||
| 	"golang.org/x/net/html/charset" | 	stdcharset "golang.org/x/net/html/charset" | ||||||
| 	"golang.org/x/text/transform" | 	"golang.org/x/text/transform" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -641,9 +641,9 @@ func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*D | |||||||
| 				buf.WriteString("\n") | 				buf.WriteString("\n") | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		charsetLabel, err := base.DetectEncoding(buf.Bytes()) | 		charsetLabel, err := charset.DetectEncoding(buf.Bytes()) | ||||||
| 		if charsetLabel != "UTF-8" && err == nil { | 		if charsetLabel != "UTF-8" && err == nil { | ||||||
| 			encoding, _ := charset.Lookup(charsetLabel) | 			encoding, _ := stdcharset.Lookup(charsetLabel) | ||||||
| 			if encoding != nil { | 			if encoding != nil { | ||||||
| 				d := encoding.NewDecoder() | 				d := encoding.NewDecoder() | ||||||
| 				for _, sec := range f.Sections { | 				for _, sec := range f.Sections { | ||||||
|   | |||||||
| @@ -10,6 +10,7 @@ import ( | |||||||
| 	"strings" | 	"strings" | ||||||
|  |  | ||||||
| 	"code.gitea.io/gitea/modules/base" | 	"code.gitea.io/gitea/modules/base" | ||||||
|  | 	"code.gitea.io/gitea/modules/charset" | ||||||
| 	"code.gitea.io/gitea/modules/git" | 	"code.gitea.io/gitea/modules/git" | ||||||
| 	"code.gitea.io/gitea/modules/indexer" | 	"code.gitea.io/gitea/modules/indexer" | ||||||
| 	"code.gitea.io/gitea/modules/log" | 	"code.gitea.io/gitea/modules/log" | ||||||
| @@ -207,6 +208,7 @@ func addUpdate(update fileUpdate, repo *Repository, batch rupture.FlushingBatch) | |||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} else if !base.IsTextFile(fileContents) { | 	} else if !base.IsTextFile(fileContents) { | ||||||
|  | 		// FIXME: UTF-16 files will probably fail here | ||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
| 	indexerUpdate := indexer.RepoIndexerUpdate{ | 	indexerUpdate := indexer.RepoIndexerUpdate{ | ||||||
| @@ -214,7 +216,7 @@ func addUpdate(update fileUpdate, repo *Repository, batch rupture.FlushingBatch) | |||||||
| 		Op:       indexer.RepoIndexerOpUpdate, | 		Op:       indexer.RepoIndexerOpUpdate, | ||||||
| 		Data: &indexer.RepoIndexerData{ | 		Data: &indexer.RepoIndexerData{ | ||||||
| 			RepoID:  repo.ID, | 			RepoID:  repo.ID, | ||||||
| 			Content: string(fileContents), | 			Content: string(charset.ToUTF8DropErrors(fileContents)), | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
| 	return indexerUpdate.AddToFlushingBatch(batch) | 	return indexerUpdate.AddToFlushingBatch(batch) | ||||||
|   | |||||||
| @@ -5,7 +5,6 @@ | |||||||
| package base | package base | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"bytes" |  | ||||||
| 	"crypto/md5" | 	"crypto/md5" | ||||||
| 	"crypto/rand" | 	"crypto/rand" | ||||||
| 	"crypto/sha1" | 	"crypto/sha1" | ||||||
| @@ -26,7 +25,6 @@ import ( | |||||||
| 	"strings" | 	"strings" | ||||||
| 	"time" | 	"time" | ||||||
| 	"unicode" | 	"unicode" | ||||||
| 	"unicode/utf8" |  | ||||||
|  |  | ||||||
| 	"code.gitea.io/gitea/modules/git" | 	"code.gitea.io/gitea/modules/git" | ||||||
| 	"code.gitea.io/gitea/modules/log" | 	"code.gitea.io/gitea/modules/log" | ||||||
| @@ -35,12 +33,8 @@ import ( | |||||||
|  |  | ||||||
| 	"github.com/Unknwon/com" | 	"github.com/Unknwon/com" | ||||||
| 	"github.com/Unknwon/i18n" | 	"github.com/Unknwon/i18n" | ||||||
| 	"github.com/gogits/chardet" |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // UTF8BOM is the utf-8 byte-order marker |  | ||||||
| var UTF8BOM = []byte{'\xef', '\xbb', '\xbf'} |  | ||||||
|  |  | ||||||
| // EncodeMD5 encodes string to md5 hex value. | // EncodeMD5 encodes string to md5 hex value. | ||||||
| func EncodeMD5(str string) string { | func EncodeMD5(str string) string { | ||||||
| 	m := md5.New() | 	m := md5.New() | ||||||
| @@ -68,49 +62,6 @@ func ShortSha(sha1 string) string { | |||||||
| 	return TruncateString(sha1, 10) | 	return TruncateString(sha1, 10) | ||||||
| } | } | ||||||
|  |  | ||||||
| // DetectEncoding detect the encoding of content |  | ||||||
| func DetectEncoding(content []byte) (string, error) { |  | ||||||
| 	if utf8.Valid(content) { |  | ||||||
| 		log.Debug("Detected encoding: utf-8 (fast)") |  | ||||||
| 		return "UTF-8", nil |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	textDetector := chardet.NewTextDetector() |  | ||||||
| 	var detectContent []byte |  | ||||||
| 	if len(content) < 1024 { |  | ||||||
| 		// Check if original content is valid |  | ||||||
| 		if _, err := textDetector.DetectBest(content); err != nil { |  | ||||||
| 			return "", err |  | ||||||
| 		} |  | ||||||
| 		times := 1024 / len(content) |  | ||||||
| 		detectContent = make([]byte, 0, times*len(content)) |  | ||||||
| 		for i := 0; i < times; i++ { |  | ||||||
| 			detectContent = append(detectContent, content...) |  | ||||||
| 		} |  | ||||||
| 	} else { |  | ||||||
| 		detectContent = content |  | ||||||
| 	} |  | ||||||
| 	result, err := textDetector.DetectBest(detectContent) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return "", err |  | ||||||
| 	} |  | ||||||
| 	if result.Charset != "UTF-8" && len(setting.Repository.AnsiCharset) > 0 { |  | ||||||
| 		log.Debug("Using default AnsiCharset: %s", setting.Repository.AnsiCharset) |  | ||||||
| 		return setting.Repository.AnsiCharset, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	log.Debug("Detected encoding: %s", result.Charset) |  | ||||||
| 	return result.Charset, err |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // RemoveBOMIfPresent removes a UTF-8 BOM from a []byte |  | ||||||
| func RemoveBOMIfPresent(content []byte) []byte { |  | ||||||
| 	if len(content) > 2 && bytes.Equal(content[0:3], UTF8BOM) { |  | ||||||
| 		return content[3:] |  | ||||||
| 	} |  | ||||||
| 	return content |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // BasicAuthDecode decode basic auth string | // BasicAuthDecode decode basic auth string | ||||||
| func BasicAuthDecode(encoded string) (string, string, error) { | func BasicAuthDecode(encoded string) (string, string, error) { | ||||||
| 	s, err := base64.StdEncoding.DecodeString(encoded) | 	s, err := base64.StdEncoding.DecodeString(encoded) | ||||||
|   | |||||||
| @@ -64,42 +64,6 @@ func TestShortSha(t *testing.T) { | |||||||
| 	assert.Equal(t, "veryverylo", ShortSha("veryverylong")) | 	assert.Equal(t, "veryverylo", ShortSha("veryverylong")) | ||||||
| } | } | ||||||
|  |  | ||||||
| func TestDetectEncoding(t *testing.T) { |  | ||||||
| 	testSuccess := func(b []byte, expected string) { |  | ||||||
| 		encoding, err := DetectEncoding(b) |  | ||||||
| 		assert.NoError(t, err) |  | ||||||
| 		assert.Equal(t, expected, encoding) |  | ||||||
| 	} |  | ||||||
| 	// utf-8 |  | ||||||
| 	b := []byte("just some ascii") |  | ||||||
| 	testSuccess(b, "UTF-8") |  | ||||||
|  |  | ||||||
| 	// utf-8-sig: "hey" (with BOM) |  | ||||||
| 	b = []byte{0xef, 0xbb, 0xbf, 0x68, 0x65, 0x79} |  | ||||||
| 	testSuccess(b, "UTF-8") |  | ||||||
|  |  | ||||||
| 	// utf-16: "hey<accented G>" |  | ||||||
| 	b = []byte{0xff, 0xfe, 0x68, 0x00, 0x65, 0x00, 0x79, 0x00, 0xf4, 0x01} |  | ||||||
| 	testSuccess(b, "UTF-16LE") |  | ||||||
|  |  | ||||||
| 	// iso-8859-1: d<accented e>cor<newline> |  | ||||||
| 	b = []byte{0x44, 0xe9, 0x63, 0x6f, 0x72, 0x0a} |  | ||||||
| 	encoding, err := DetectEncoding(b) |  | ||||||
| 	assert.NoError(t, err) |  | ||||||
| 	// due to a race condition in `chardet` library, it could either detect |  | ||||||
| 	// "ISO-8859-1" or "IS0-8859-2" here. Technically either is correct, so |  | ||||||
| 	// we accept either. |  | ||||||
| 	assert.Contains(t, encoding, "ISO-8859") |  | ||||||
|  |  | ||||||
| 	setting.Repository.AnsiCharset = "placeholder" |  | ||||||
| 	testSuccess(b, "placeholder") |  | ||||||
|  |  | ||||||
| 	// invalid bytes |  | ||||||
| 	b = []byte{0xfa} |  | ||||||
| 	_, err = DetectEncoding(b) |  | ||||||
| 	assert.Error(t, err) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func TestBasicAuthDecode(t *testing.T) { | func TestBasicAuthDecode(t *testing.T) { | ||||||
| 	_, _, err := BasicAuthDecode("?") | 	_, _, err := BasicAuthDecode("?") | ||||||
| 	assert.Equal(t, "illegal base64 data at input byte 0", err.Error()) | 	assert.Equal(t, "illegal base64 data at input byte 0", err.Error()) | ||||||
|   | |||||||
							
								
								
									
										152
									
								
								modules/charset/charset.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										152
									
								
								modules/charset/charset.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,152 @@ | |||||||
|  | // Copyright 2014 The Gogs Authors. All rights reserved. | ||||||
|  | // Use of this source code is governed by a MIT-style | ||||||
|  | // license that can be found in the LICENSE file. | ||||||
|  |  | ||||||
|  | package charset | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 	"fmt" | ||||||
|  | 	"unicode/utf8" | ||||||
|  |  | ||||||
|  | 	"code.gitea.io/gitea/modules/log" | ||||||
|  | 	"code.gitea.io/gitea/modules/setting" | ||||||
|  |  | ||||||
|  | 	"github.com/gogits/chardet" | ||||||
|  | 	"golang.org/x/net/html/charset" | ||||||
|  | 	"golang.org/x/text/transform" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // UTF8BOM is the utf-8 byte-order marker | ||||||
|  | var UTF8BOM = []byte{'\xef', '\xbb', '\xbf'} | ||||||
|  |  | ||||||
|  | // ToUTF8WithErr converts content to UTF8 encoding | ||||||
|  | func ToUTF8WithErr(content []byte) (string, error) { | ||||||
|  | 	charsetLabel, err := DetectEncoding(content) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return "", err | ||||||
|  | 	} else if charsetLabel == "UTF-8" { | ||||||
|  | 		return string(RemoveBOMIfPresent(content)), nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	encoding, _ := charset.Lookup(charsetLabel) | ||||||
|  | 	if encoding == nil { | ||||||
|  | 		return string(content), fmt.Errorf("Unknown encoding: %s", charsetLabel) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// If there is an error, we concatenate the nicely decoded part and the | ||||||
|  | 	// original left over. This way we won't lose data. | ||||||
|  | 	result, n, err := transform.Bytes(encoding.NewDecoder(), content) | ||||||
|  | 	if err != nil { | ||||||
|  | 		result = append(result, content[n:]...) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	result = RemoveBOMIfPresent(result) | ||||||
|  |  | ||||||
|  | 	return string(result), err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ToUTF8WithFallback detects the encoding of content and coverts to UTF-8 if possible | ||||||
|  | func ToUTF8WithFallback(content []byte) []byte { | ||||||
|  | 	charsetLabel, err := DetectEncoding(content) | ||||||
|  | 	if err != nil || charsetLabel == "UTF-8" { | ||||||
|  | 		return RemoveBOMIfPresent(content) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	encoding, _ := charset.Lookup(charsetLabel) | ||||||
|  | 	if encoding == nil { | ||||||
|  | 		return content | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// If there is an error, we concatenate the nicely decoded part and the | ||||||
|  | 	// original left over. This way we won't lose data. | ||||||
|  | 	result, n, err := transform.Bytes(encoding.NewDecoder(), content) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return append(result, content[n:]...) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return RemoveBOMIfPresent(result) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ToUTF8 converts content to UTF8 encoding and ignore error | ||||||
|  | func ToUTF8(content string) string { | ||||||
|  | 	res, _ := ToUTF8WithErr([]byte(content)) | ||||||
|  | 	return res | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ToUTF8DropErrors makes sure the return string is valid utf-8; attempts conversion if possible | ||||||
|  | func ToUTF8DropErrors(content []byte) []byte { | ||||||
|  | 	charsetLabel, err := DetectEncoding(content) | ||||||
|  | 	if err != nil || charsetLabel == "UTF-8" { | ||||||
|  | 		return RemoveBOMIfPresent(content) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	encoding, _ := charset.Lookup(charsetLabel) | ||||||
|  | 	if encoding == nil { | ||||||
|  | 		return content | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// We ignore any non-decodable parts from the file. | ||||||
|  | 	// Some parts might be lost | ||||||
|  | 	var decoded []byte | ||||||
|  | 	decoder := encoding.NewDecoder() | ||||||
|  | 	idx := 0 | ||||||
|  | 	for { | ||||||
|  | 		result, n, err := transform.Bytes(decoder, content[idx:]) | ||||||
|  | 		decoded = append(decoded, result...) | ||||||
|  | 		if err == nil { | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 		decoded = append(decoded, ' ') | ||||||
|  | 		idx = idx + n + 1 | ||||||
|  | 		if idx >= len(content) { | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return RemoveBOMIfPresent(decoded) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // RemoveBOMIfPresent removes a UTF-8 BOM from a []byte | ||||||
|  | func RemoveBOMIfPresent(content []byte) []byte { | ||||||
|  | 	if len(content) > 2 && bytes.Equal(content[0:3], UTF8BOM) { | ||||||
|  | 		return content[3:] | ||||||
|  | 	} | ||||||
|  | 	return content | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // DetectEncoding detect the encoding of content | ||||||
|  | func DetectEncoding(content []byte) (string, error) { | ||||||
|  | 	if utf8.Valid(content) { | ||||||
|  | 		log.Debug("Detected encoding: utf-8 (fast)") | ||||||
|  | 		return "UTF-8", nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	textDetector := chardet.NewTextDetector() | ||||||
|  | 	var detectContent []byte | ||||||
|  | 	if len(content) < 1024 { | ||||||
|  | 		// Check if original content is valid | ||||||
|  | 		if _, err := textDetector.DetectBest(content); err != nil { | ||||||
|  | 			return "", err | ||||||
|  | 		} | ||||||
|  | 		times := 1024 / len(content) | ||||||
|  | 		detectContent = make([]byte, 0, times*len(content)) | ||||||
|  | 		for i := 0; i < times; i++ { | ||||||
|  | 			detectContent = append(detectContent, content...) | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		detectContent = content | ||||||
|  | 	} | ||||||
|  | 	result, err := textDetector.DetectBest(detectContent) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return "", err | ||||||
|  | 	} | ||||||
|  | 	// FIXME: to properly decouple this function the fallback ANSI charset should be passed as an argument | ||||||
|  | 	if result.Charset != "UTF-8" && len(setting.Repository.AnsiCharset) > 0 { | ||||||
|  | 		log.Debug("Using default AnsiCharset: %s", setting.Repository.AnsiCharset) | ||||||
|  | 		return setting.Repository.AnsiCharset, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	log.Debug("Detected encoding: %s", result.Charset) | ||||||
|  | 	return result.Charset, err | ||||||
|  | } | ||||||
							
								
								
									
										191
									
								
								modules/charset/charset_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										191
									
								
								modules/charset/charset_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,191 @@ | |||||||
|  | // Copyright 2019 The Gitea Authors. All rights reserved. | ||||||
|  | // Use of this source code is governed by a MIT-style | ||||||
|  | // license that can be found in the LICENSE file. | ||||||
|  |  | ||||||
|  | package charset | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"testing" | ||||||
|  |  | ||||||
|  | 	"code.gitea.io/gitea/modules/setting" | ||||||
|  |  | ||||||
|  | 	"github.com/stretchr/testify/assert" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func TestRemoveBOMIfPresent(t *testing.T) { | ||||||
|  | 	res := RemoveBOMIfPresent([]byte{0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba}) | ||||||
|  | 	assert.Equal(t, []byte{0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba}, res) | ||||||
|  |  | ||||||
|  | 	res = RemoveBOMIfPresent([]byte{0xef, 0xbb, 0xbf, 0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba}) | ||||||
|  | 	assert.Equal(t, []byte{0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba}, res) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestToUTF8WithErr(t *testing.T) { | ||||||
|  | 	var res string | ||||||
|  | 	var err error | ||||||
|  |  | ||||||
|  | 	res, err = ToUTF8WithErr([]byte{0x41, 0x42, 0x43}) | ||||||
|  | 	assert.Equal(t, "ABC", res) | ||||||
|  | 	assert.NoError(t, err) | ||||||
|  |  | ||||||
|  | 	res, err = ToUTF8WithErr([]byte{0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba}) | ||||||
|  | 	assert.Equal(t, "áéíóú", res) | ||||||
|  | 	assert.NoError(t, err) | ||||||
|  |  | ||||||
|  | 	res, err = ToUTF8WithErr([]byte{0xef, 0xbb, 0xbf, 0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba}) | ||||||
|  | 	assert.Equal(t, "áéíóú", res) | ||||||
|  | 	assert.NoError(t, err) | ||||||
|  |  | ||||||
|  | 	// This test FAILS | ||||||
|  | 	res, err = ToUTF8WithErr([]byte{0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73, 0xED, 0x20, 0x63, 0xF3, 0x6D, 0x6F, 0x20, 0xF1, 0x6F, 0x73}) | ||||||
|  | 	assert.Equal(t, "Hola, así cómo ños", res) | ||||||
|  | 	assert.NoError(t, err) | ||||||
|  |  | ||||||
|  | 	res, err = ToUTF8WithErr([]byte{0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73, 0xED, 0x20, 0x63, 0xF3, 0x6D, 0x6F, 0x20, 0x07, 0xA4, 0x6F, 0x73}) | ||||||
|  | 	// Do not fail for differences in invalid cases, as the library might change the conversion criteria for those | ||||||
|  | 	assert.Regexp(t, "^Hola, así cómo", res) | ||||||
|  | 	assert.NoError(t, err) | ||||||
|  |  | ||||||
|  | 	res, err = ToUTF8WithErr([]byte{0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73, 0xED, 0x20, 0x63, 0xF3, 0x6D, 0x6F, 0x20, 0x81, 0xA4, 0x6F, 0x73}) | ||||||
|  | 	// Do not fail for differences in invalid cases, as the library might change the conversion criteria for those | ||||||
|  | 	assert.Regexp(t, "^Hola, así cómo", res) | ||||||
|  | 	assert.NoError(t, err) | ||||||
|  |  | ||||||
|  | 	// Japanese (Shift-JIS) | ||||||
|  | 	res, err = ToUTF8WithErr([]byte{0x93, 0xFA, 0x91, 0xAE, 0x94, 0xE9, 0x82, 0xBC, 0x82, 0xB5, 0x82, 0xBF, 0x82, 0xE3, 0x81, 0x42}) | ||||||
|  | 	assert.Equal(t, "日属秘ぞしちゅ。", res) | ||||||
|  | 	assert.NoError(t, err) | ||||||
|  |  | ||||||
|  | 	res, err = ToUTF8WithErr([]byte{0x00, 0x00, 0x00, 0x00}) | ||||||
|  | 	assert.Equal(t, "\x00\x00\x00\x00", res) | ||||||
|  | 	assert.NoError(t, err) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestToUTF8WithFallback(t *testing.T) { | ||||||
|  | 	res := ToUTF8WithFallback([]byte{0x41, 0x42, 0x43}) | ||||||
|  | 	assert.Equal(t, []byte("ABC"), res) | ||||||
|  |  | ||||||
|  | 	res = ToUTF8WithFallback([]byte{0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba}) | ||||||
|  | 	assert.Equal(t, []byte("áéíóú"), res) | ||||||
|  |  | ||||||
|  | 	res = ToUTF8WithFallback([]byte{0xef, 0xbb, 0xbf, 0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba}) | ||||||
|  | 	assert.Equal(t, []byte("áéíóú"), res) | ||||||
|  |  | ||||||
|  | 	res = ToUTF8WithFallback([]byte{0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73, 0xED, 0x20, 0x63, 0xF3, 0x6D, 0x6F, 0x20, 0xF1, 0x6F, 0x73}) | ||||||
|  | 	assert.Equal(t, []byte("Hola, así cómo ños"), res) | ||||||
|  |  | ||||||
|  | 	minmatch := []byte("Hola, así cómo ") | ||||||
|  |  | ||||||
|  | 	res = ToUTF8WithFallback([]byte{0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73, 0xED, 0x20, 0x63, 0xF3, 0x6D, 0x6F, 0x20, 0x07, 0xA4, 0x6F, 0x73}) | ||||||
|  | 	// Do not fail for differences in invalid cases, as the library might change the conversion criteria for those | ||||||
|  | 	assert.Equal(t, minmatch, res[0:len(minmatch)]) | ||||||
|  |  | ||||||
|  | 	res = ToUTF8WithFallback([]byte{0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73, 0xED, 0x20, 0x63, 0xF3, 0x6D, 0x6F, 0x20, 0x81, 0xA4, 0x6F, 0x73}) | ||||||
|  | 	// Do not fail for differences in invalid cases, as the library might change the conversion criteria for those | ||||||
|  | 	assert.Equal(t, minmatch, res[0:len(minmatch)]) | ||||||
|  |  | ||||||
|  | 	// Japanese (Shift-JIS) | ||||||
|  | 	res = ToUTF8WithFallback([]byte{0x93, 0xFA, 0x91, 0xAE, 0x94, 0xE9, 0x82, 0xBC, 0x82, 0xB5, 0x82, 0xBF, 0x82, 0xE3, 0x81, 0x42}) | ||||||
|  | 	assert.Equal(t, []byte("日属秘ぞしちゅ。"), res) | ||||||
|  |  | ||||||
|  | 	res = ToUTF8WithFallback([]byte{0x00, 0x00, 0x00, 0x00}) | ||||||
|  | 	assert.Equal(t, []byte{0x00, 0x00, 0x00, 0x00}, res) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestToUTF8(t *testing.T) { | ||||||
|  | 	res := ToUTF8("ABC") | ||||||
|  | 	assert.Equal(t, "ABC", res) | ||||||
|  |  | ||||||
|  | 	res = ToUTF8("áéíóú") | ||||||
|  | 	assert.Equal(t, "áéíóú", res) | ||||||
|  |  | ||||||
|  | 	// With utf-8 BOM | ||||||
|  | 	res = ToUTF8("\ufeffáéíóú") | ||||||
|  | 	assert.Equal(t, "áéíóú", res) | ||||||
|  |  | ||||||
|  | 	res = ToUTF8("Hola, así cómo ños") | ||||||
|  | 	assert.Equal(t, "Hola, así cómo ños", res) | ||||||
|  |  | ||||||
|  | 	res = ToUTF8("Hola, así cómo \x07ños") | ||||||
|  | 	// Do not fail for differences in invalid cases, as the library might change the conversion criteria for those | ||||||
|  | 	assert.Regexp(t, "^Hola, así cómo", res) | ||||||
|  |  | ||||||
|  | 	// This test FAILS | ||||||
|  | 	// res = ToUTF8("Hola, así cómo \x81ños") | ||||||
|  | 	// Do not fail for differences in invalid cases, as the library might change the conversion criteria for those | ||||||
|  | 	// assert.Regexp(t, "^Hola, así cómo", res) | ||||||
|  |  | ||||||
|  | 	// Japanese (Shift-JIS) | ||||||
|  | 	res = ToUTF8("\x93\xFA\x91\xAE\x94\xE9\x82\xBC\x82\xB5\x82\xBF\x82\xE3\x81\x42") | ||||||
|  | 	assert.Equal(t, "日属秘ぞしちゅ。", res) | ||||||
|  |  | ||||||
|  | 	res = ToUTF8("\x00\x00\x00\x00") | ||||||
|  | 	assert.Equal(t, "\x00\x00\x00\x00", res) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestToUTF8DropErrors(t *testing.T) { | ||||||
|  | 	res := ToUTF8DropErrors([]byte{0x41, 0x42, 0x43}) | ||||||
|  | 	assert.Equal(t, []byte("ABC"), res) | ||||||
|  |  | ||||||
|  | 	res = ToUTF8DropErrors([]byte{0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba}) | ||||||
|  | 	assert.Equal(t, []byte("áéíóú"), res) | ||||||
|  |  | ||||||
|  | 	res = ToUTF8DropErrors([]byte{0xef, 0xbb, 0xbf, 0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba}) | ||||||
|  | 	assert.Equal(t, []byte("áéíóú"), res) | ||||||
|  |  | ||||||
|  | 	res = ToUTF8DropErrors([]byte{0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73, 0xED, 0x20, 0x63, 0xF3, 0x6D, 0x6F, 0x20, 0xF1, 0x6F, 0x73}) | ||||||
|  | 	assert.Equal(t, []byte("Hola, así cómo ños"), res) | ||||||
|  |  | ||||||
|  | 	minmatch := []byte("Hola, así cómo ") | ||||||
|  |  | ||||||
|  | 	res = ToUTF8DropErrors([]byte{0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73, 0xED, 0x20, 0x63, 0xF3, 0x6D, 0x6F, 0x20, 0x07, 0xA4, 0x6F, 0x73}) | ||||||
|  | 	// Do not fail for differences in invalid cases, as the library might change the conversion criteria for those | ||||||
|  | 	assert.Equal(t, minmatch, res[0:len(minmatch)]) | ||||||
|  |  | ||||||
|  | 	res = ToUTF8DropErrors([]byte{0x48, 0x6F, 0x6C, 0x61, 0x2C, 0x20, 0x61, 0x73, 0xED, 0x20, 0x63, 0xF3, 0x6D, 0x6F, 0x20, 0x81, 0xA4, 0x6F, 0x73}) | ||||||
|  | 	// Do not fail for differences in invalid cases, as the library might change the conversion criteria for those | ||||||
|  | 	assert.Equal(t, minmatch, res[0:len(minmatch)]) | ||||||
|  |  | ||||||
|  | 	// Japanese (Shift-JIS) | ||||||
|  | 	res = ToUTF8DropErrors([]byte{0x93, 0xFA, 0x91, 0xAE, 0x94, 0xE9, 0x82, 0xBC, 0x82, 0xB5, 0x82, 0xBF, 0x82, 0xE3, 0x81, 0x42}) | ||||||
|  | 	assert.Equal(t, []byte("日属秘ぞしちゅ。"), res) | ||||||
|  |  | ||||||
|  | 	res = ToUTF8DropErrors([]byte{0x00, 0x00, 0x00, 0x00}) | ||||||
|  | 	assert.Equal(t, []byte{0x00, 0x00, 0x00, 0x00}, res) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestDetectEncoding(t *testing.T) { | ||||||
|  | 	testSuccess := func(b []byte, expected string) { | ||||||
|  | 		encoding, err := DetectEncoding(b) | ||||||
|  | 		assert.NoError(t, err) | ||||||
|  | 		assert.Equal(t, expected, encoding) | ||||||
|  | 	} | ||||||
|  | 	// utf-8 | ||||||
|  | 	b := []byte("just some ascii") | ||||||
|  | 	testSuccess(b, "UTF-8") | ||||||
|  |  | ||||||
|  | 	// utf-8-sig: "hey" (with BOM) | ||||||
|  | 	b = []byte{0xef, 0xbb, 0xbf, 0x68, 0x65, 0x79} | ||||||
|  | 	testSuccess(b, "UTF-8") | ||||||
|  |  | ||||||
|  | 	// utf-16: "hey<accented G>" | ||||||
|  | 	b = []byte{0xff, 0xfe, 0x68, 0x00, 0x65, 0x00, 0x79, 0x00, 0xf4, 0x01} | ||||||
|  | 	testSuccess(b, "UTF-16LE") | ||||||
|  |  | ||||||
|  | 	// iso-8859-1: d<accented e>cor<newline> | ||||||
|  | 	b = []byte{0x44, 0xe9, 0x63, 0x6f, 0x72, 0x0a} | ||||||
|  | 	encoding, err := DetectEncoding(b) | ||||||
|  | 	assert.NoError(t, err) | ||||||
|  | 	// due to a race condition in `chardet` library, it could either detect | ||||||
|  | 	// "ISO-8859-1" or "IS0-8859-2" here. Technically either is correct, so | ||||||
|  | 	// we accept either. | ||||||
|  | 	assert.Contains(t, encoding, "ISO-8859") | ||||||
|  |  | ||||||
|  | 	setting.Repository.AnsiCharset = "placeholder" | ||||||
|  | 	testSuccess(b, "placeholder") | ||||||
|  |  | ||||||
|  | 	// invalid bytes | ||||||
|  | 	b = []byte{0xfa} | ||||||
|  | 	_, err = DetectEncoding(b) | ||||||
|  | 	assert.Error(t, err) | ||||||
|  | } | ||||||
| @@ -23,7 +23,7 @@ const ( | |||||||
| 	repoIndexerAnalyzer = "repoIndexerAnalyzer" | 	repoIndexerAnalyzer = "repoIndexerAnalyzer" | ||||||
| 	repoIndexerDocType  = "repoIndexerDocType" | 	repoIndexerDocType  = "repoIndexerDocType" | ||||||
|  |  | ||||||
| 	repoIndexerLatestVersion = 2 | 	repoIndexerLatestVersion = 3 | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // repoIndexer (thread-safe) index for repository contents | // repoIndexer (thread-safe) index for repository contents | ||||||
|   | |||||||
| @@ -11,17 +11,17 @@ import ( | |||||||
| 	"path" | 	"path" | ||||||
| 	"strings" | 	"strings" | ||||||
|  |  | ||||||
| 	"golang.org/x/net/html/charset" |  | ||||||
| 	"golang.org/x/text/transform" |  | ||||||
|  |  | ||||||
| 	"code.gitea.io/gitea/models" | 	"code.gitea.io/gitea/models" | ||||||
| 	"code.gitea.io/gitea/modules/base" |  | ||||||
| 	"code.gitea.io/gitea/modules/cache" | 	"code.gitea.io/gitea/modules/cache" | ||||||
|  | 	"code.gitea.io/gitea/modules/charset" | ||||||
| 	"code.gitea.io/gitea/modules/git" | 	"code.gitea.io/gitea/modules/git" | ||||||
| 	"code.gitea.io/gitea/modules/lfs" | 	"code.gitea.io/gitea/modules/lfs" | ||||||
| 	"code.gitea.io/gitea/modules/log" | 	"code.gitea.io/gitea/modules/log" | ||||||
| 	"code.gitea.io/gitea/modules/setting" | 	"code.gitea.io/gitea/modules/setting" | ||||||
| 	"code.gitea.io/gitea/modules/structs" | 	"code.gitea.io/gitea/modules/structs" | ||||||
|  |  | ||||||
|  | 	stdcharset "golang.org/x/net/html/charset" | ||||||
|  | 	"golang.org/x/text/transform" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // IdentityOptions for a person's identity like an author or committer | // IdentityOptions for a person's identity like an author or committer | ||||||
| @@ -87,15 +87,15 @@ func detectEncodingAndBOM(entry *git.TreeEntry, repo *models.Repository) (string | |||||||
|  |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	encoding, err := base.DetectEncoding(buf) | 	encoding, err := charset.DetectEncoding(buf) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		// just default to utf-8 and no bom | 		// just default to utf-8 and no bom | ||||||
| 		return "UTF-8", false | 		return "UTF-8", false | ||||||
| 	} | 	} | ||||||
| 	if encoding == "UTF-8" { | 	if encoding == "UTF-8" { | ||||||
| 		return encoding, bytes.Equal(buf[0:3], base.UTF8BOM) | 		return encoding, bytes.Equal(buf[0:3], charset.UTF8BOM) | ||||||
| 	} | 	} | ||||||
| 	charsetEncoding, _ := charset.Lookup(encoding) | 	charsetEncoding, _ := stdcharset.Lookup(encoding) | ||||||
| 	if charsetEncoding == nil { | 	if charsetEncoding == nil { | ||||||
| 		return "UTF-8", false | 		return "UTF-8", false | ||||||
| 	} | 	} | ||||||
| @@ -107,7 +107,7 @@ func detectEncodingAndBOM(entry *git.TreeEntry, repo *models.Repository) (string | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if n > 2 { | 	if n > 2 { | ||||||
| 		return encoding, bytes.Equal([]byte(result)[0:3], base.UTF8BOM) | 		return encoding, bytes.Equal([]byte(result)[0:3], charset.UTF8BOM) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return encoding, false | 	return encoding, false | ||||||
| @@ -321,10 +321,10 @@ func CreateOrUpdateRepoFile(repo *models.Repository, doer *models.User, opts *Up | |||||||
|  |  | ||||||
| 	content := opts.Content | 	content := opts.Content | ||||||
| 	if bom { | 	if bom { | ||||||
| 		content = string(base.UTF8BOM) + content | 		content = string(charset.UTF8BOM) + content | ||||||
| 	} | 	} | ||||||
| 	if encoding != "UTF-8" { | 	if encoding != "UTF-8" { | ||||||
| 		charsetEncoding, _ := charset.Lookup(encoding) | 		charsetEncoding, _ := stdcharset.Lookup(encoding) | ||||||
| 		if charsetEncoding != nil { | 		if charsetEncoding != nil { | ||||||
| 			result, _, err := transform.String(charsetEncoding.NewEncoder(), content) | 			result, _, err := transform.String(charsetEncoding.NewEncoder(), content) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
|   | |||||||
| @@ -28,8 +28,6 @@ import ( | |||||||
| 	"code.gitea.io/gitea/modules/markup" | 	"code.gitea.io/gitea/modules/markup" | ||||||
| 	"code.gitea.io/gitea/modules/setting" | 	"code.gitea.io/gitea/modules/setting" | ||||||
|  |  | ||||||
| 	"golang.org/x/net/html/charset" |  | ||||||
| 	"golang.org/x/text/transform" |  | ||||||
| 	"gopkg.in/editorconfig/editorconfig-core-go.v1" | 	"gopkg.in/editorconfig/editorconfig-core-go.v1" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -274,60 +272,6 @@ func Sha1(str string) string { | |||||||
| 	return base.EncodeSha1(str) | 	return base.EncodeSha1(str) | ||||||
| } | } | ||||||
|  |  | ||||||
| // ToUTF8WithErr converts content to UTF8 encoding |  | ||||||
| func ToUTF8WithErr(content []byte) (string, error) { |  | ||||||
| 	charsetLabel, err := base.DetectEncoding(content) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return "", err |  | ||||||
| 	} else if charsetLabel == "UTF-8" { |  | ||||||
| 		return string(base.RemoveBOMIfPresent(content)), nil |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	encoding, _ := charset.Lookup(charsetLabel) |  | ||||||
| 	if encoding == nil { |  | ||||||
| 		return string(content), fmt.Errorf("Unknown encoding: %s", charsetLabel) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// If there is an error, we concatenate the nicely decoded part and the |  | ||||||
| 	// original left over. This way we won't lose data. |  | ||||||
| 	result, n, err := transform.Bytes(encoding.NewDecoder(), content) |  | ||||||
| 	if err != nil { |  | ||||||
| 		result = append(result, content[n:]...) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	result = base.RemoveBOMIfPresent(result) |  | ||||||
|  |  | ||||||
| 	return string(result), err |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // ToUTF8WithFallback detects the encoding of content and coverts to UTF-8 if possible |  | ||||||
| func ToUTF8WithFallback(content []byte) []byte { |  | ||||||
| 	charsetLabel, err := base.DetectEncoding(content) |  | ||||||
| 	if err != nil || charsetLabel == "UTF-8" { |  | ||||||
| 		return base.RemoveBOMIfPresent(content) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	encoding, _ := charset.Lookup(charsetLabel) |  | ||||||
| 	if encoding == nil { |  | ||||||
| 		return content |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// If there is an error, we concatenate the nicely decoded part and the |  | ||||||
| 	// original left over. This way we won't lose data. |  | ||||||
| 	result, n, err := transform.Bytes(encoding.NewDecoder(), content) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return append(result, content[n:]...) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return base.RemoveBOMIfPresent(result) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // ToUTF8 converts content to UTF8 encoding and ignore error |  | ||||||
| func ToUTF8(content string) string { |  | ||||||
| 	res, _ := ToUTF8WithErr([]byte(content)) |  | ||||||
| 	return res |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // ReplaceLeft replaces all prefixes 'oldS' in 's' with 'newS'. | // ReplaceLeft replaces all prefixes 'oldS' in 's' with 'newS'. | ||||||
| func ReplaceLeft(s, oldS, newS string) string { | func ReplaceLeft(s, oldS, newS string) string { | ||||||
| 	oldLen, newLen, i, n := len(oldS), len(newS), 0, 0 | 	oldLen, newLen, i, n := len(oldS), len(newS), 0, 0 | ||||||
|   | |||||||
| @@ -11,11 +11,11 @@ import ( | |||||||
|  |  | ||||||
| 	"code.gitea.io/gitea/models" | 	"code.gitea.io/gitea/models" | ||||||
| 	"code.gitea.io/gitea/modules/base" | 	"code.gitea.io/gitea/modules/base" | ||||||
|  | 	"code.gitea.io/gitea/modules/charset" | ||||||
| 	"code.gitea.io/gitea/modules/context" | 	"code.gitea.io/gitea/modules/context" | ||||||
| 	"code.gitea.io/gitea/modules/git" | 	"code.gitea.io/gitea/modules/git" | ||||||
| 	"code.gitea.io/gitea/modules/log" | 	"code.gitea.io/gitea/modules/log" | ||||||
| 	"code.gitea.io/gitea/modules/setting" | 	"code.gitea.io/gitea/modules/setting" | ||||||
| 	"code.gitea.io/gitea/modules/templates" |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| const ( | const ( | ||||||
| @@ -251,7 +251,7 @@ func Diff(ctx *context.Context) { | |||||||
| 	note := &git.Note{} | 	note := &git.Note{} | ||||||
| 	err = git.GetNote(ctx.Repo.GitRepo, commitID, note) | 	err = git.GetNote(ctx.Repo.GitRepo, commitID, note) | ||||||
| 	if err == nil { | 	if err == nil { | ||||||
| 		ctx.Data["Note"] = string(templates.ToUTF8WithFallback(note.Message)) | 		ctx.Data["Note"] = string(charset.ToUTF8WithFallback(note.Message)) | ||||||
| 		ctx.Data["NoteCommit"] = note.Commit | 		ctx.Data["NoteCommit"] = note.Commit | ||||||
| 		ctx.Data["NoteAuthor"] = models.ValidateCommitWithEmail(note.Commit) | 		ctx.Data["NoteAuthor"] = models.ValidateCommitWithEmail(note.Commit) | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -14,12 +14,12 @@ import ( | |||||||
| 	"code.gitea.io/gitea/models" | 	"code.gitea.io/gitea/models" | ||||||
| 	"code.gitea.io/gitea/modules/auth" | 	"code.gitea.io/gitea/modules/auth" | ||||||
| 	"code.gitea.io/gitea/modules/base" | 	"code.gitea.io/gitea/modules/base" | ||||||
|  | 	"code.gitea.io/gitea/modules/charset" | ||||||
| 	"code.gitea.io/gitea/modules/context" | 	"code.gitea.io/gitea/modules/context" | ||||||
| 	"code.gitea.io/gitea/modules/git" | 	"code.gitea.io/gitea/modules/git" | ||||||
| 	"code.gitea.io/gitea/modules/log" | 	"code.gitea.io/gitea/modules/log" | ||||||
| 	"code.gitea.io/gitea/modules/repofiles" | 	"code.gitea.io/gitea/modules/repofiles" | ||||||
| 	"code.gitea.io/gitea/modules/setting" | 	"code.gitea.io/gitea/modules/setting" | ||||||
| 	"code.gitea.io/gitea/modules/templates" |  | ||||||
| 	"code.gitea.io/gitea/modules/upload" | 	"code.gitea.io/gitea/modules/upload" | ||||||
| 	"code.gitea.io/gitea/modules/util" | 	"code.gitea.io/gitea/modules/util" | ||||||
| ) | ) | ||||||
| @@ -118,7 +118,7 @@ func editFile(ctx *context.Context, isNewFile bool) { | |||||||
|  |  | ||||||
| 		d, _ := ioutil.ReadAll(dataRc) | 		d, _ := ioutil.ReadAll(dataRc) | ||||||
| 		buf = append(buf, d...) | 		buf = append(buf, d...) | ||||||
| 		if content, err := templates.ToUTF8WithErr(buf); err != nil { | 		if content, err := charset.ToUTF8WithErr(buf); err != nil { | ||||||
| 			log.Error("ToUTF8WithErr: %v", err) | 			log.Error("ToUTF8WithErr: %v", err) | ||||||
| 			ctx.Data["FileContent"] = string(buf) | 			ctx.Data["FileContent"] = string(buf) | ||||||
| 		} else { | 		} else { | ||||||
|   | |||||||
| @@ -16,6 +16,7 @@ import ( | |||||||
|  |  | ||||||
| 	"code.gitea.io/gitea/models" | 	"code.gitea.io/gitea/models" | ||||||
| 	"code.gitea.io/gitea/modules/base" | 	"code.gitea.io/gitea/modules/base" | ||||||
|  | 	"code.gitea.io/gitea/modules/charset" | ||||||
| 	"code.gitea.io/gitea/modules/context" | 	"code.gitea.io/gitea/modules/context" | ||||||
| 	"code.gitea.io/gitea/modules/git" | 	"code.gitea.io/gitea/modules/git" | ||||||
| 	"code.gitea.io/gitea/modules/highlight" | 	"code.gitea.io/gitea/modules/highlight" | ||||||
| @@ -23,7 +24,6 @@ import ( | |||||||
| 	"code.gitea.io/gitea/modules/log" | 	"code.gitea.io/gitea/modules/log" | ||||||
| 	"code.gitea.io/gitea/modules/markup" | 	"code.gitea.io/gitea/modules/markup" | ||||||
| 	"code.gitea.io/gitea/modules/setting" | 	"code.gitea.io/gitea/modules/setting" | ||||||
| 	"code.gitea.io/gitea/modules/templates" |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| const ( | const ( | ||||||
| @@ -160,7 +160,7 @@ func renderDirectory(ctx *context.Context, treeLink string) { | |||||||
| 				ctx.Data["FileSize"] = fileSize | 				ctx.Data["FileSize"] = fileSize | ||||||
| 			} else { | 			} else { | ||||||
| 				d, _ := ioutil.ReadAll(dataRc) | 				d, _ := ioutil.ReadAll(dataRc) | ||||||
| 				buf = templates.ToUTF8WithFallback(append(buf, d...)) | 				buf = charset.ToUTF8WithFallback(append(buf, d...)) | ||||||
|  |  | ||||||
| 				if markup.Type(readmeFile.Name()) != "" { | 				if markup.Type(readmeFile.Name()) != "" { | ||||||
| 					ctx.Data["IsMarkup"] = true | 					ctx.Data["IsMarkup"] = true | ||||||
| @@ -278,7 +278,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		d, _ := ioutil.ReadAll(dataRc) | 		d, _ := ioutil.ReadAll(dataRc) | ||||||
| 		buf = templates.ToUTF8WithFallback(append(buf, d...)) | 		buf = charset.ToUTF8WithFallback(append(buf, d...)) | ||||||
|  |  | ||||||
| 		readmeExist := markup.IsReadmeFile(blob.Name()) | 		readmeExist := markup.IsReadmeFile(blob.Name()) | ||||||
| 		ctx.Data["ReadmeExist"] = readmeExist | 		ctx.Data["ReadmeExist"] = readmeExist | ||||||
| @@ -293,7 +293,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st | |||||||
| 		} else { | 		} else { | ||||||
| 			// Building code view blocks with line number on server side. | 			// Building code view blocks with line number on server side. | ||||||
| 			var fileContent string | 			var fileContent string | ||||||
| 			if content, err := templates.ToUTF8WithErr(buf); err != nil { | 			if content, err := charset.ToUTF8WithErr(buf); err != nil { | ||||||
| 				log.Error("ToUTF8WithErr: %v", err) | 				log.Error("ToUTF8WithErr: %v", err) | ||||||
| 				fileContent = string(buf) | 				fileContent = string(buf) | ||||||
| 			} else { | 			} else { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user