Skip to content

Commit 17d2336

Browse files
authored
Added base64 library with encoders/decoders and json encoders/decoders (#31)
* To prep for json/yaml encoder/decoder, write wrappers for golang io to lua's file. * Add json.Encoder and Decoder - mainly so that (A) decode could be done from file, and (B) encoding could do pretty printing by setting the indentation. * Added strings.Reader and strings.Builder support. * Add a test for pretty printing. * Minor style fix * Add examples in READMEs * Added more tests for reading and writing multiple values. * Add comment for CheckIOReader and CheckIOWriter. * Use os.ModePerm; not fs.ModePerm. * 2001 (one millisecond over 2s) is too slim a margin; bumping to 3.001s. * Just a small adjustment to convert to []byte (in case encoding unfurls to lareger size than the size of unicode string) * Check possible error in encode. * Add a base64 module from the golang's encoding/base64 encodings. * Set example for encode to not bother with err. * Also adjust tests to not get/check err when not returned. * Add TODO for the other PR. * Added preload for base64. * Combine base64 work with encoders so that the io stuff could be shared. * Added test for reading a count. * Added ioutil.copy as well. * Remove TODOs as they were done. * Use return of copy as n (num bytes) * Added more to the readme. * Add README and test for strings reader and builder string(). * Update README to use `:` method. Co-authored-by: Sheridan C Rawlins <[email protected]>
1 parent e5c9db4 commit 17d2336

36 files changed

+1725
-35
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ go get github.com/vadv/gopher-lua-libs
1616

1717
## Index
1818

19+
* [base64](/base64) [encoding/base64](https://pkg.go.dev/encoding/base64) api
1920
* [cloudwatch](/aws/cloudwatch) aws cloudwatch log access
2021
* [cert_util](/cert_util) monitoring ssl certs
2122
* [chef](/chef) chef client api

base64/README.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# base64 [![GoDoc](https://godoc.org/github.com/vadv/gopher-lua-libs/base64?status.svg)](https://godoc.org/github.com/vadv/gopher-lua-libs/base64)
2+
3+
Lua module for [encoding/base64](https://pkg.go.dev/encoding/base64)
4+
5+
## Usage
6+
7+
### Encoding
8+
9+
```lua
10+
local base64 = require("base64")
11+
12+
s = base64.RawStdEncoding:encode_to_string("foo\01bar")
13+
print(s)
14+
Zm9vAWJhcg
15+
16+
s = base64.StdEncoding:encode_to_string("foo\01bar")
17+
print(s)
18+
Zm9vAWJhcg==
19+
20+
s = base64.RawURLEncoding:encode_to_string("this is a <tag> and should be encoded")
21+
print(s)
22+
dGhpcyBpcyBhIDx0YWc-IGFuZCBzaG91bGQgYmUgZW5jb2RlZA
23+
24+
s = base64.URLEncoding:encode_to_string("this is a <tag> and should be encoded")
25+
print(s)
26+
dGhpcyBpcyBhIDx0YWc-IGFuZCBzaG91bGQgYmUgZW5jb2RlZA==
27+
28+
```
29+
30+
### Decoding
31+
32+
```lua
33+
local base64 = require("base64")
34+
35+
s, err = base64.RawStdEncoding:decode_string("Zm9vAWJhcg")
36+
assert(not err, err)
37+
print(s)
38+
foobar
39+
40+
s, err = base64.StdEncoding:decode_string("Zm9vAWJhcg==")
41+
assert(not err, err)
42+
print(s)
43+
foobar
44+
45+
s, err = base64.RawURLEncoding:decode_string("dGhpcyBpcyBhIDx0YWc-IGFuZCBzaG91bGQgYmUgZW5jb2RlZA")
46+
assert(not err, err)
47+
print(s)
48+
this is a <tag> and should be encoded
49+
50+
s, err = base64.URLEncoding:decode_string("dGhpcyBpcyBhIDx0YWc-IGFuZCBzaG91bGQgYmUgZW5jb2RlZA==")
51+
assert(not err, err)
52+
print(s)
53+
this is a <tag> and should be encoded
54+
```

base64/api.go

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
// Package base64 implements base64 encode/decode functionality for lua.
2+
package base64
3+
4+
import (
5+
"encoding/base64"
6+
lio "github.com/vadv/gopher-lua-libs/io"
7+
lua "github.com/yuin/gopher-lua"
8+
"io"
9+
)
10+
11+
const (
12+
base64EncodingType = "base64.Encoding"
13+
base64EncoderType = "base64.Encoder"
14+
base64DecoderType = "base64.Decoder"
15+
)
16+
17+
//CheckBase64Encoding checks the argument at position n is a *base64.Encoding
18+
func CheckBase64Encoding(L *lua.LState, n int) *base64.Encoding {
19+
ud := L.CheckUserData(n)
20+
if encoding, ok := ud.Value.(*base64.Encoding); ok {
21+
return encoding
22+
}
23+
L.ArgError(n, base64EncodingType+" expected")
24+
return nil
25+
}
26+
27+
//LVBase64Encoding converts encoding to a UserData type for lua
28+
func LVBase64Encoding(L *lua.LState, encoding *base64.Encoding) lua.LValue {
29+
ud := L.NewUserData()
30+
ud.Value = encoding
31+
L.SetMetatable(ud, L.GetTypeMetatable(base64EncodingType))
32+
return ud
33+
}
34+
35+
func LVBase64Encoder(L *lua.LState, writer io.Writer) lua.LValue {
36+
ud := L.NewUserData()
37+
ud.Value = writer
38+
L.SetMetatable(ud, L.GetTypeMetatable(base64EncoderType))
39+
return ud
40+
}
41+
42+
func LVBase64Decoder(L *lua.LState, reader io.Reader) lua.LValue {
43+
ud := L.NewUserData()
44+
ud.Value = reader
45+
L.SetMetatable(ud, L.GetTypeMetatable(base64DecoderType))
46+
return ud
47+
}
48+
49+
//DecodeString decodes the encoded string with the encoding
50+
func DecodeString(L *lua.LState) int {
51+
encoding := CheckBase64Encoding(L, 1)
52+
encoded := L.CheckString(2)
53+
L.Pop(L.GetTop())
54+
decoded, err := encoding.DecodeString(encoded)
55+
if err != nil {
56+
L.Push(lua.LNil)
57+
L.Push(lua.LString(err.Error()))
58+
return 2
59+
}
60+
L.Push(lua.LString(decoded))
61+
return 1
62+
}
63+
64+
//EncodeToString decodes the string with the encoding
65+
func EncodeToString(L *lua.LState) int {
66+
encoding := CheckBase64Encoding(L, 1)
67+
decoded := L.CheckString(2)
68+
L.Pop(L.GetTop())
69+
encoded := encoding.EncodeToString([]byte(decoded))
70+
L.Push(lua.LString(encoded))
71+
return 1
72+
}
73+
74+
//registerBase64Encoding Registers the encoding type and its methods
75+
func registerBase64Encoding(L *lua.LState) {
76+
mt := L.NewTypeMetatable(base64EncodingType)
77+
L.SetField(mt, "__index", L.SetFuncs(L.NewTable(), map[string]lua.LGFunction{
78+
"decode_string": DecodeString,
79+
"encode_to_string": EncodeToString,
80+
}))
81+
}
82+
83+
//registerBase64Encoder Registers the encoder type and its methods
84+
func registerBase64Encoder(L *lua.LState) {
85+
mt := L.NewTypeMetatable(base64EncoderType)
86+
L.SetGlobal(base64EncoderType, mt)
87+
L.SetField(mt, "__index", lio.WriterFuncTable(L))
88+
}
89+
90+
//registerBase64Decoder Registers the decoder type and its methods
91+
func registerBase64Decoder(L *lua.LState) {
92+
mt := L.NewTypeMetatable(base64DecoderType)
93+
L.SetGlobal(base64DecoderType, mt)
94+
L.SetField(mt, "__index", lio.ReaderFuncTable(L))
95+
}
96+
97+
func NewEncoding(L *lua.LState) int {
98+
encoder := L.CheckString(1)
99+
if len(encoder) != 64 {
100+
L.ArgError(1, "encoder must have 64 characters")
101+
return 0
102+
}
103+
L.Pop(L.GetTop())
104+
105+
encoding := base64.NewEncoding(encoder)
106+
L.Push(LVBase64Encoding(L, encoding))
107+
return 1
108+
}
109+
110+
func NewEncoder(L *lua.LState) int {
111+
encoding := CheckBase64Encoding(L, 1)
112+
writer := lio.CheckIOWriter(L, 2)
113+
L.Pop(L.GetTop())
114+
encoder := base64.NewEncoder(encoding, writer)
115+
L.Push(LVBase64Encoder(L, encoder))
116+
return 1
117+
}
118+
119+
func NewDecoder(L *lua.LState) int {
120+
encoding := CheckBase64Encoding(L, 1)
121+
reader := lio.CheckIOReader(L, 2)
122+
L.Pop(L.GetTop())
123+
decoder := base64.NewDecoder(encoding, reader)
124+
L.Push(LVBase64Decoder(L, decoder))
125+
return 1
126+
}

base64/api_test.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package base64
2+
3+
import (
4+
"github.com/stretchr/testify/assert"
5+
"github.com/vadv/gopher-lua-libs/strings"
6+
"github.com/vadv/gopher-lua-libs/tests"
7+
"testing"
8+
)
9+
10+
func TestApi(t *testing.T) {
11+
preload := tests.SeveralPreloadFuncs(Preload, strings.Preload)
12+
assert.NotZero(t, tests.RunLuaTestFile(t, preload, "./test/test_api.lua"))
13+
}

base64/example_test.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package base64
2+
3+
import (
4+
"log"
5+
6+
lua "github.com/yuin/gopher-lua"
7+
)
8+
9+
func ExampleEncodeToString() {
10+
state := lua.NewState()
11+
defer state.Close()
12+
Preload(state)
13+
source := `
14+
local base64 = require("base64")
15+
s = base64.RawStdEncoding:encode_to_string("foo\01bar")
16+
print(s)
17+
18+
s = base64.StdEncoding:encode_to_string("foo\01bar")
19+
print(s)
20+
21+
s = base64.RawURLEncoding:encode_to_string("this is a <tag> and should be encoded")
22+
print(s)
23+
24+
s = base64.URLEncoding:encode_to_string("this is a <tag> and should be encoded")
25+
print(s)
26+
27+
`
28+
if err := state.DoString(source); err != nil {
29+
log.Fatal(err.Error())
30+
}
31+
// Output:
32+
// Zm9vAWJhcg
33+
// Zm9vAWJhcg==
34+
// dGhpcyBpcyBhIDx0YWc-IGFuZCBzaG91bGQgYmUgZW5jb2RlZA
35+
// dGhpcyBpcyBhIDx0YWc-IGFuZCBzaG91bGQgYmUgZW5jb2RlZA==
36+
}
37+
38+
func ExampleDecodeString() {
39+
state := lua.NewState()
40+
defer state.Close()
41+
Preload(state)
42+
source := `
43+
local base64 = require("base64")
44+
s, err = base64.RawStdEncoding:decode_string("Zm9vAWJhcg")
45+
assert(not err, err)
46+
print(s)
47+
48+
s, err = base64.StdEncoding:decode_string("Zm9vAWJhcg==")
49+
assert(not err, err)
50+
print(s)
51+
52+
s, err = base64.RawURLEncoding:decode_string("dGhpcyBpcyBhIDx0YWc-IGFuZCBzaG91bGQgYmUgZW5jb2RlZA")
53+
assert(not err, err)
54+
print(s)
55+
56+
s, err = base64.URLEncoding:decode_string("dGhpcyBpcyBhIDx0YWc-IGFuZCBzaG91bGQgYmUgZW5jb2RlZA==")
57+
assert(not err, err)
58+
print(s)
59+
60+
`
61+
if err := state.DoString(source); err != nil {
62+
log.Fatal(err.Error())
63+
}
64+
// Output:
65+
// foobar
66+
// foobar
67+
// this is a <tag> and should be encoded
68+
// this is a <tag> and should be encoded
69+
}

base64/loader.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package base64
2+
3+
import (
4+
"encoding/base64"
5+
lua "github.com/yuin/gopher-lua"
6+
)
7+
8+
// Preload adds yaml to the given Lua state's package.preload table. After it
9+
// has been preloaded, it can be loaded using require:
10+
//
11+
// local yaml = require("yaml")
12+
func Preload(L *lua.LState) {
13+
L.PreloadModule("base64", Loader)
14+
}
15+
16+
// Loader is the module loader function.
17+
func Loader(L *lua.LState) int {
18+
registerBase64Encoding(L)
19+
registerBase64Encoder(L)
20+
registerBase64Decoder(L)
21+
22+
// Register the encodings offered by base64 go module.
23+
t := L.NewTable()
24+
L.SetField(t, "RawStdEncoding", LVBase64Encoding(L, base64.RawStdEncoding))
25+
L.SetField(t, "RawURLEncoding", LVBase64Encoding(L, base64.RawURLEncoding))
26+
L.SetField(t, "StdEncoding", LVBase64Encoding(L, base64.StdEncoding))
27+
L.SetField(t, "URLEncoding", LVBase64Encoding(L, base64.URLEncoding))
28+
L.SetFuncs(t, map[string]lua.LGFunction{
29+
"new_encoding": NewEncoding,
30+
"new_encoder": NewEncoder,
31+
"new_decoder": NewDecoder,
32+
})
33+
L.Push(t)
34+
return 1
35+
}

0 commit comments

Comments
 (0)