Skip to content

archive/zip: need new api to support local file name encoding #10741

Description

@chai2010

The archive/zip can't support gbk filename on chinese windows.

This is a simple test (test-gbk-zip.go):

// only for go1.4

// Go output on Chinese Win7/64bit
// go run test-gbk-zip.go
//
// File name(%s): ����/���¶���.txt
// File name(%q): "\xc0\xee\xb0\xd7/\xd4\xc2\xcf¶\xc0\xd7\xc3.txt"
// File name(%s): �Ÿ�/
// File name(%q): "\xb6Ÿ\xa6/"
//

// 7z output on Chinese Win7/64bit
//
// 7z l -r 中文-测试.zip
//
// 7-Zip [64] 9.25 alpha  Copyright (c) 1999-2011 Igor Pavlov  2011-09-16
//
// Listing archive: 中文-测试.zip
//
// --
// Path = 中文-测试.zip
// Type = zip
// Physical Size = 483
//
//    Date      Time    Attr         Size   Compressed  Name
// ------------------- ----- ------------ ------------  ------------------------
//                     .....          282          228  李白\月下独酌.txt
//                     D....            0            5  杜甫
// ------------------- ----- ------------ ------------  ------------------------
//                                    282          233  1 files, 1 folders

package main

import (
    "archive/zip"
    "fmt"
    "log"
    "os"

    "golang.org/x/text/encoding/simplifiedchinese"
)

type ZipTest struct {
    Name string
    File []ZipTestFile
}

type ZipTestFile struct {
    Name string
    Body string
}

func main() {
    makeGbkTestfile()

    r, err := zip.OpenReader(gbkZipTest.Name)
    if err != nil {
        log.Fatal(err)
    }
    defer r.Close()

    for _, f := range r.File {
        fmt.Printf("File name(%%s): %s\n", f.Name)
        fmt.Printf("File name(%%q): %q\n", f.Name)
    }
}

func makeGbkTestfile() {
    file, err := os.Create(gbkZipTest.Name)
    if err != nil {
        log.Fatal(err)
    }
    defer file.Close()

    wzip := zip.NewWriter(file)
    defer func() {
        if err := wzip.Close(); err != nil {
            log.Fatal(err)
        }
    }()

    for _, file := range gbkZipTest.File {
        localGbkName, _ := utf8ToGBK(file.Name) // 文件名转换为 GBK编码
        f, err := wzip.Create(localGbkName)
        if err != nil {
            log.Fatal(err)
        }
        _, err = f.Write([]byte(file.Body))
        if err != nil {
            log.Fatal(err)
        }
    }
}

func utf8ToGBK(text string) (string, error) {
    dst := make([]byte, len(text)*2)
    tr := simplifiedchinese.GB18030.NewEncoder()
    nDst, _, err := tr.Transform(dst, []byte(text), true)
    if err != nil {
        return text, err
    }
    return string(dst[:nDst]), nil
}

var gbkZipTest = ZipTest{
    Name: "中文-测试.zip",
    File: []ZipTestFile{
        {
            Name: "李白/月下独酌.txt",
            Body: `月下独酌 - 李白

花间一壶酒,独酌无相亲。
举杯邀明月,对影成三人。
月既不解饮,影徒随我身。
暂伴月将影,行乐须及春。
我歌月徘徊,我舞影零乱。
醒时同交欢,醉后各分散。
永结无情游,相期邈云汉。
`,
        },
        {
            Name: "杜甫/",
            Body: "",
        },
    },
}

So i create CL9381 try to fix this poblem.
But CL9381 can only support utf8 encoding,
it can't create local gbk encoding zip.

I think we need new api for user defined filename encoding:

func OpenReaderEx(name string, decoder func(x string)(utf8Name string)) (*ReadCloser, error)
func (w *Writer) CreateEx(name string, encoder func(x string)(localName string)) (io.Writer, error)

If the decoder or encoder is nil, the local encoding is utf8.

The func (w *Writer) Create(name string) (io.Writer, error) force use utf8 encoding.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions