Files

68 lines
1.7 KiB
Go

package parser
import (
"bytes"
"crypto/sha1"
"encoding/hex"
"errors"
"fmt"
"math"
"strconv"
"strings"
"git.kleiax.de/homepage/field"
)
type PuzzleBank struct {
ParserHelper
}
func (pb *PuzzleBank) Parse(data []byte) error {
if pb == nil {
return errors.New("nil puzzle bank parser")
}
var parsed []*field.Field
for index, rawLine := range bytes.Split(data, []byte("\n")) {
lineNumber := index + 1
line := strings.TrimSpace(string(rawLine))
if line == "" {
continue
}
columns := strings.Fields(line)
if len(columns) != 3 {
return fmt.Errorf("line %d: %w: expected hash, puzzle and rating", lineNumber, ErrInvalidInput)
}
if len(columns[0]) != 12 {
return fmt.Errorf("line %d: %w: hash has %d characters, expected 12", lineNumber, ErrInvalidInput, len(columns[0]))
}
if _, err := hex.DecodeString(columns[0]); err != nil {
return fmt.Errorf("line %d: %w: invalid hash: %v", lineNumber, ErrInvalidInput, err)
}
digest := sha1.Sum([]byte(columns[1]))
if columns[0] != hex.EncodeToString(digest[:])[:12] {
return fmt.Errorf("line %d: %w: hash does not match puzzle", lineNumber, ErrInvalidInput)
}
rating, err := strconv.ParseFloat(columns[2], 64)
if err != nil {
return fmt.Errorf("line %d: %w: invalid rating %q: %v", lineNumber, ErrInvalidInput, columns[2], err)
}
if rating < 0 || math.IsNaN(rating) || math.IsInf(rating, 0) {
return fmt.Errorf("line %d: %w: rating must be a finite non-negative number", lineNumber, ErrInvalidInput)
}
parsedField, err := classicField(columns[1], rating)
if err != nil {
return fmt.Errorf("line %d: %w", lineNumber, err)
}
parsed = append(parsed, parsedField)
}
if len(parsed) == 0 {
return ErrNoPuzzles
}
pb.fields = parsed
return nil
}