• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mewkiz / flac / 6713408042

31 Oct 2023 11:04PM UTC coverage: 68.265% (+4.9%) from 63.409%
6713408042

push

github

mewmew
internal/bits: minor updates of TestUnary for consistency

Run `goimports -w` to sort imports and change order of
"expected xx, got xx" to match other test cases
(e.g. TestZigZag).

1680 of 2461 relevant lines covered (68.26%)

4364391.81 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

59.03
/encode_meta.go
1
package flac
2

3
import (
4
        "encoding/binary"
5
        "fmt"
6
        "io"
7

8
        "github.com/icza/bitio"
9
        "github.com/mewkiz/flac/internal/ioutilx"
10
        "github.com/mewkiz/flac/meta"
11
        "github.com/mewkiz/pkg/errutil"
12
)
13

14
// --- [ Metadata block ] ------------------------------------------------------
15

16
// encodeBlock encodes the metadata block, writing to bw.
17
func encodeBlock(bw *bitio.Writer, block *meta.Block, last bool) error {
192✔
18
        if block.Type == meta.TypePadding {
236✔
19
                return encodePadding(bw, block.Length, last)
44✔
20
        }
44✔
21
        if block.Length == 0 {
150✔
22
                return encodeEmptyBlock(bw, block.Type, last)
2✔
23
        }
2✔
24
        switch body := block.Body.(type) {
146✔
25
        case *meta.StreamInfo:
×
26
                return encodeStreamInfo(bw, body, last)
×
27
        case *meta.Application:
9✔
28
                return encodeApplication(bw, body, last)
9✔
29
        case *meta.SeekTable:
44✔
30
                return encodeSeekTable(bw, body, last)
44✔
31
        case *meta.VorbisComment:
80✔
32
                return encodeVorbisComment(bw, body, last)
80✔
33
        case *meta.CueSheet:
6✔
34
                return encodeCueSheet(bw, body, last)
6✔
35
        case *meta.Picture:
7✔
36
                return encodePicture(bw, body, last)
7✔
37
        default:
×
38
                panic(fmt.Errorf("support for metadata block body type %T not yet implemented", body))
×
39
        }
40
}
41

42
// --- [ Metadata block header ] -----------------------------------------------
43

44
// encodeEmptyBlock encodes the metadata block header of an empty metadata
45
// block with the specified type, writing to bw.
46
func encodeEmptyBlock(bw *bitio.Writer, typ meta.Type, last bool) error {
2✔
47
        // Store metadata block header.
2✔
48
        hdr := &meta.Header{
2✔
49
                IsLast: last,
2✔
50
                Type:   typ,
2✔
51
                Length: 0,
2✔
52
        }
2✔
53
        if err := encodeBlockHeader(bw, hdr); err != nil {
2✔
54
                return errutil.Err(err)
×
55
        }
×
56
        return nil
2✔
57
}
58

59
// --- [ Metadata block header ] -----------------------------------------------
60

61
// encodeBlockHeader encodes the metadata block header, writing to bw.
62
func encodeBlockHeader(bw *bitio.Writer, hdr *meta.Header) error {
274✔
63
        // 1 bit: IsLast.
274✔
64
        if err := bw.WriteBool(hdr.IsLast); err != nil {
274✔
65
                return errutil.Err(err)
×
66
        }
×
67
        // 7 bits: Type.
68
        if err := bw.WriteBits(uint64(hdr.Type), 7); err != nil {
274✔
69
                return errutil.Err(err)
×
70
        }
×
71
        // 24 bits: Length.
72
        if err := bw.WriteBits(uint64(hdr.Length), 24); err != nil {
274✔
73
                return errutil.Err(err)
×
74
        }
×
75
        return nil
274✔
76
}
77

78
// --- [ StreamInfo ] ----------------------------------------------------------
79

80
// encodeStreamInfo encodes the StreamInfo metadata block, writing to bw.
81
func encodeStreamInfo(bw *bitio.Writer, info *meta.StreamInfo, last bool) error {
82✔
82
        // Store metadata block header.
82✔
83
        const nbits = 16 + 16 + 24 + 24 + 20 + 3 + 5 + 36 + 8*16
82✔
84
        hdr := &meta.Header{
82✔
85
                IsLast: last,
82✔
86
                Type:   meta.TypeStreamInfo,
82✔
87
                Length: nbits / 8,
82✔
88
        }
82✔
89
        if err := encodeBlockHeader(bw, hdr); err != nil {
82✔
90
                return errutil.Err(err)
×
91
        }
×
92

93
        // Store metadata block body.
94
        // 16 bits: BlockSizeMin.
95
        if err := bw.WriteBits(uint64(info.BlockSizeMin), 16); err != nil {
82✔
96
                return errutil.Err(err)
×
97
        }
×
98
        // 16 bits: BlockSizeMax.
99
        if err := bw.WriteBits(uint64(info.BlockSizeMax), 16); err != nil {
82✔
100
                return errutil.Err(err)
×
101
        }
×
102
        // 24 bits: FrameSizeMin.
103
        if err := bw.WriteBits(uint64(info.FrameSizeMin), 24); err != nil {
82✔
104
                return errutil.Err(err)
×
105
        }
×
106
        // 24 bits: FrameSizeMax.
107
        if err := bw.WriteBits(uint64(info.FrameSizeMax), 24); err != nil {
82✔
108
                return errutil.Err(err)
×
109
        }
×
110
        // 20 bits: SampleRate.
111
        if err := bw.WriteBits(uint64(info.SampleRate), 20); err != nil {
82✔
112
                return errutil.Err(err)
×
113
        }
×
114
        // 3 bits: NChannels; stored as (number of channels) - 1.
115
        if err := bw.WriteBits(uint64(info.NChannels-1), 3); err != nil {
82✔
116
                return errutil.Err(err)
×
117
        }
×
118
        // 5 bits: BitsPerSample; stored as (bits-per-sample) - 1.
119
        if err := bw.WriteBits(uint64(info.BitsPerSample-1), 5); err != nil {
82✔
120
                return errutil.Err(err)
×
121
        }
×
122
        // 36 bits: NSamples.
123
        if err := bw.WriteBits(info.NSamples, 36); err != nil {
82✔
124
                return errutil.Err(err)
×
125
        }
×
126
        // 16 bytes: MD5sum.
127
        if _, err := bw.Write(info.MD5sum[:]); err != nil {
82✔
128
                return errutil.Err(err)
×
129
        }
×
130
        return nil
82✔
131
}
132

133
// --- [ Padding ] ----------------------------------------------------------
134

135
// encodePadding encodes the Padding metadata block, writing to bw.
136
func encodePadding(bw *bitio.Writer, length int64, last bool) error {
44✔
137
        // Store metadata block header.
44✔
138
        hdr := &meta.Header{
44✔
139
                IsLast: last,
44✔
140
                Type:   meta.TypePadding,
44✔
141
                Length: length,
44✔
142
        }
44✔
143
        if err := encodeBlockHeader(bw, hdr); err != nil {
44✔
144
                return errutil.Err(err)
×
145
        }
×
146
        // Store metadata block body.
147
        if _, err := io.CopyN(bw, ioutilx.Zero, length); err != nil {
44✔
148
                return errutil.Err(err)
×
149
        }
×
150
        return nil
44✔
151
}
152

153
// --- [ Application ] ---------------------------------------------------------
154

155
// encodeApplication encodes the Application metadata block, writing to bw.
156
func encodeApplication(bw *bitio.Writer, app *meta.Application, last bool) error {
9✔
157
        // Store metadata block header.
9✔
158
        nbits := int64(32 + 8*len(app.Data))
9✔
159
        hdr := &meta.Header{
9✔
160
                IsLast: last,
9✔
161
                Type:   meta.TypeApplication,
9✔
162
                Length: nbits / 8,
9✔
163
        }
9✔
164
        if err := encodeBlockHeader(bw, hdr); err != nil {
9✔
165
                return errutil.Err(err)
×
166
        }
×
167

168
        // Store metadata block body.
169
        // 32 bits: ID.
170
        if err := bw.WriteBits(uint64(app.ID), 32); err != nil {
9✔
171
                return errutil.Err(err)
×
172
        }
×
173
        // TODO: check if the Application block may contain only an ID.
174
        if _, err := bw.Write(app.Data); err != nil {
9✔
175
                return errutil.Err(err)
×
176
        }
×
177
        return nil
9✔
178
}
179

180
// --- [ SeekTable ] -----------------------------------------------------------
181

182
// encodeSeekTable encodes the SeekTable metadata block, writing to bw.
183
func encodeSeekTable(bw *bitio.Writer, table *meta.SeekTable, last bool) error {
44✔
184
        // Store metadata block header.
44✔
185
        nbits := int64((64 + 64 + 16) * len(table.Points))
44✔
186
        hdr := &meta.Header{
44✔
187
                IsLast: last,
44✔
188
                Type:   meta.TypeSeekTable,
44✔
189
                Length: nbits / 8,
44✔
190
        }
44✔
191
        if err := encodeBlockHeader(bw, hdr); err != nil {
44✔
192
                return errutil.Err(err)
×
193
        }
×
194

195
        // Store metadata block body.
196
        for _, point := range table.Points {
1,866,639✔
197
                if err := binary.Write(bw, binary.BigEndian, point); err != nil {
1,866,595✔
198
                        return errutil.Err(err)
×
199
                }
×
200
        }
201
        return nil
44✔
202
}
203

204
// --- [ VorbisComment ] -------------------------------------------------------
205

206
// encodeVorbisComment encodes the VorbisComment metadata block, writing to bw.
207
func encodeVorbisComment(bw *bitio.Writer, comment *meta.VorbisComment, last bool) error {
80✔
208
        // Store metadata block header.
80✔
209
        nbits := int64(32 + 8*len(comment.Vendor) + 32)
80✔
210
        for _, tag := range comment.Tags {
60,216✔
211
                nbits += int64(32 + 8*(len(tag[0])+1+len(tag[1])))
60,136✔
212
        }
60,136✔
213
        hdr := &meta.Header{
80✔
214
                IsLast: last,
80✔
215
                Type:   meta.TypeVorbisComment,
80✔
216
                Length: nbits / 8,
80✔
217
        }
80✔
218
        if err := encodeBlockHeader(bw, hdr); err != nil {
80✔
219
                return errutil.Err(err)
×
220
        }
×
221

222
        // Store metadata block body.
223
        // 32 bits: vendor length.
224
        // TODO: verify that little-endian encoding is used; otherwise, switch to
225
        // using bw.WriteBits.
226
        if err := binary.Write(bw, binary.LittleEndian, uint32(len(comment.Vendor))); err != nil {
80✔
227
                return errutil.Err(err)
×
228
        }
×
229
        // (vendor length) bits: Vendor.
230
        if _, err := bw.Write([]byte(comment.Vendor)); err != nil {
80✔
231
                return errutil.Err(err)
×
232
        }
×
233
        // Store tags.
234
        // 32 bits: number of tags.
235
        if err := binary.Write(bw, binary.LittleEndian, uint32(len(comment.Tags))); err != nil {
80✔
236
                return errutil.Err(err)
×
237
        }
×
238
        for _, tag := range comment.Tags {
60,216✔
239
                // Store tag, which has the following format:
60,136✔
240
                //    NAME=VALUE
60,136✔
241
                buf := []byte(fmt.Sprintf("%s=%s", tag[0], tag[1]))
60,136✔
242
                // 32 bits: vector length
60,136✔
243
                if err := binary.Write(bw, binary.LittleEndian, uint32(len(buf))); err != nil {
60,136✔
244
                        return errutil.Err(err)
×
245
                }
×
246
                // (vector length): vector.
247
                if _, err := bw.Write(buf); err != nil {
60,136✔
248
                        return errutil.Err(err)
×
249
                }
×
250
        }
251
        return nil
80✔
252
}
253

254
// --- [ CueSheet ] ------------------------------------------------------------
255

256
// encodeCueSheet encodes the CueSheet metadata block, writing to bw.
257
func encodeCueSheet(bw *bitio.Writer, cs *meta.CueSheet, last bool) error {
6✔
258
        // Store metadata block header.
6✔
259
        nbits := int64(8*128 + 64 + 1 + 7 + 8*258 + 8)
6✔
260
        for _, track := range cs.Tracks {
218✔
261
                nbits += 64 + 8 + 8*12 + 1 + 1 + 6 + 8*13 + 8
212✔
262
                for range track.Indicies {
4,974✔
263
                        nbits += 64 + 8 + 8*3
4,762✔
264
                }
4,762✔
265
        }
266
        hdr := &meta.Header{
6✔
267
                IsLast: last,
6✔
268
                Type:   meta.TypeCueSheet,
6✔
269
                Length: nbits / 8,
6✔
270
        }
6✔
271
        if err := encodeBlockHeader(bw, hdr); err != nil {
6✔
272
                return errutil.Err(err)
×
273
        }
×
274

275
        // Store metadata block body.
276
        // Store cue sheet.
277
        // 128 bytes: MCN.
278
        var mcn [128]byte
6✔
279
        copy(mcn[:], cs.MCN)
6✔
280
        if _, err := bw.Write(mcn[:]); err != nil {
6✔
281
                return errutil.Err(err)
×
282
        }
×
283
        // 64 bits: NLeadInSamples.
284
        if err := bw.WriteBits(cs.NLeadInSamples, 64); err != nil {
6✔
285
                return errutil.Err(err)
×
286
        }
×
287
        // 1 bit: IsCompactDisc.
288
        if err := bw.WriteBool(cs.IsCompactDisc); err != nil {
6✔
289
                return errutil.Err(err)
×
290
        }
×
291
        // 7 bits and 258 bytes: reserved.
292
        if err := bw.WriteBits(0, 7); err != nil {
6✔
293
                return errutil.Err(err)
×
294
        }
×
295
        if _, err := io.CopyN(bw, ioutilx.Zero, 258); err != nil {
6✔
296
                return errutil.Err(err)
×
297
        }
×
298
        // Store cue sheet tracks.
299
        // 8 bits: (number of tracks)
300
        if err := bw.WriteBits(uint64(len(cs.Tracks)), 8); err != nil {
6✔
301
                return errutil.Err(err)
×
302
        }
×
303
        for _, track := range cs.Tracks {
218✔
304
                // 64 bits: Offset.
212✔
305
                if err := bw.WriteBits(track.Offset, 64); err != nil {
212✔
306
                        return errutil.Err(err)
×
307
                }
×
308
                // 8 bits: Num.
309
                if err := bw.WriteBits(uint64(track.Num), 8); err != nil {
212✔
310
                        return errutil.Err(err)
×
311
                }
×
312
                // 12 bytes: ISRC.
313
                var isrc [12]byte
212✔
314
                copy(isrc[:], track.ISRC)
212✔
315
                if _, err := bw.Write(isrc[:]); err != nil {
212✔
316
                        return errutil.Err(err)
×
317
                }
×
318
                // 1 bit: IsAudio.
319
                if err := bw.WriteBool(!track.IsAudio); err != nil {
212✔
320
                        return errutil.Err(err)
×
321
                }
×
322
                // 1 bit: HasPreEmphasis.
323
                // mask = 01000000
324
                if err := bw.WriteBool(track.HasPreEmphasis); err != nil {
212✔
325
                        return errutil.Err(err)
×
326
                }
×
327
                // 6 bits and 13 bytes: reserved.
328
                // mask = 00111111
329
                if err := bw.WriteBits(0, 6); err != nil {
212✔
330
                        return errutil.Err(err)
×
331
                }
×
332
                if _, err := io.CopyN(bw, ioutilx.Zero, 13); err != nil {
212✔
333
                        return errutil.Err(err)
×
334
                }
×
335
                // Store indicies.
336
                // 8 bits: (number of indicies)
337
                if err := bw.WriteBits(uint64(len(track.Indicies)), 8); err != nil {
212✔
338
                        return errutil.Err(err)
×
339
                }
×
340
                for _, index := range track.Indicies {
4,974✔
341
                        // 64 bits: Offset.
4,762✔
342
                        if err := bw.WriteBits(index.Offset, 64); err != nil {
4,762✔
343
                                return errutil.Err(err)
×
344
                        }
×
345
                        // 8 bits: Num.
346
                        if err := bw.WriteBits(uint64(index.Num), 8); err != nil {
4,762✔
347
                                return errutil.Err(err)
×
348
                        }
×
349
                        // 3 bytes: reserved.
350
                        if _, err := io.CopyN(bw, ioutilx.Zero, 3); err != nil {
4,762✔
351
                                return errutil.Err(err)
×
352
                        }
×
353
                }
354
        }
355
        return nil
6✔
356
}
357

358
// --- [ Picture ] -------------------------------------------------------------
359

360
// encodePicture encodes the Picture metadata block, writing to bw.
361
func encodePicture(bw *bitio.Writer, pic *meta.Picture, last bool) error {
7✔
362
        // Store metadata block header.
7✔
363
        nbits := int64(32 + 32 + 8*len(pic.MIME) + 32 + 8*len(pic.Desc) + 32 + 32 + 32 + 32 + 32 + 8*len(pic.Data))
7✔
364
        hdr := &meta.Header{
7✔
365
                IsLast: last,
7✔
366
                Type:   meta.TypePicture,
7✔
367
                Length: nbits / 8,
7✔
368
        }
7✔
369
        if err := encodeBlockHeader(bw, hdr); err != nil {
7✔
370
                return errutil.Err(err)
×
371
        }
×
372

373
        // Store metadata block body.
374
        // 32 bits: Type.
375
        if err := bw.WriteBits(uint64(pic.Type), 32); err != nil {
7✔
376
                return errutil.Err(err)
×
377
        }
×
378
        // 32 bits: (MIME type length).
379
        if err := bw.WriteBits(uint64(len(pic.MIME)), 32); err != nil {
7✔
380
                return errutil.Err(err)
×
381
        }
×
382
        // (MIME type length) bytes: MIME.
383
        if _, err := bw.Write([]byte(pic.MIME)); err != nil {
7✔
384
                return errutil.Err(err)
×
385
        }
×
386
        // 32 bits: (description length).
387
        if err := bw.WriteBits(uint64(len(pic.Desc)), 32); err != nil {
7✔
388
                return errutil.Err(err)
×
389
        }
×
390
        // (description length) bytes: Desc.
391
        if _, err := bw.Write([]byte(pic.Desc)); err != nil {
7✔
392
                return errutil.Err(err)
×
393
        }
×
394
        // 32 bits: Width.
395
        if err := bw.WriteBits(uint64(pic.Width), 32); err != nil {
7✔
396
                return errutil.Err(err)
×
397
        }
×
398
        // 32 bits: Height.
399
        if err := bw.WriteBits(uint64(pic.Height), 32); err != nil {
7✔
400
                return errutil.Err(err)
×
401
        }
×
402
        // 32 bits: Depth.
403
        if err := bw.WriteBits(uint64(pic.Depth), 32); err != nil {
7✔
404
                return errutil.Err(err)
×
405
        }
×
406
        // 32 bits: NPalColors.
407
        if err := bw.WriteBits(uint64(pic.NPalColors), 32); err != nil {
7✔
408
                return errutil.Err(err)
×
409
        }
×
410
        // 32 bits: (data length).
411
        if err := bw.WriteBits(uint64(len(pic.Data)), 32); err != nil {
7✔
412
                return errutil.Err(err)
×
413
        }
×
414
        // (data length) bytes: Data.
415
        if _, err := bw.Write(pic.Data); err != nil {
7✔
416
                return errutil.Err(err)
×
417
        }
×
418
        return nil
7✔
419
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc