aboutsummaryrefslogtreecommitdiff
path: root/feed/meta.go
diff options
context:
space:
mode:
Diffstat (limited to 'feed/meta.go')
-rw-r--r--feed/meta.go106
1 files changed, 106 insertions, 0 deletions
diff --git a/feed/meta.go b/feed/meta.go
new file mode 100644
index 0000000..fd46025
--- /dev/null
+++ b/feed/meta.go
@@ -0,0 +1,106 @@
+package feed
+
+import (
+ "bufio"
+ "encoding/hex"
+ "fmt"
+ "io"
+ "strconv"
+ "strings"
+ "time"
+)
+
+// NVD metadata.
+type Meta struct {
+ LastModifiedDate time.Time // last modified time
+ Size uint64 // uncompressed size, in bytes
+ ZipSize uint64 // zip file size, in bytes
+ GzSize uint64 // gz file size, in bytes
+ Sha256 [32]byte // sha256 hash of uncompressed data
+}
+
+func parseMetaSize(name, val string) (uint64, error) {
+ // parse value, check for error
+ v, err := strconv.ParseUint(val, 10, 64)
+ if err == nil {
+ // return size
+ return v, nil
+ } else {
+ // return error
+ return 0, fmt.Errorf("invalid %s: \"%s\"", name, val)
+ }
+}
+
+// Unmarshal new Metadata from reader.
+func NewMeta(r io.Reader) (*Meta, error) {
+ // declare result
+ var m Meta
+
+ // create scanner
+ scanner := bufio.NewScanner(r)
+
+ // read lines
+ for scanner.Scan() {
+ // split into key/value pair, check for error
+ pair := strings.SplitN(scanner.Text(), ":", 2)
+ if len(pair) != 2 {
+ return nil, fmt.Errorf("bad meta line: \"%s\"", scanner.Text())
+ }
+
+ switch pair[0] {
+ case "lastModifiedDate":
+ // parse time, check for error
+ if err := m.LastModifiedDate.UnmarshalText([]byte(pair[1])); err != nil {
+ return nil, err
+ }
+ case "size":
+ if v, err := parseMetaSize("size", pair[1]); err == nil {
+ m.Size = v
+ } else {
+ return nil, err
+ }
+ case "zipSize":
+ if v, err := parseMetaSize("zipSize", pair[1]); err == nil {
+ m.ZipSize = v
+ } else {
+ return nil, err
+ }
+ case "gzSize":
+ if v, err := parseMetaSize("gzSize", pair[1]); err == nil {
+ m.GzSize = v
+ } else {
+ return nil, err
+ }
+ case "sha256":
+ // check hash length
+ if len(pair[1]) != 64 {
+ return nil, fmt.Errorf("invalid sha256 hash length: %d", len(pair[1]))
+ }
+
+ // decode hex, check for error
+ buf, err := hex.DecodeString(pair[1])
+ if err != nil {
+ return nil, fmt.Errorf("invalid sha256 hash: %v", err)
+ }
+
+ // save to buffer, check for error
+ len := copy(m.Sha256[:], buf[0:32])
+ if len != 32 {
+ // difficult to test, but this basically doesn't happen, see here:
+ // https://github.com/golang/go/blob/2ebe77a2fda1ee9ff6fd9a3e08933ad1ebaea039/src/runtime/slice.go#L247
+ return nil, fmt.Errorf("invalid copy length: %d", len)
+ }
+ default:
+ // return error
+ return nil, fmt.Errorf("unknown key: \"%s\"", pair[0])
+ }
+ }
+
+ // check for scanner error
+ if err := scanner.Err(); err != nil {
+ return nil, err
+ }
+
+ // return success
+ return &m, nil
+}