117 lines
2.4 KiB
Go
117 lines
2.4 KiB
Go
package nntp
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"io"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
// YencMetadata contains just the header information
|
|
type YencMetadata struct {
|
|
Name string // filename
|
|
Size int64 // total file size
|
|
Part int // part number
|
|
Total int // total parts
|
|
Begin int64 // part start byte
|
|
End int64 // part end byte
|
|
LineSize int // line length
|
|
}
|
|
|
|
// DecodeYencHeaders extracts only yenc header metadata without decoding body
|
|
func DecodeYencHeaders(reader io.Reader) (*YencMetadata, error) {
|
|
buf := bufio.NewReader(reader)
|
|
metadata := &YencMetadata{}
|
|
|
|
// Find and parse =ybegin header
|
|
if err := parseYBeginHeader(buf, metadata); err != nil {
|
|
return nil, NewYencDecodeError(fmt.Errorf("failed to parse ybegin header: %w", err))
|
|
}
|
|
|
|
// Parse =ypart header if this is a multipart file
|
|
if metadata.Part > 0 {
|
|
if err := parseYPartHeader(buf, metadata); err != nil {
|
|
return nil, NewYencDecodeError(fmt.Errorf("failed to parse ypart header: %w", err))
|
|
}
|
|
}
|
|
|
|
return metadata, nil
|
|
}
|
|
|
|
func parseYBeginHeader(buf *bufio.Reader, metadata *YencMetadata) error {
|
|
var s string
|
|
var err error
|
|
|
|
// Find the =ybegin line
|
|
for {
|
|
s, err = buf.ReadString('\n')
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if len(s) >= 7 && s[:7] == "=ybegin" {
|
|
break
|
|
}
|
|
}
|
|
|
|
// Parse the header line
|
|
parts := strings.SplitN(s[7:], "name=", 2)
|
|
if len(parts) > 1 {
|
|
metadata.Name = strings.TrimSpace(parts[1])
|
|
}
|
|
|
|
// Parse other parameters
|
|
for _, header := range strings.Split(parts[0], " ") {
|
|
kv := strings.SplitN(strings.TrimSpace(header), "=", 2)
|
|
if len(kv) < 2 {
|
|
continue
|
|
}
|
|
|
|
switch kv[0] {
|
|
case "size":
|
|
metadata.Size, _ = strconv.ParseInt(kv[1], 10, 64)
|
|
case "line":
|
|
metadata.LineSize, _ = strconv.Atoi(kv[1])
|
|
case "part":
|
|
metadata.Part, _ = strconv.Atoi(kv[1])
|
|
case "total":
|
|
metadata.Total, _ = strconv.Atoi(kv[1])
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func parseYPartHeader(buf *bufio.Reader, metadata *YencMetadata) error {
|
|
var s string
|
|
var err error
|
|
|
|
// Find the =ypart line
|
|
for {
|
|
s, err = buf.ReadString('\n')
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if len(s) >= 6 && s[:6] == "=ypart" {
|
|
break
|
|
}
|
|
}
|
|
|
|
// Parse part parameters
|
|
for _, header := range strings.Split(s[6:], " ") {
|
|
kv := strings.SplitN(strings.TrimSpace(header), "=", 2)
|
|
if len(kv) < 2 {
|
|
continue
|
|
}
|
|
|
|
switch kv[0] {
|
|
case "begin":
|
|
metadata.Begin, _ = strconv.ParseInt(kv[1], 10, 64)
|
|
case "end":
|
|
metadata.End, _ = strconv.ParseInt(kv[1], 10, 64)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|