You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
DateKeys-App/scripts/zip-go-read.go

133 lines
3.9 KiB

//go:build ignore
// Prints src/lib/dkc/testing/zip-vectors.json: how archive/zip of the Go
// standard library reads the ZIP samples that the page writes (plan of
// format 3 in datekeys-ts, step 5), which scripts/zip-ts-samples.mjs wrote
// into a directory. For each archive it records the SHA-256 of its bytes,
// the number of its entries and, for each entry, a line with its name,
// whether bit 11 marks the name as UTF-8, its method, its CRC-32, its sizes,
// the time archive/zip reads from its extra fields, in UTC, and the SHA-256
// of its content, read with the CRC-32 checked. It keeps the lines of an
// archive of 20 entries at most, and the SHA-256 of all of them joined by
// newlines for any archive, so that the archive of 65535 entries, which is
// ZIP64 by its number of entries, weighs little. zipsink.test.ts writes each
// archive again, requires its SHA-256, and computes the lines it must give.
//
// It needs only the standard library:
//
// node scripts/zip-ts-samples.mjs DIR > zip-samples.json
// go run zip-go-read.go DIR zip-samples.json > zip-vectors.json
package main
import (
"archive/zip"
"bytes"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"os"
"path/filepath"
"runtime"
"strings"
"time"
)
type sampleIn struct {
Name string `json:"name"`
File string `json:"file"`
SHA256 string `json:"sha256"`
}
type sampleOut struct {
Name string `json:"name"`
SHA256 string `json:"sha256"`
Count int `json:"count"`
LinesSHA256 string `json:"lines_sha256"`
Lines []string `json:"lines,omitempty"`
Error string `json:"error,omitempty"`
}
type output struct {
Description string `json:"description"`
Generator string `json:"generator"`
SamplesGenerator string `json:"samples_generator"`
Go string `json:"go"`
Samples []sampleOut `json:"samples"`
}
func must[T any](v T, err error) T {
if err != nil {
panic(err)
}
return v
}
// read reads an archive with archive/zip, and gives one line for each entry.
func read(b []byte) ([]string, error) {
r, err := zip.NewReader(bytes.NewReader(b), int64(len(b)))
if err != nil {
return nil, err
}
var lines []string
for _, f := range r.File {
rc, err := f.Open()
if err != nil {
return nil, fmt.Errorf("%s: %w", f.Name, err)
}
data, err := io.ReadAll(rc)
rc.Close()
if err != nil {
return nil, fmt.Errorf("%s: %w", f.Name, err)
}
sum := sha256.Sum256(data)
lines = append(lines, fmt.Sprintf("%s\t%t\t%d\t%08x\t%d\t%d\t%s\t%s",
f.Name, f.Flags&0x800 != 0, f.Method, f.CRC32, f.UncompressedSize64, f.CompressedSize64,
f.Modified.UTC().Format(time.RFC3339), hex.EncodeToString(sum[:])))
}
return lines, nil
}
func main() {
dir := os.Args[1]
var in struct {
Generator string `json:"generator"`
Samples []sampleIn `json:"samples"`
}
if err := json.Unmarshal(must(os.ReadFile(os.Args[2])), &in); err != nil {
panic(err)
}
out := output{
Description: "How archive/zip of Go reads the ZIP samples of the page; see the header of scripts/zip-go-read.go.",
Generator: "scripts/zip-go-read.go",
SamplesGenerator: in.Generator,
Go: runtime.Version(),
}
for _, s := range in.Samples {
b := must(os.ReadFile(filepath.Join(dir, s.File)))
sum := sha256.Sum256(b)
so := sampleOut{Name: s.Name, SHA256: hex.EncodeToString(sum[:])}
if so.SHA256 != s.SHA256 {
panic(fmt.Sprintf("%s: the file is not the sample written", s.Name))
}
lines, err := read(b)
if err != nil {
so.Error = err.Error()
}
so.Count = len(lines)
all := sha256.Sum256([]byte(strings.Join(lines, "\n")))
so.LinesSHA256 = hex.EncodeToString(all[:])
if len(lines) <= 20 {
so.Lines = lines
}
out.Samples = append(out.Samples, so)
}
e := json.NewEncoder(os.Stdout)
e.SetEscapeHTML(false)
e.SetIndent("", " ")
if err := e.Encode(out); err != nil {
panic(err)
}
}

Powered by TurnKey Linux.