replace zxq.co/ripple/hanayo

This commit is contained in:
Alicia
2019-02-23 13:29:15 +00:00
commit c3d206c173
5871 changed files with 1353715 additions and 0 deletions

2
vendor/github.com/frustra/bbcode/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,2 @@
/bbcode
/bbcode.test

3
vendor/github.com/frustra/bbcode/.travis.yml generated vendored Normal file
View File

@@ -0,0 +1,3 @@
language: go
go: 1.2
script: go test -v

19
vendor/github.com/frustra/bbcode/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,19 @@
Copyright (C) 2015 Frustra.
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

123
vendor/github.com/frustra/bbcode/README.md generated vendored Normal file
View File

@@ -0,0 +1,123 @@
# bbcode [![Build Status](https://travis-ci.org/frustra/bbcode.png?branch=master)](http://travis-ci.org/frustra/bbcode)
frustra/bbcode is a fast BBCode compiler for Go. It supports custom tags, safe html output (for user-specified input),
and allows for graceful parsing of syntax errors similar to the output of a regex bbcode compiler.
Visit the godoc here: [http://godoc.org/github.com/frustra/bbcode](http://godoc.org/github.com/frustra/bbcode)
## Usage
To get started compiling some text, create a compiler instance:
```go
compiler := bbcode.NewCompiler(true, true) // autoCloseTags, ignoreUnmatchedClosingTags
fmt.Println(compiler.Compile("[b]Hello World[/b]"))
// Output:
// <b>Hello World</b>
```
## Supported BBCode Syntax
```
[tag]basic tag[/tag]
[tag1][tag2]nested tags[/tag2][/tag1]
[tag=value]tag with value[/tag]
[tag arg=value]tag with named argument[/tag]
[tag="quote value"]tag with quoted value[/tag]
[tag=value foo="hello world" bar=baz]multiple tag arguments[/tag]
```
## Default Tags
* `[b]text[/b]` --> `<b>text</b>` (b, i, u, and s all map the same)
* `[url]link[/url]` --> `<a href="link">link</a>`
* `[url=link]text[/url]` --> `<a href="link">text</a>`
* `[img]link[/img]` --> `<img src="link">`
* `[img=link]alt[/img]` --> `<img alt="alt" title="alt" src="link">`
* `[center]text[/center]` --> `<div style="text-align: center;">text</div>`
* `[color=red]text[/color]` --> `<span style="color: red;">text</span>`
* `[size=2]text[/size]` --> `<span class="size2">text</span>`
* `[quote]text[/quote]` --> `<blockquote><cite>Quote</cite>text</blockquote>`
* `[quote=Somebody]text[/quote]` --> `<blockquote><cite>Somebody said:</cite>text</blockquote>`
* `[quote name=Somebody]text[/quote]` --> `<blockquote><cite>Somebody said:</cite>text</blockquote>`
* `[code][b]anything[/b][/code]` --> `<pre>[b]anything[/b]</pre>`
Lists are not currently implemented as a default tag, but can be added as a custom tag.
A working implementation of list tags can be found [here](https://gist.github.com/xthexder/44f4b9cec3ed7876780d)
## Adding Custom Tags
Custom tag handlers can be added to a compiler using the `compiler.SetTag(tag, handler)` function:
```go
compiler.SetTag("center", func(node *bbcode.BBCodeNode) (*bbcode.HTMLTag, bool) {
// Create a new div element to output
out := bbcode.NewHTMLTag("")
out.Name = "div"
// Set the style attribute of our output div
out.Attrs["style"] = "text-align: center;"
// Returning true here means continue to parse child nodes.
// This should be false if children are parsed by this tag's handler, like in the [code] tag.
return out, true
})
```
Tag values can be read from the opening tag like this:
Main tag value `[tag={value}]`: `node.GetOpeningTag().Value`
Tag arguments `[tag name={value}]`: `node.GetOpeningTag().Args["name"]`
`bbcode.NewHTMLTag(text)` creates a text node by default. By setting `tag.Name`, the node because an html tag prefixed by the text. The closing html tag is not rendered unless child elements exist. The closing tag can be forced by adding a blank text node:
```go
out := bbcode.NewHTMLTag("")
out.Name = "div"
out.AppendChild(nil) // equivalent to out.AppendChild(bbcode.NewHTMLTag(""))
```
For more examples of tag definitions, look at the default tag implementations in [compiler.go](https://github.com/frustra/bbcode/blob/master/compiler.go)
## Overriding Default Tags
The built-in tags can be overridden simply by redefining the tag with `compiler.SetTag(tag, handler)`
To remove a tag, set the tag handler to nil:
```go
compiler.SetTag("quote", nil)
```
The default tags can also be modified without completely redefining the tag by calling the default handler:
```go
compiler.SetTag("url", func(node *bbcode.BBCodeNode) (*bbcode.HTMLTag, bool) {
out, appendExpr := bbcode.DefaultTagCompilers["url"](node)
out.Attrs["class"] = "bbcode-link"
return out, appendExpr
})
```
## Auto-Close Tags
Input:
```
[center][b]text[/center]
```
Enabled Output:
```html
<div style="text-align: center;"><b>text</b></div>
```
Disabled Output:
```html
<div style="text-align: center;">[b]text</div>
```
## Ignore Unmatched Closing Tags
Input:
```
[center]text[/b][/center]
```
Enabled Output:
```html
<div style="text-align: center;">text</div>
```
Disabled Output:
```html
<div style="text-align: center;">text[/b]</div>
```

42
vendor/github.com/frustra/bbcode/bbcode.go generated vendored Normal file
View File

@@ -0,0 +1,42 @@
// Copyright 2015 Frustra. All rights reserved.
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.
// Package bbcode implements a parser and HTML generator for BBCode.
package bbcode
import "sort"
type BBOpeningTag struct {
Name string
Value string
Args map[string]string
Raw string
}
type BBClosingTag struct {
Name string
Raw string
}
func (t *BBOpeningTag) String() string {
str := t.Name
if len(t.Value) > 0 {
str += "=" + t.Value
}
keys := make([]string, len(t.Args))
i := 0
for key := range t.Args {
keys[i] = key
i++
}
sort.Strings(keys)
for _, key := range keys {
v := t.Args[key]
str += " " + key
if len(v) > 0 {
str += "=" + v
}
}
return str
}

16
vendor/github.com/frustra/bbcode/cmd/bbcode/main.go generated vendored Normal file
View File

@@ -0,0 +1,16 @@
package main
import (
"bufio"
"fmt"
"github.com/frustra/bbcode"
"os"
)
func main() {
compiler := bbcode.NewCompiler(true, true)
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
fmt.Println(compiler.Compile(scanner.Text()))
}
}

256
vendor/github.com/frustra/bbcode/compiler.go generated vendored Normal file
View File

@@ -0,0 +1,256 @@
// Copyright 2015 Frustra. All rights reserved.
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.
package bbcode
import (
"fmt"
"strconv"
"strings"
)
type TagCompilerFunc func(*BBCodeNode) (*HTMLTag, bool)
type Compiler struct {
tagCompilers map[string]TagCompilerFunc
defaultCompiler TagCompilerFunc
AutoCloseTags bool
IgnoreUnmatchedClosingTags bool
}
func NewCompiler(autoCloseTags, ignoreUnmatchedClosingTags bool) Compiler {
compiler := Compiler{make(map[string]TagCompilerFunc), DefaultTagCompiler, autoCloseTags, ignoreUnmatchedClosingTags}
for tag, compilerFunc := range DefaultTagCompilers {
compiler.SetTag(tag, compilerFunc)
}
return compiler
}
func (c Compiler) Compile(str string) string {
tokens := Lex(str)
tree := Parse(tokens)
return c.CompileTree(tree).String()
}
func (c Compiler) SetDefault(compiler TagCompilerFunc) {
if compiler == nil {
panic("Default tag compiler can't be nil")
} else {
c.defaultCompiler = compiler
}
}
func (c Compiler) SetTag(tag string, compiler TagCompilerFunc) {
if compiler == nil {
delete(c.tagCompilers, tag)
} else {
c.tagCompilers[tag] = compiler
}
}
// CompileTree transforms BBCodeNode into an HTML tag.
func (c Compiler) CompileTree(node *BBCodeNode) *HTMLTag {
var out = NewHTMLTag("")
if node.ID == TEXT {
out.Value = node.Value.(string)
InsertNewlines(out)
for _, child := range node.Children {
out.AppendChild(c.CompileTree(child))
}
} else if node.ID == CLOSING_TAG {
if !c.IgnoreUnmatchedClosingTags {
out.Value = node.Value.(BBClosingTag).Raw
InsertNewlines(out)
}
for _, child := range node.Children {
out.AppendChild(c.CompileTree(child))
}
} else if node.ClosingTag == nil && !c.AutoCloseTags {
out.Value = node.Value.(BBOpeningTag).Raw
InsertNewlines(out)
for _, child := range node.Children {
out.AppendChild(c.CompileTree(child))
}
} else {
in := node.GetOpeningTag()
compileFunc, ok := c.tagCompilers[in.Name]
if !ok {
compileFunc = c.defaultCompiler
}
var appendExpr bool
node.Compiler = &c
out, appendExpr = compileFunc(node)
if appendExpr {
if len(node.Children) == 0 {
out.AppendChild(NewHTMLTag(""))
} else {
for _, child := range node.Children {
out.AppendChild(c.CompileTree(child))
}
}
}
}
return out
}
func CompileText(in *BBCodeNode) string {
out := ""
if in.ID == TEXT {
out = in.Value.(string)
}
for _, child := range in.Children {
out += CompileText(child)
}
return out
}
func CompileRaw(in *BBCodeNode) *HTMLTag {
out := NewHTMLTag("")
if in.ID == TEXT {
out.Value = in.Value.(string)
} else if in.ID == CLOSING_TAG {
out.Value = in.Value.(BBClosingTag).Raw
} else {
out.Value = in.Value.(BBOpeningTag).Raw
}
for _, child := range in.Children {
out.AppendChild(CompileRaw(child))
}
if in.ID == OPENING_TAG && in.ClosingTag != nil {
tag := NewHTMLTag(in.ClosingTag.Raw)
out.AppendChild(tag)
}
return out
}
var DefaultTagCompilers map[string]TagCompilerFunc
var DefaultTagCompiler TagCompilerFunc
func init() {
DefaultTagCompiler = func(node *BBCodeNode) (*HTMLTag, bool) {
out := NewHTMLTag(node.GetOpeningTag().Raw)
InsertNewlines(out)
if len(node.Children) == 0 {
out.AppendChild(NewHTMLTag(""))
} else {
for _, child := range node.Children {
out.AppendChild(node.Compiler.CompileTree(child))
}
}
if node.ClosingTag != nil {
tag := NewHTMLTag(node.ClosingTag.Raw)
InsertNewlines(tag)
out.AppendChild(tag)
}
return out, false
}
DefaultTagCompilers = make(map[string]TagCompilerFunc)
DefaultTagCompilers["url"] = func(node *BBCodeNode) (*HTMLTag, bool) {
out := NewHTMLTag("")
out.Name = "a"
value := node.GetOpeningTag().Value
if value == "" {
text := CompileText(node)
if len(text) > 0 {
out.Attrs["href"] = ValidURL(text)
}
} else {
out.Attrs["href"] = ValidURL(value)
}
return out, true
}
DefaultTagCompilers["img"] = func(node *BBCodeNode) (*HTMLTag, bool) {
out := NewHTMLTag("")
out.Name = "img"
value := node.GetOpeningTag().Value
if value == "" {
out.Attrs["src"] = ValidURL(CompileText(node))
} else {
out.Attrs["src"] = ValidURL(value)
text := CompileText(node)
if len(text) > 0 {
out.Attrs["alt"] = text
out.Attrs["title"] = out.Attrs["alt"]
}
}
return out, false
}
DefaultTagCompilers["center"] = func(node *BBCodeNode) (*HTMLTag, bool) {
out := NewHTMLTag("")
out.Name = "div"
out.Attrs["style"] = "text-align: center;"
return out, true
}
DefaultTagCompilers["color"] = func(node *BBCodeNode) (*HTMLTag, bool) {
out := NewHTMLTag("")
out.Name = "span"
sanitize := func(r rune) rune {
if r == '#' || r == ',' || r == '.' || r == '(' || r == ')' || r == '%' {
return r
} else if r >= '0' && r <= '9' {
return r
} else if r >= 'a' && r <= 'z' {
return r
} else if r >= 'A' && r <= 'Z' {
return r
}
return -1
}
color := strings.Map(sanitize, node.GetOpeningTag().Value)
out.Attrs["style"] = "color: " + color + ";"
return out, true
}
DefaultTagCompilers["size"] = func(node *BBCodeNode) (*HTMLTag, bool) {
out := NewHTMLTag("")
out.Name = "span"
if size, err := strconv.Atoi(node.GetOpeningTag().Value); err == nil {
out.Attrs["class"] = fmt.Sprintf("size%d", size)
}
return out, true
}
DefaultTagCompilers["quote"] = func(node *BBCodeNode) (*HTMLTag, bool) {
out := NewHTMLTag("")
out.Name = "blockquote"
who := ""
in := node.GetOpeningTag()
if name, ok := in.Args["name"]; ok && name != "" {
who = name
} else {
who = in.Value
}
cite := NewHTMLTag("")
cite.Name = "cite"
if who != "" {
cite.AppendChild(NewHTMLTag(who + " said:"))
} else {
cite.AppendChild(NewHTMLTag("Quote"))
}
return out.AppendChild(cite), true
}
DefaultTagCompilers["code"] = func(node *BBCodeNode) (*HTMLTag, bool) {
out := NewHTMLTag("")
out.Name = "pre"
for _, child := range node.Children {
out.AppendChild(CompileRaw(child))
}
return out, false
}
for _, tag := range []string{"i", "b", "u", "s"} {
DefaultTagCompilers[tag] = func(node *BBCodeNode) (*HTMLTag, bool) {
out := NewHTMLTag("")
out.Name = node.GetOpeningTag().Name
return out, true
}
}
}

221
vendor/github.com/frustra/bbcode/compiler_test.go generated vendored Normal file
View File

@@ -0,0 +1,221 @@
// Copyright 2015 Frustra. All rights reserved.
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.
package bbcode
import (
"strings"
"testing"
)
var fullTestInput = `the quick brown [b]fox[/b]:
[url=http://example][img]http://example.png[/img][/url]`
var fullTestOutput = `the quick brown <b>fox</b>:<br><a href="http://example"><img src="http://example.png"></a>`
func TestFullBasic(t *testing.T) {
c := NewCompiler(false, false)
input := fullTestInput
output := fullTestOutput
for in, out := range basicTests {
input += in
output += out
}
result := c.Compile(input)
if result != output {
t.Errorf("Failed to compile %s.\nExpected: %s, got: %s\n", input, output, result)
}
}
func BenchmarkFullBasic(b *testing.B) {
c := NewCompiler(false, false)
input := fullTestInput
for in := range basicTests {
input += in
}
b.SetBytes(int64(len(input)))
b.ReportAllocs()
for i := 0; i < b.N; i++ {
c.Compile(input)
}
}
var basicTests = map[string]string{
``: ``,
`[url]http://example.com[/url]`: `<a href="http://example.com">http://example.com</a>`,
`[img]http://example.com[/img]`: `<img src="http://example.com">`,
`[img][/img]`: `<img src="">`,
`[url=http://example.com]example[/url]`: `<a href="http://example.com">example</a>`,
`[img=http://example.com][/img]`: `<img src="http://example.com">`,
`[B]bold[/b]`: `<b>bold</b>`,
`[i]italic[/i]`: `<i>italic</i>`,
`[u]underline[/U]`: `<u>underline</u>`,
`[s]strikethrough[/s]`: `<s>strikethrough</s>`,
`[u][b]something[/b] then [b]something else[/b][/u]`: `<u><b>something</b> then <b>something else</b></u>`,
`blank[b][/b]`: `blank<b></b>`,
"test\nnewline\nnewline": `test<br>newline<br>newline`,
"test\n\nnewline": `test<br><br>newline`,
"[b]test[/b]\n\nnewline": `<b>test</b><br><br>newline`,
"[b]test\nnewline[/b]": `<b>test<br>newline</b>`,
"[code][b]some[/b]\n[i]stuff[/i]\n[/quote][/code][b]more[/b]": "<pre>[b]some[/b]\n[i]stuff[/i]\n[/quote]</pre><b>more</b>",
"[quote name=Someguy]hello[/quote]": `<blockquote><cite>Someguy said:</cite>hello</blockquote>`,
"[center]hello[/center]": `<div style="text-align: center;">hello</div>`,
"[size=6]hello[/size]": `<span class="size6">hello</span>`,
"[center][b][color=#00BFFF][size=6]hello[/size][/color][/b][/center]": `<div style="text-align: center;"><b><span style="color: #00BFFF;"><span class="size6">hello</span></span></b></div>`,
`[not a tag][/not ]`: `[not a tag][/not ]`,
`[not a tag]`: `[not a tag]`,
}
var basicMultiArgTests = map[string][]string{
`[img=http://example.com]alt text[/img]`: []string{`<img`, ` src="http://example.com"`, ` alt="alt text"`, ` title="alt text"`, `>`},
`[img = foo]bar[/img]`: []string{`<img`, ` src="foo"`, ` alt="bar"`, ` title="bar"`, `>`},
}
func TestCompile(t *testing.T) {
c := NewCompiler(false, false)
for in, out := range basicTests {
result := c.Compile(in)
if result != out {
t.Errorf("Failed to compile %s.\nExpected: %s, got: %s\n", in, out, result)
}
}
for in, out := range basicMultiArgTests {
result := c.Compile(in)
if !strings.HasPrefix(result, out[0]) || !strings.HasSuffix(result, out[len(out)-1]) {
t.Errorf("Failed to compile %s.\nExpected: %s, got: %s\n", in, out, result)
}
for i := 1; i < len(out)-1; i++ {
if !strings.Contains(result, out[i]) {
t.Errorf("Failed to compile %s.\nExpected: %s, got: %s\n", in, out, result)
}
}
}
}
var sanitizationTests = map[string]string{
`<script>`: `&lt;script&gt;`,
`[url]<script>[/url]`: `<a href="%3Cscript%3E">&lt;script&gt;</a>`,
`[url=<script>]<script>[/url]`: `<a href="%3Cscript%3E">&lt;script&gt;</a>`,
`[url=http://a.b/z?\]link[/url]`: `<a href="http://a.b/z?\">link</a>`,
}
var sanitizationMultiArgTests = map[string][]string{
`[img=<script>]<script>[/img]`: []string{`<img`, ` src="%3Cscript%3E"`, ` alt="&lt;script&gt;"`, ` title="&lt;script&gt;"`, `>`},
`[img="http://\"a.b/z"]"link"\[/img]`: []string{`<img`, ` src="http://&#34;a.b/z"`, ` alt="&#34;link&#34;\"`, ` title="&#34;link&#34;\"`, `>`},
}
func TestSanitization(t *testing.T) {
c := NewCompiler(false, false)
for in, out := range sanitizationTests {
result := c.Compile(in)
if result != out {
t.Errorf("Failed to compile %s.\nExpected: %s, got: %s\n", in, out, result)
}
}
for in, out := range sanitizationMultiArgTests {
result := c.Compile(in)
if !strings.HasPrefix(result, out[0]) || !strings.HasSuffix(result, out[len(out)-1]) {
t.Errorf("Failed to compile %s.\nExpected: %s, got: %s\n", in, out, result)
}
for i := 1; i < len(out)-1; i++ {
if !strings.Contains(result, out[i]) {
t.Errorf("Failed to compile %s.\nExpected: %s, got: %s\n", in, out, result)
}
}
}
}
func TestFullSanitization(t *testing.T) {
c := NewCompiler(false, false)
input := fullTestInput
output := fullTestOutput
for in, out := range sanitizationTests {
input += in
output += out
}
result := c.Compile(input)
if result != output {
t.Errorf("Failed to compile %s.\nExpected: %s, got: %s\n", input, output, result)
}
}
func BenchmarkFullSanitization(b *testing.B) {
c := NewCompiler(false, false)
input := fullTestInput
for in := range sanitizationTests {
input += in
}
b.SetBytes(int64(len(input)))
b.ReportAllocs()
for i := 0; i < b.N; i++ {
c.Compile(input)
}
}
var brokenTests = map[string]string{
"[b]": `[b]`,
"[b]\n": `[b]<br>`,
"[b]hello": `[b]hello`,
"[b]hello\n": `[b]hello<br>`,
"the quick brown [b][i]fox[/b][/i]\n[i]\n[b]hi[/b]][b][url=http://example[img]http://example.png[/img][/url][b]": `the quick brown <b>[i]fox</b>[/i]<br>[i]<br><b>hi</b>][b][url=http://example<img src="http://example.png">[/url][b]`,
"the quick brown[/b][b]hello[/b]": `the quick brown[/b]<b>hello</b>`,
"the quick brown[/b][/code]": `the quick brown[/b][/code]`,
"[ b][ i]the quick brown[/i][/b=hello]": `[ b]<i>the quick brown</i>[/b=hello]`,
"[b [herp@#$%]]the quick brown[/b]": `[b [herp@#$%]]the quick brown[/b]`,
"[b=hello a=hi q]the quick brown[/b]": `<b>the quick brown</b>`,
"[b]hi[": `[b]hi[`,
"[b hi=derp": `[b hi=derp`,
}
func TestBroken(t *testing.T) {
c := NewCompiler(false, false)
for in, out := range brokenTests {
result := c.Compile(in)
if result != out {
t.Errorf("Failed to compile %s.\nExpected: %s, got: %s\n", in, out, result)
}
}
}
func BenchmarkFullBroken(b *testing.B) {
c := NewCompiler(false, false)
input := fullTestInput
for in := range brokenTests {
input += in
}
b.SetBytes(int64(len(input)))
b.ReportAllocs()
for i := 0; i < b.N; i++ {
c.Compile(input)
}
}
var customTests = map[string]string{
`[img]//foo/bar.png[/img]`: `<img src="//custom.png">`,
`[url]//foo/bar.png[/url]`: `[url]//foo/bar.png[/url]`,
}
func compileImg(node *BBCodeNode) (*HTMLTag, bool) {
out, appendExpr := DefaultTagCompilers["img"](node)
out.Attrs["src"] = "//custom.png"
return out, appendExpr
}
func TestCompileCustom(t *testing.T) {
c := NewCompiler(false, false)
c.SetTag("url", nil)
c.SetTag("img", compileImg)
for in, out := range customTests {
result := c.Compile(in)
if result != out {
t.Errorf("Failed to compile %s.\nExpected: %s, got: %s\n", in, out, result)
}
}
}

94
vendor/github.com/frustra/bbcode/html.go generated vendored Normal file
View File

@@ -0,0 +1,94 @@
// Copyright 2015 Frustra. All rights reserved.
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.
package bbcode
import (
"html"
"net/url"
"strings"
)
// HTMLTag represents a DOM node.
type HTMLTag struct {
Name string
Value string
Attrs map[string]string
Children []*HTMLTag
}
// NewHTMLTag creates a new HTMLTag with string contents specified by value.
func NewHTMLTag(value string) *HTMLTag {
return &HTMLTag{
Value: value,
Attrs: make(map[string]string),
Children: make([]*HTMLTag, 0),
}
}
func (t *HTMLTag) String() string {
var value string
if len(t.Value) > 0 {
value = html.EscapeString(t.Value)
}
var attrString string
for key, value := range t.Attrs {
attrString += " " + key + `="` + strings.Replace(html.EscapeString(value), "\n", "", -1) + `"`
}
if len(t.Children) > 0 {
var childrenString string
for _, child := range t.Children {
childrenString += child.String()
}
if len(t.Name) > 0 {
return value + "<" + t.Name + attrString + ">" + childrenString + "</" + t.Name + ">"
} else {
return value + childrenString
}
} else if len(t.Name) > 0 {
return value + "<" + t.Name + attrString + ">"
} else {
return value
}
}
func (t *HTMLTag) AppendChild(child *HTMLTag) *HTMLTag {
if child == nil {
t.Children = append(t.Children, NewHTMLTag(""))
} else {
t.Children = append(t.Children, child)
}
return t
}
func InsertNewlines(out *HTMLTag) {
if strings.ContainsRune(out.Value, '\n') {
parts := strings.Split(out.Value, "\n")
for i, part := range parts {
if i == 0 {
out.Value = parts[i]
} else {
out.AppendChild(NewlineTag())
if len(part) > 0 {
out.AppendChild(NewHTMLTag(part))
}
}
}
}
}
// Returns a new HTMLTag representing a line break
func NewlineTag() *HTMLTag {
var out = NewHTMLTag("")
out.Name = "br"
return out
}
func ValidURL(raw string) string {
u, err := url.Parse(raw)
if err != nil {
return ""
}
return u.String()
}

24
vendor/github.com/frustra/bbcode/html_test.go generated vendored Normal file
View File

@@ -0,0 +1,24 @@
// Copyright 2015 Frustra. All rights reserved.
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.
package bbcode
import "testing"
var urlTests = map[string]string{
"http://example.com/path?query=value#fragment": "http://example.com/path?query=value#fragment",
"<script>http://example.com": "%3Cscript%3Ehttp://example.com",
"http://example.com/path?query=value#fragment<script>": "http://example.com/path?query=value#fragment%3Cscript%3E",
"http://example.com/path?query=<script>": "http://example.com/path?query=<script>",
"javascript:alert(1);": "javascript:alert(1);",
}
func TestValidURL(t *testing.T) {
for in, out := range urlTests {
result := ValidURL(in)
if result != out {
t.Errorf("Failed to sanitize %s.\nExpected: %s, got: %s", in, out, result)
}
}
}

260
vendor/github.com/frustra/bbcode/lexer.go generated vendored Normal file
View File

@@ -0,0 +1,260 @@
// Copyright 2015 Frustra. All rights reserved.
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.
package bbcode
import (
"bytes"
"strings"
)
type Token struct {
ID string
Value interface{}
}
type lexer struct {
input string
tokens chan Token
start int
end int
pos int
tagName string
tagValue string
tagTmpName string
tagTmpValue string
tagArgs map[string]string
}
const (
TEXT = "text"
OPENING_TAG = "opening"
CLOSING_TAG = "closing"
)
func newLexer(str string) *lexer {
return &lexer{
input: str,
tokens: make(chan Token),
}
}
func Lex(str string) chan Token {
lex := newLexer(str)
go lex.runStateMachine()
return lex.tokens
}
func (l *lexer) runStateMachine() {
for state := lexText; state != nil; {
state = state(l)
}
close(l.tokens)
}
func (l *lexer) emit(id string, value interface{}) {
if l.pos > 0 {
// fmt.Println(l.input)
// fmt.Printf("Emit %s: %+v\n", id, value)
l.tokens <- Token{id, value}
l.input = l.input[l.pos:]
l.pos = 0
}
}
type stateFn func(*lexer) stateFn
func lexText(l *lexer) stateFn {
for l.pos < len(l.input) {
if l.input[l.pos] == '[' {
l.emit(TEXT, l.input[:l.pos])
return lexOpenBracket
}
l.pos++
}
l.emit(TEXT, l.input)
return nil
}
func lexOpenBracket(l *lexer) stateFn {
l.pos++
closingTag := false
for l.pos < len(l.input) {
switch l.input[l.pos] {
case '[', ']':
return lexText
default:
if l.input[l.pos] == '/' && !closingTag {
closingTag = true
} else if l.input[l.pos] != ' ' && l.input[l.pos] != '\t' && l.input[l.pos] != '\n' {
if closingTag {
return lexClosingTag
} else {
l.tagName = ""
l.tagValue = ""
l.tagArgs = make(map[string]string)
return lexTagName
}
}
}
l.pos++
}
l.emit(TEXT, l.input)
return nil
}
func lexClosingTag(l *lexer) stateFn {
whiteSpace := false
l.start = l.pos
l.end = l.pos
for l.pos < len(l.input) {
switch l.input[l.pos] {
case '[':
return lexText
case ']':
l.pos++
l.emit(CLOSING_TAG, BBClosingTag{strings.ToLower(l.input[l.start:l.end]), l.input[:l.pos]})
return lexText
case ' ', '\t', '\n':
whiteSpace = true
default:
if whiteSpace {
return lexText
} else {
l.end++
}
}
l.pos++
}
l.emit(TEXT, l.input)
return nil
}
func lexTagName(l *lexer) stateFn {
l.tagTmpValue = ""
whiteSpace := false
l.start = l.pos
l.end = l.pos
for l.pos < len(l.input) {
switch l.input[l.pos] {
case '[':
return lexText
case ']':
l.tagTmpName = l.input[l.start:l.end]
return lexTagArgs
case '=':
l.tagTmpName = l.input[l.start:l.end]
return lexTagValue
case ' ', '\t', '\n':
whiteSpace = true
default:
if whiteSpace {
l.tagTmpName = l.input[l.start:l.end]
return lexTagArgs
} else {
l.end++
}
}
l.pos++
}
l.emit(TEXT, l.input)
return nil
}
func lexTagValue(l *lexer) stateFn {
l.pos++
loop:
for l.pos < len(l.input) {
switch l.input[l.pos] {
case ' ', '\t', '\n':
l.pos++
case '"', '\'':
return lexQuotedValue
default:
break loop
}
}
l.start = l.pos
l.end = l.pos
for l.pos < len(l.input) {
switch l.input[l.pos] {
case '[':
return lexText
case ']':
l.tagTmpValue = l.input[l.start:l.end]
return lexTagArgs
case ' ', '\t', '\n':
l.tagTmpValue = l.input[l.start:l.end]
return lexTagArgs
default:
l.end++
}
l.pos++
}
l.emit(TEXT, l.input)
return nil
}
func lexQuotedValue(l *lexer) stateFn {
quoteChar := l.input[l.pos]
l.pos++
l.start = l.pos
var buf bytes.Buffer
escape := false
for l.pos < len(l.input) {
if escape {
if l.input[l.pos] == 'n' {
buf.WriteRune('\n')
} else {
buf.WriteRune(rune(l.input[l.pos]))
}
escape = false
} else {
switch l.input[l.pos] {
case '\\':
escape = true
case '\n':
l.pos = l.start
return lexText
case quoteChar:
l.pos++
l.tagTmpValue = buf.String()
return lexTagArgs
default:
buf.WriteRune(rune(l.input[l.pos]))
}
}
l.pos++
}
l.pos = l.start
return lexText
}
func lexTagArgs(l *lexer) stateFn {
if len(l.tagName) > 0 {
l.tagArgs[strings.ToLower(l.tagTmpName)] = l.tagTmpValue
} else {
l.tagName = l.tagTmpName
l.tagValue = l.tagTmpValue
}
for l.pos < len(l.input) {
switch l.input[l.pos] {
case '[':
return lexText
case ']':
l.pos++
l.emit(OPENING_TAG, BBOpeningTag{strings.ToLower(l.tagName), l.tagValue, l.tagArgs, l.input[:l.pos]})
return lexText
case ' ', '\t', '\n':
l.pos++
default:
l.tagTmpName = ""
return lexTagName
}
}
l.emit(TEXT, l.input)
return nil
}

121
vendor/github.com/frustra/bbcode/lexer_test.go generated vendored Normal file
View File

@@ -0,0 +1,121 @@
// Copyright 2015 Frustra. All rights reserved.
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.
package bbcode
import (
"fmt"
"testing"
)
var prelexTests = map[string][]string{
``: []string{},
`[url]a[/url]`: []string{`<url>`, `a`, `</url>`},
`[img][/img]`: []string{`<img>`, `</img>`},
`[img = foo]bar[/img]`: []string{`<img=foo>`, `bar`, `</img>`},
`[quote name=Someguy]hello[/quote]`: []string{`<quote name=Someguy>`, `hello`, `</quote>`},
`[center][b][color=#00BFFF][size=6]hello[/size][/color][/b][/center]`: []string{`<center>`, `<b>`, `<color=#00BFFF>`, `<size=6>`, `hello`, `</size>`, `</color>`, `</b>`, `</center>`},
`[b]`: []string{`<b>`},
`blank[b][/b]`: []string{`blank`, `<b>`, `</b>`},
`[b][/b]blank`: []string{`<b>`, `</b>`, `blank`},
`[not a tag][/not]`: []string{`<not a tag>`, `</not>`},
`[u][b]something[/b] then [b]something else[/b][/u]`: []string{`<u>`, `<b>`, `something`, `</b>`, ` then `, `<b>`, `something else`, `</b>`, `</u>`},
"the quick brown [b][i]fox[/b][/i]\n[i]\n[b]hi[/b]][b][url=a[img]v[/img][/url][b]": []string{"the quick brown ", "<b>", "<i>", "fox", "</b>", "</i>", "\n", "<i>", "\n", "<b>", "hi", "</b>", "]", "<b>", "[url=a", "<img>", "v", "</img>", "</url>", "<b>"},
"the quick brown[/b][b]hello[/b]": []string{"the quick brown", "</b>", "<b>", "hello", "</b>"},
"the quick brown[/b][/code]": []string{"the quick brown", "</b>", "</code>"},
"[quote\n name=xthexder\n time=555555\n ]hello[/quote]": []string{`<quote name=xthexder time=555555>`, `hello`, `</quote>`},
"[q\nuot\ne\nna\nme\n=\nxthex\nder\n]hello[/quote]": []string{`<q der e me=xthex na uot>`, `hello`, `</quote>`},
`[ b][ i]the quick brown[/i][/b=hello]`: []string{`<b>`, `<i>`, `the quick brown`, `</i>`, `</b=hello>`},
`[b [herp@#$%]]the quick brown[/b]`: []string{`[b `, `<herp@#$%>`, `]the quick brown`, `</b>`},
`[b=hello a=hi q]the quick brown[/b]`: []string{`<b=hello a=hi q>`, `the quick brown`, `</b>`},
`[b]hi[`: []string{`<b>`, `hi`, `[`},
`[size=6 =hello]hi[/size]`: []string{`<size=6 =hello>`, `hi`, `</size>`},
`[size=6 =hello =hi]hi[/size]`: []string{`<size=6 =hi>`, `hi`, `</size>`},
`[img = 'fo"o']bar[/img]`: []string{`<img=fo"o>`, `bar`, `</img>`},
`[img = "foo'"]bar[/img]`: []string{`<img=foo'>`, `bar`, `</img>`},
`[img = "\"'foo"]bar[/img]`: []string{`<img="'foo>`, `bar`, `</img>`},
`[img = "f\oo\]\'fo\\o"]bar[/img]`: []string{`<img=foo]'fo\o>`, `bar`, `</img>`},
`[img = "foo\]'fo\n\"o"]bar[/img]`: []string{"<img=foo]'fo\n\"o>", `bar`, `</img>`},
`[quote name='Someguy']hello[/quote]`: []string{`<quote name=Someguy>`, `hello`, `</quote>`},
`[center][b][color="#00BFFF"][size='6]hello[/size][/color][/b][/center]`: []string{`<center>`, `<b>`, `<color=#00BFFF>`, `[size='6]hello`, `</size>`, `</color>`, `</b>`, `</center>`},
"[center][b][color=\"#00BFFF\"][size='6]hello[/size]\n[/color][/b][/center]": []string{`<center>`, `<b>`, `<color=#00BFFF>`, `[size='6]hello`, `</size>`, "\n", `</color>`, `</b>`, `</center>`},
}
func TestLexer(t *testing.T) {
for in, expected := range prelexTests {
lexer := newLexer(in)
go lexer.runStateMachine()
ok, out := CheckResult(lexer, expected)
if !ok {
t.Errorf("Failed to prelex %s.\nExpected: %s, got: %s\n", in, PrintExpected(expected), PrintOutput(out))
}
}
}
func PrintExpected(expected []string) string {
result := ""
for i, v := range expected {
if i > 0 {
result += "_"
}
result += v
}
return result
}
func PrintOutput(out []Token) string {
result := ""
for i, v := range out {
if i > 0 {
result += "_"
}
switch t := v.Value.(type) {
case string:
result += t
case BBOpeningTag:
result += "<" + t.String() + ">"
case BBClosingTag:
result += "</" + t.Name + ">"
default:
result += fmt.Sprintf("{%v}", t)
}
}
return result
}
func CheckResult(l *lexer, b []string) (bool, []Token) {
i := 0
out := make([]Token, 0)
good := true
for v := range l.tokens {
out = append(out, v)
if i < len(b) && good {
switch t := v.Value.(type) {
case string:
if t != b[i] {
good = false
}
case BBOpeningTag:
if "<"+t.String()+">" != b[i] {
good = false
}
case BBClosingTag:
if "</"+t.Name+">" != b[i] {
good = false
}
default:
good = false
}
}
i++
}
if i != len(b) {
return false, out
}
return good, out
}

60
vendor/github.com/frustra/bbcode/parser.go generated vendored Normal file
View File

@@ -0,0 +1,60 @@
// Copyright 2015 Frustra. All rights reserved.
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.
package bbcode
type BBCodeNode struct {
Token
Parent *BBCodeNode
Children []*BBCodeNode
ClosingTag *BBClosingTag
Compiler *Compiler
Info interface{}
}
func (n *BBCodeNode) GetOpeningTag() *BBOpeningTag {
if tag, ok := n.Value.(BBOpeningTag); ok {
return &tag
} else {
return nil
}
}
func (n *BBCodeNode) appendChild(t Token) *BBCodeNode {
if t.ID == CLOSING_TAG {
curr := n
closing := t.Value.(BBClosingTag)
for curr.Parent != nil {
if curr.ID == OPENING_TAG && curr.Value.(BBOpeningTag).Name == closing.Name {
curr.ClosingTag = &closing
return curr.Parent
}
curr = curr.Parent
}
}
// Join consecutive TEXT tokens
if len(n.Children) == 0 && t.ID == TEXT && n.ID == TEXT {
n.Value = n.Value.(string) + t.Value.(string)
return n
}
node := &BBCodeNode{t, n, make([]*BBCodeNode, 0, 5), nil, nil, nil}
n.Children = append(n.Children, node)
if t.ID == OPENING_TAG {
return node
} else {
return n
}
}
func Parse(tokens chan Token) *BBCodeNode {
root := &BBCodeNode{Token{TEXT, ""}, nil, make([]*BBCodeNode, 0, 5), nil, nil, nil}
curr := root
for tok := range tokens {
curr = curr.appendChild(tok)
}
return root
}