-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathsauce.go
136 lines (112 loc) · 2.71 KB
/
sauce.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// sauce.go
// go-ansi
//
// Copyright (C) 2017 ActiveState Software Inc.
// Written by Pete Garcin (@rawktron)
//
// Based on ansilove/C
// Copyright (C) 2011-2017 Stefan Vogt, Brian Cassidy, and Frederic Cambus.
// All rights reserved.
// ansilove/C is licensed under the BSD-2 License.
//
// go-ansi is licensed under the BSD 3-Clause License.
// See the file LICENSE for details.
//
package goansi
import (
"encoding/binary"
"io"
"os"
)
// SauceID is the SAUCE record identifier tagged onto the file data
const SauceID = "SAUCE"
// SauceInfo contains the bulk of the SAUCE record
type SauceInfo struct {
ID [5]byte
Version [2]byte
Title [35]byte
Author [20]byte
Group [20]byte
Date [8]byte
FileSize int32
DataType byte
FileType byte
Tinfo1 uint16
Tinfo2 uint16
Tinfo3 uint16
Tinfo4 uint16
Comments byte
Flags byte
Filler [22]byte
}
// Sauce - container structure for sauceInfo and variable length comments
// This feels like a bit of a hack
type Sauce struct {
Sauceinf SauceInfo
CommentLines []string
}
// Internal constants
const recordSize = 128
const commentSize = 64
const commentID = "COMNT"
// TODO: Put this check function into a utils file
// Simple error checking to reduce duplicated code
func check(e error) {
if e != nil {
panic(e)
}
}
// ReadFileName reads SAUCE via a filename.
func readFileName(fileName string) *Sauce {
file, err := os.Open(fileName)
check(err)
record := readFile(file)
file.Close()
return record
}
// ReadFile - Read SAUCE via a FILE pointer.
// TODO: This doesn't trap OOM errors
// TODO: This seems redundant now, can we eliminate this?
func readFile(file *os.File) *Sauce {
record := readRecord(file)
return record
}
// ReadRecord parses a SAUCE record from a data stream
func readRecord(stream io.ReadSeeker) *Sauce {
_, err := stream.Seek(0-recordSize, 2)
if err != nil {
return nil
}
var record Sauce
var sinfo SauceInfo
err = binary.Read(stream, binary.LittleEndian, &sinfo)
check(err)
if string(sinfo.ID[:]) == SauceID {
var comments []string
if sinfo.Comments > 0 {
comments = readComments(stream, int(sinfo.Comments))
}
record = Sauce{Sauceinf: sinfo, CommentLines: comments}
} else {
record = Sauce{}
}
return &record
}
func readComments(stream io.ReadSeeker, comments int) []string {
var commentLines []string
_, err := stream.Seek(0-(recordSize+5+commentSize*int64(comments)), 2)
check(err)
ID := make([]byte, 6)
stream.Read(ID)
idString := string(ID[:6])
if idString != commentID {
return nil
}
// TODO Error checking
for i := 0; i < comments; i++ {
buf := make([]byte, commentSize+1)
stream.Read(buf)
commentLines = append(commentLines, string(buf[:]))
}
return commentLines
}