-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrifx.go
119 lines (107 loc) · 2.65 KB
/
rifx.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
package rifx
import (
"bytes"
"encoding/binary"
"fmt"
"io"
)
// FromReader parses the RIFX format from a reader
func FromReader(r io.Reader) (*List, error) {
b4 := make([]byte, 4)
io.ReadFull(r, b4)
if fmt.Sprintf("%s", b4) != "RIFX" {
return nil, fmt.Errorf("Unknown RIFX file format")
}
io.ReadFull(r, b4)
fileSize := binary.BigEndian.Uint32(b4)
list, _, err := readList(r, fileSize)
if err != nil {
return nil, err
}
return list, nil
}
func readList(r io.Reader, limit uint32) (*List, uint32, error) {
listBlock := &List{}
readBytes := uint32(0)
blocks := make([]*Block, 0)
// Read the list identifier
idBytes := make([]byte, 4)
n, err := io.ReadFull(r, idBytes)
readBytes += uint32(n)
if err != nil {
return nil, readBytes, err
}
// Read all blocks in the list up to byte limit
numBlocks := 0
for readBytes < limit {
block, n, err := readBlock(r, limit-readBytes)
readBytes += n
if err != nil {
return nil, readBytes, err
}
blocks = append(blocks, block)
numBlocks++
}
listBlock.Identifier = fmt.Sprintf("%s", idBytes)
listBlock.NumBlocks = numBlocks
listBlock.Blocks = blocks
return listBlock, readBytes, nil
}
func readBlock(r io.Reader, limit uint32) (*Block, uint32, error) {
block := &Block{}
bytesRead := uint32(0)
b4 := make([]byte, 4)
// Read the type of block
n, err := io.ReadFull(r, b4)
bytesRead += uint32(n)
if err != nil {
return nil, bytesRead, err
}
block.Type = fmt.Sprintf("%s", b4)
// Read the number of bytes contained in the block
n, err = io.ReadFull(r, b4)
bytesRead += uint32(n)
if err != nil {
return nil, bytesRead, err
}
block.Size = binary.BigEndian.Uint32(b4)
if block.Size > limit-bytesRead {
// Overflow, or malformed block... Try to recover by reading as an anonymous block
restData := make([]byte, limit-bytesRead)
n, err = io.ReadFull(r, restData)
bytesRead += uint32(n)
if err != nil {
return nil, bytesRead, err
}
block.Data = bytes.Join([][]byte{[]byte(block.Type), b4, restData}, []byte{})
block.Type = "ANON"
} else {
// Read the bock data normally, and recurse on LISTS
switch block.Type {
case "LIST":
group, n, err := readList(r, block.Size)
bytesRead += n
if err != nil {
return nil, bytesRead, err
}
block.Data = group
default:
blockData := make([]byte, block.Size)
n, err = io.ReadFull(r, blockData)
bytesRead += uint32(n)
if err != nil {
return nil, bytesRead, err
}
block.Data = blockData
}
}
// Read padding if data is odd length
if (block.Size % 2) != 0 {
n, err = io.ReadFull(r, []byte{0})
bytesRead += uint32(n)
if err != nil {
return nil, bytesRead, err
}
}
return block, bytesRead, nil
}