5
5
package uploader
6
6
7
7
import (
8
+ "bytes"
8
9
"fmt"
9
10
"strings"
10
11
12
+ "golang.org/x/net/html/charset"
13
+ "golang.org/x/text/transform"
14
+
11
15
"code.gitea.io/git"
12
16
"code.gitea.io/gitea/models"
17
+ "code.gitea.io/gitea/modules/base"
13
18
"code.gitea.io/gitea/modules/lfs"
19
+ "code.gitea.io/gitea/modules/log"
14
20
"code.gitea.io/gitea/modules/setting"
15
21
)
16
22
23
+ func detectEncodingAndBOM (entry * git.TreeEntry , repo * models.Repository ) (string , bool ) {
24
+ reader , err := entry .Blob ().DataAsync ()
25
+ if err != nil {
26
+ // return default
27
+ return "UTF-8" , false
28
+ }
29
+ defer reader .Close ()
30
+ buf := make ([]byte , 1024 )
31
+ n , err := reader .Read (buf )
32
+ if err != nil {
33
+ // return default
34
+ return "UTF-8" , false
35
+ }
36
+ buf = buf [:n ]
37
+
38
+ if setting .LFS .StartServer {
39
+ meta := lfs .IsPointerFile (& buf )
40
+ if meta != nil {
41
+ meta , err = repo .GetLFSMetaObjectByOid (meta .Oid )
42
+ if err != nil && err != models .ErrLFSObjectNotExist {
43
+ // return default
44
+ return "UTF-8" , false
45
+ }
46
+ }
47
+ if meta != nil {
48
+ dataRc , err := lfs .ReadMetaObject (meta )
49
+ if err != nil {
50
+ // return default
51
+ return "UTF-8" , false
52
+ }
53
+ defer dataRc .Close ()
54
+ buf = make ([]byte , 1024 )
55
+ n , err = dataRc .Read (buf )
56
+ if err != nil {
57
+ // return default
58
+ return "UTF-8" , false
59
+ }
60
+ buf = buf [:n ]
61
+ }
62
+
63
+ }
64
+
65
+ encoding , err := base .DetectEncoding (buf )
66
+ if err != nil {
67
+ // just default to utf-8 and no bom
68
+ return "UTF-8" , false
69
+ }
70
+ if encoding == "UTF-8" {
71
+ return encoding , bytes .Equal (buf [0 :3 ], base .UTF8BOM )
72
+ }
73
+ charsetEncoding , _ := charset .Lookup (encoding )
74
+ if charsetEncoding == nil {
75
+ return "UTF-8" , false
76
+ }
77
+
78
+ result , n , err := transform .String (charsetEncoding .NewDecoder (), string (buf ))
79
+
80
+ if n > 2 {
81
+ return encoding , bytes .Equal ([]byte (result )[0 :3 ], base .UTF8BOM )
82
+ }
83
+
84
+ return encoding , false
85
+ }
86
+
17
87
// UpdateRepoFileOptions holds the repository file update options
18
88
type UpdateRepoFileOptions struct {
19
89
LastCommitID string
@@ -45,12 +115,29 @@ func UpdateRepoFile(repo *models.Repository, doer *models.User, opts *UpdateRepo
45
115
return fmt .Errorf ("UpdateRepoFile: %v" , err )
46
116
}
47
117
118
+ encoding := "UTF-8"
119
+ bom := false
120
+
48
121
if opts .IsNewFile {
49
122
for _ , file := range filesInIndex {
50
123
if file == opts .NewTreeName {
51
124
return models.ErrRepoFileAlreadyExist {FileName : opts .NewTreeName }
52
125
}
53
126
}
127
+ } else {
128
+ gitRepo , err := git .OpenRepository (t .basePath )
129
+ if err != nil {
130
+ return err
131
+ }
132
+ tree , err := gitRepo .GetTree ("HEAD" )
133
+ if err != nil {
134
+ return err
135
+ }
136
+ entry , err := tree .GetTreeEntryByPath (opts .OldTreeName )
137
+ if err != nil {
138
+ return err
139
+ }
140
+ encoding , bom = detectEncodingAndBOM (entry , repo )
54
141
}
55
142
56
143
//var stdout string
@@ -72,9 +159,28 @@ func UpdateRepoFile(repo *models.Repository, doer *models.User, opts *UpdateRepo
72
159
}
73
160
74
161
content := opts .Content
162
+ if bom {
163
+ content = string (base .UTF8BOM ) + content
164
+ }
165
+ if encoding != "UTF-8" {
166
+ charsetEncoding , _ := charset .Lookup (encoding )
167
+ if charsetEncoding != nil {
168
+ result , _ , err := transform .String (charsetEncoding .NewEncoder (), string (content ))
169
+ if err != nil {
170
+ // Look if we can't encode back in to the original we should just stick with utf-8
171
+ log .Error (4 , "Error re-encoding %s (%s) as %s - will stay as UTF-8: %v" , opts .NewTreeName , opts .OldTreeName , encoding , err )
172
+ result = content
173
+ }
174
+ content = result
175
+ } else {
176
+ log .Error (4 , "Unknown encoding: %s" , encoding )
177
+ }
178
+ }
179
+ // Reset the opts.Content with the re-encoded and BOM'd content
180
+ opts .Content = content
75
181
var lfsMetaObject * models.LFSMetaObject
76
182
77
- if filename2attribute2info [opts .NewTreeName ] != nil && filename2attribute2info [opts .NewTreeName ]["filter" ] == "lfs" {
183
+ if setting . LFS . StartServer && filename2attribute2info [opts .NewTreeName ] != nil && filename2attribute2info [opts .NewTreeName ]["filter" ] == "lfs" {
78
184
// OK so we are supposed to LFS this data!
79
185
oid , err := models .GenerateLFSOid (strings .NewReader (opts .Content ))
80
186
if err != nil {
0 commit comments