-
Notifications
You must be signed in to change notification settings - Fork 14
/
Copy pathreadwrite.go
140 lines (125 loc) · 3.58 KB
/
readwrite.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
137
138
139
140
package stl
// This file defines the top level reading and writing operations
// for the stl package
import (
"bufio"
"errors"
"io"
"os"
)
// ErrIncompleteBinaryHeader is used when reading binary STL files with incomplete header.
var ErrIncompleteBinaryHeader = errors.New("incomplete STL binary header, 84 bytes expected")
// ErrUnexpectedEOF is used by ReadFile and ReadAll to signify an incomplete file.
var ErrUnexpectedEOF = errors.New("unexpected end of file")
// ReadFile reads the contents of a file into a new Solid object. The file
// can be either in STL ASCII format, beginning with "solid ", or in
// STL binary format, beginning with a 84 byte header. Shorthand for os.Open and ReadAll
func ReadFile(filename string) (solid *Solid, err error) {
var s Solid
err = CopyFile(filename, &s)
if err == nil {
solid = &s
}
return
}
// ReadAll reads the contents of a file into a new Solid object. The file
// can be either in STL ASCII format, beginning with "solid ", or in
// STL binary format, beginning with a 84 byte header. Because of this,
// the file pointer has to be at the beginning of the file.
func ReadAll(r io.ReadSeeker) (solid *Solid, err error) {
var s Solid
err = CopyAll(r, &s)
if err == nil {
solid = &s
}
return
}
func CopyFile(filename string, sw Writer) (err error) {
file, openErr := os.Open(filename)
if openErr != nil {
err = openErr
return
}
err = CopyAll(file, sw)
closeErr := file.Close()
if err == nil {
err = closeErr
}
return
}
func CopyAll(r io.ReadSeeker, sw Writer) (err error) {
isBinary, err := isBinaryFile(r)
if err != nil {
return
}
if _, err = r.Seek(0, io.SeekStart); err != nil {
return
}
br := bufio.NewReader(r)
if isBinary {
sw.SetASCII(false)
err = readAllBinary(br, sw)
} else {
sw.SetASCII(true)
err = readAllASCII(br, sw)
}
return
}
// isBinaryFile returns true if the seekable stream tests as a binary file by
// matching triangle count (in header) and file size
func isBinaryFile(r io.ReadSeeker) (isBinary bool, err error) {
var header [binaryHeaderSize]byte
_, err = r.Read(header[:])
if err != nil {
if err == io.EOF { // too short to meet spec
err = nil
}
return
}
triangleCount := triangleCountFromBinaryHeader(header[:])
expectedFileLength := int64(triangleCount)*binaryTriangleSize + binaryHeaderSize
actualFileLength, err := r.Seek(0, io.SeekEnd)
if err != nil {
return
}
isBinary = expectedFileLength == actualFileLength
return
}
// WriteFile creates file with name filename and write contents of this Solid.
// Shorthand for os.Create and Solid.WriteAll
func (s *Solid) WriteFile(filename string) (err error) {
file, err := os.Create(filename)
if err != nil {
return err
}
bufWriter := bufio.NewWriter(file)
err = s.WriteAll(bufWriter)
flushErr := bufWriter.Flush()
closeErr := file.Close()
if err == nil {
err = flushErr
}
if err == nil {
err = closeErr
}
return
}
// WriteAll writes the contents of this solid to an io.Writer. Depending on solid.IsAscii
// the STL ASCII format, or the STL binary format is used. If IsAscii
// is false, and the binary format is used, solid.Name will be used for
// the header, if solid.BinaryHeader is empty.
func (s *Solid) WriteAll(w io.Writer) error {
if s.IsAscii {
return writeSolidASCII(w, s)
}
return writeSolidBinary(w, s)
}
// Extracts an ASCII string from a byte slice. Reads all characters
// from the beginning until a \0 or a non-ASCII character is found.
func extractASCIIString(byteData []byte) string {
i := 0
for i < len(byteData) && byteData[i] < byte(128) && byteData[i] != byte(0) {
i++
}
return string(byteData[0:i])
}