forked from akavel/rsrc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
rsrc.go
104 lines (90 loc) · 3.08 KB
/
rsrc.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
package main
import (
"flag"
"fmt"
"io"
"os"
"regexp"
"strings"
"github.com/akavel/rsrc/coff"
"github.com/akavel/rsrc/binutil"
"github.com/akavel/rsrc/internal"
"github.com/akavel/rsrc/rsrc"
)
var usage = `USAGE:
%s [-manifest FILE.exe.manifest] [-ico FILE.ico[,FILE2.ico...]] -o FILE.syso
Generates a .syso file with specified resources embedded in .rsrc section,
aimed for consumption by Go linker when building Win32 excecutables.
The generated *.syso files should get automatically recognized by 'go build'
command and linked into an executable/library, as long as there are any *.go
files in the same directory.
OPTIONS:
`
func main() {
//TODO: allow in options advanced specification of multiple resources, as a tree (json?)
//FIXME: verify that data file size doesn't exceed uint32 max value
var fnamein, fnameico, fnamedata, fnameout, arch string
flags := flag.NewFlagSet("", flag.ContinueOnError)
flags.StringVar(&fnamein, "manifest", "", "path to a Windows manifest file to embed")
flags.StringVar(&fnameico, "ico", "", "comma-separated list of paths to .ico files to embed")
flags.StringVar(&fnamedata, "data", "", "path to raw data file to embed [WARNING: useless for Go 1.4+]")
flags.StringVar(&fnameout, "o", "rsrc.syso", "name of output COFF (.res or .syso) file")
flags.StringVar(&arch, "arch", "386", "architecture of output file - one of: 386, [EXPERIMENTAL: amd64]")
_ = flags.Parse(os.Args[1:])
if fnameout == "" || (fnamein == "" && fnamedata == "" && fnameico == "") {
fmt.Fprintf(os.Stderr, usage, os.Args[0])
flags.PrintDefaults()
os.Exit(1)
}
var err error
switch {
case fnamein != "" || fnameico != "":
err = rsrc.Embed(fnameout, arch, fnamein, fnameico)
case fnamedata != "":
err = embedData(fnameout, arch, fnamedata)
}
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
func embedData(fnameout, arch, fnamedata string) error {
if !strings.HasSuffix(fnameout, ".syso") {
return fmt.Errorf("Output file name '%s' must end with '.syso'", fnameout)
}
symname := strings.TrimSuffix(fnameout, ".syso")
ok, err := regexp.MatchString(`^[a-z0-9_]+$`, symname)
if err != nil {
return fmt.Errorf("Internal error: %s", err)
}
if !ok {
return fmt.Errorf("Output file name '%s' must be composed of only lowercase letters (a-z), digits (0-9) and underscore (_)", fnameout)
}
dat, err := binutil.SizedOpen(fnamedata)
if err != nil {
return fmt.Errorf("Error opening data file '%s': %s", fnamedata, err)
}
defer dat.Close()
coff := coff.NewRDATA()
err = coff.Arch(arch)
if err != nil {
return err
}
coff.AddData("_brsrc_"+symname, dat)
coff.AddData("_ersrc_"+symname, io.NewSectionReader(strings.NewReader("\000\000"), 0, 2)) // TODO: why? copied from as-generated
coff.Freeze()
err = internal.Write(coff, fnameout)
if err != nil {
return err
}
//FIXME: output a .c file
fmt.Println(strings.Replace(`#include "runtime.h"
extern byte _brsrc_NAME[], _ersrc_NAME;
/* func get_NAME() []byte */
void ·get_NAME(Slice a) {
a.array = _brsrc_NAME;
a.len = a.cap = &_ersrc_NAME - _brsrc_NAME;
FLUSH(&a);
}`, "NAME", symname, -1))
return nil
}