-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcrc.go
98 lines (80 loc) · 1.87 KB
/
crc.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
package megasd
import (
"bytes"
"errors"
"fmt"
"hash/crc32"
"io"
"os"
"path/filepath"
"github.com/vchimishuk/chub/cue"
)
const (
sectorHeader = 16
sectorSize = 2048
sectorTrailer = 288
)
func firstDataTrack(sheet *cue.Sheet) (string, cue.TrackDataType, error) {
for _, file := range sheet.Files {
for _, track := range file.Tracks {
switch track.DataType {
case cue.DataTypeMode1_2048, cue.DataTypeMode1_2352:
return file.Name, track.DataType, nil
}
}
}
return "", cue.DataTypeAudio, errors.New("audio-only CDs are not supported for hashing")
}
func crcCueFile(file string) (string, error) {
sheet, err := cue.ParseFile(file)
if err != nil {
return "", err
}
fileName, dataType, err := firstDataTrack(sheet)
if err != nil {
return "", nil
}
f, err := os.Open(filepath.Join(filepath.Dir(file), fileName))
if err != nil {
return "", nil
}
defer f.Close()
if dataType == cue.DataTypeMode1_2352 {
if _, err := f.Seek(sectorHeader, os.SEEK_CUR); err != nil {
return "", nil
}
}
h := crc32.NewIEEE()
var b bytes.Buffer
if _, err := io.CopyN(io.MultiWriter(h, &b), f, sectorSize); err != nil {
return "", nil
}
if bytes.Compare(b.Bytes()[0x100:0x104], []byte{'S', 'E', 'G', 'A'}) != 0 {
return "", errors.New("invalid signature")
}
if dataType == cue.DataTypeMode1_2352 {
if _, err := f.Seek(sectorTrailer, os.SEEK_CUR); err != nil {
return "", nil
}
}
return fmt.Sprintf("%.*X", crc32.Size<<1, h.Sum(nil)), nil
}
func crcFile(file string) (string, error) {
f, err := os.Open(file)
if err != nil {
return "", err
}
defer f.Close()
info, err := f.Stat()
if err != nil {
return "", err
}
if _, err = f.Seek(info.Size()&0xfff, os.SEEK_CUR); err != nil {
return "", nil
}
h := crc32.NewIEEE()
if _, err = io.Copy(h, f); err != nil {
return "", err
}
return fmt.Sprintf("%.*X", crc32.Size<<1, h.Sum(nil)), nil
}