18
18
package ota
19
19
20
20
import (
21
- "bufio"
22
21
"encoding/binary"
22
+ "fmt"
23
23
"hash/crc32"
24
24
"io"
25
25
"strconv"
26
26
27
27
"github.com/arduino/arduino-cloud-cli/internal/lzss"
28
- "github.com/juju/errors"
29
28
)
30
29
31
- // A writer is a buffered, flushable writer.
32
- type writer interface {
33
- io.Writer
34
- Flush () error
35
- }
36
-
37
- // encoder encodes a binary into an .ota file.
38
- type encoder struct {
39
- // w is the writer that compressed bytes are written to.
40
- w writer
30
+ // Encoder writes a binary to an output stream in the ota format.
31
+ type Encoder struct {
32
+ // w is the stream where encoded bytes are written.
33
+ w io.Writer
41
34
42
- // vendorID is the ID of the board vendor
35
+ // vendorID is the ID of the board vendor.
43
36
vendorID string
44
37
45
- // is the ID of the board vendor is the ID of the board model
38
+ // productID is the ID of the board model.
46
39
productID string
47
40
}
48
41
49
- // NewWriter creates a new `WriteCloser` for the the given VID/PID.
50
- func NewWriter (w io.Writer , vendorID , productID string ) io.WriteCloser {
51
- bw , ok := w .(writer )
52
- if ! ok {
53
- bw = bufio .NewWriter (w )
54
- }
55
- return & encoder {
56
- w : bw ,
42
+ // NewEncoder creates a new ota encoder.
43
+ func NewEncoder (w io.Writer , vendorID , productID string ) * Encoder {
44
+ return & Encoder {
45
+ w : w ,
57
46
vendorID : vendorID ,
58
47
productID : productID ,
59
48
}
60
49
}
61
50
62
- // Write writes a compressed representation of p to e's underlying writer.
63
- func (e * encoder ) Write (binaryData []byte ) (int , error ) {
64
- //log.Println("original binaryData is", len(binaryData), "bytes length")
65
-
66
- // Magic number (VID/PID)
51
+ // Encode compresses data using a lzss algorithm, encodes the result
52
+ // in ota format and writes it to e's underlying writer.
53
+ func (e * Encoder ) Encode (data []byte ) error {
54
+ // Compute the magic number (VID/PID)
67
55
magicNumber := make ([]byte , 4 )
68
56
vid , err := strconv .ParseUint (e .vendorID , 16 , 16 )
69
57
if err != nil {
70
- return 0 , errors . Annotate ( err , "OTA encoder: failed to parse vendorID" )
58
+ return fmt . Errorf ( "cannot parse vendorID: %w" , err )
71
59
}
72
60
pid , err := strconv .ParseUint (e .productID , 16 , 16 )
73
61
if err != nil {
74
- return 0 , errors . Annotate ( err , "OTA encoder: failed to parse productID" )
62
+ return fmt . Errorf ( "cannot parse productID: %w" , err )
75
63
}
76
64
77
65
binary .LittleEndian .PutUint16 (magicNumber [0 :2 ], uint16 (pid ))
@@ -82,61 +70,43 @@ func (e *encoder) Write(binaryData []byte) (int, error) {
82
70
Compression : true ,
83
71
}
84
72
85
- // Compress the compiled binary
86
- compressed := lzss .Encode (binaryData )
87
-
73
+ compressed := lzss .Encode (data )
88
74
// Prepend magic number and version field to payload
89
- var binDataComplete []byte
90
- binDataComplete = append (binDataComplete , magicNumber ... )
91
- binDataComplete = append (binDataComplete , version .AsBytes ()... )
92
- binDataComplete = append (binDataComplete , compressed ... )
93
- //log.Println("binDataComplete is", len(binDataComplete), "bytes length")
75
+ var outData []byte
76
+ outData = append (outData , magicNumber ... )
77
+ outData = append (outData , version .Bytes ()... )
78
+ outData = append (outData , compressed ... )
94
79
95
- headerSize , err : = e .writeHeader (binDataComplete )
80
+ err = e .writeHeader (outData )
96
81
if err != nil {
97
- return headerSize , err
82
+ return fmt . Errorf ( "cannot write data header to output stream: %w" , err )
98
83
}
99
84
100
- payloadSize , err : = e .writePayload ( binDataComplete )
85
+ _ , err = e .w . Write ( outData )
101
86
if err != nil {
102
- return payloadSize , err
87
+ return fmt . Errorf ( "cannot write encoded data to output stream: %w" , err )
103
88
}
104
89
105
- return headerSize + payloadSize , nil
106
- }
107
-
108
- // Close closes the encoder, flushing any pending output. It does not close or
109
- // flush e's underlying writer.
110
- func (e * encoder ) Close () error {
111
- return e .w .Flush ()
90
+ return nil
112
91
}
113
92
114
- func (e * encoder ) writeHeader (binDataComplete []byte ) (int , error ) {
115
-
93
+ func (e * Encoder ) writeHeader (data []byte ) error {
116
94
// Write the length of the content
117
95
lengthAsBytes := make ([]byte , 4 )
118
- binary .LittleEndian .PutUint32 (lengthAsBytes , uint32 (len (binDataComplete )))
119
-
120
- n , err := e .w .Write (lengthAsBytes )
96
+ binary .LittleEndian .PutUint32 (lengthAsBytes , uint32 (len (data )))
97
+ _ , err := e .w .Write (lengthAsBytes )
121
98
if err != nil {
122
- return n , err
99
+ return err
123
100
}
124
101
125
- // Calculate the checksum for binDataComplete
126
- crc := crc32 .ChecksumIEEE (binDataComplete )
127
-
128
- // encode the checksum uint32 value as 4 bytes
102
+ // Write the checksum uint32 value as 4 bytes
103
+ crc := crc32 .ChecksumIEEE (data )
129
104
crcAsBytes := make ([]byte , 4 )
130
105
binary .LittleEndian .PutUint32 (crcAsBytes , crc )
131
-
132
- n , err = e .w .Write (crcAsBytes )
106
+ _ , err = e .w .Write (crcAsBytes )
133
107
if err != nil {
134
- return n , err
108
+ return err
135
109
}
136
110
137
- return len (lengthAsBytes ) + len (crcAsBytes ), nil
138
- }
139
-
140
- func (e * encoder ) writePayload (data []byte ) (int , error ) {
141
- return e .w .Write (data )
111
+ return nil
142
112
}
0 commit comments