"hash"
"hash/crc32"
"io"
+ "unicode/utf8"
)
// TODO(adg): support zip file comments
return w.CreateHeader(header)
}
+func hasValidUTF8(s string) bool {
+ n := 0
+ for _, r := range s {
+ // By default, ZIP uses CP437, which is only identical to ASCII for the printable characters.
+ if r < 0x20 || r >= 0x7f {
+ if !utf8.ValidRune(r) {
+ return false
+ }
+ n++
+ }
+ }
+ return n > 0
+}
+
// CreateHeader adds a file to the zip file using the provided FileHeader
// for the file metadata.
// It returns a Writer to which the file contents should be written.
fh.Flags |= 0x8 // we will write a data descriptor
+ if hasValidUTF8(fh.Name) || hasValidUTF8(fh.Comment) {
+ fh.Flags |= 0x800 // filename or comment have valid utf-8 string
+ }
+
fh.CreatorVersion = fh.CreatorVersion&0xff00 | zipVersion20 // preserve compatibility byte
fh.ReaderVersion = zipVersion20
}
}
+func TestWriterUTF8(t *testing.T) {
+ var utf8Tests = []struct {
+ name string
+ comment string
+ expect uint16
+ }{
+ {
+ name: "hi, hello",
+ comment: "in the world",
+ expect: 0x8,
+ },
+ {
+ name: "hi, こんにちわ",
+ comment: "in the world",
+ expect: 0x808,
+ },
+ {
+ name: "hi, hello",
+ comment: "in the 世界",
+ expect: 0x808,
+ },
+ {
+ name: "hi, こんにちわ",
+ comment: "in the 世界",
+ expect: 0x808,
+ },
+ }
+
+ // write a zip file
+ buf := new(bytes.Buffer)
+ w := NewWriter(buf)
+
+ for _, test := range utf8Tests {
+ h := &FileHeader{
+ Name: test.name,
+ Comment: test.comment,
+ Method: Deflate,
+ }
+ w, err := w.CreateHeader(h)
+ if err != nil {
+ t.Fatal(err)
+ }
+ w.Write([]byte{})
+ }
+
+ if err := w.Close(); err != nil {
+ t.Fatal(err)
+ }
+
+ // read it back
+ r, err := NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len()))
+ if err != nil {
+ t.Fatal(err)
+ }
+ for i, test := range utf8Tests {
+ got := r.File[i].Flags
+ t.Logf("name %v, comment %v", test.name, test.comment)
+ if got != test.expect {
+ t.Fatalf("Flags: got %v, want %v", got, test.expect)
+ }
+ }
+}
+
func TestWriterOffset(t *testing.T) {
largeData := make([]byte, 1<<17)
for i := range largeData {