Compare commits

...

15 Commits

Author SHA1 Message Date
Wim
7b0bc51183 Release v1.14.0-rc2 2019-03-02 23:23:43 +01:00
Wim
53aa076555 Do not send duplicate messages (rocketchat). Fixes #745 (#752)
For an unknown reason we get duplicate messages (from the same channel)
using the realtime API when we have > 1 channel subscribed on.
Solution for now is caching the message ID in a LRU cache and ignoring
the duplicates.

This should be reviewed when we have actual editing support from the
realtime API
2019-03-02 22:58:14 +01:00
Wim
f57370f33a Add support for URL in messageEntities (telegram). Fixes #735 (#736) 2019-03-02 22:38:44 +01:00
Wim
c557d51b6f Need to specify /topic:mytopic for channel configuration (zulip). (#751)
Breaking change for zulip channel configuration.

For zulip the channel configuration will now need to specify also
the topic with /topic:yourtopic.

Example:
[[gateway.inout]]
account="zulip.streamchat"
channel="general/topic:mytopic"

This fixes the incorrect PR #701 which didn't work with multiple
gateways.
2019-03-02 20:31:38 +01:00
Wim
df3fdc26a0 Use whatsapp forks (#750) 2019-03-02 13:04:28 +01:00
Wim
af00c34aac Do not relay any bot messages (discord) (#743) 2019-02-28 12:59:52 +01:00
Wim
120bf39f55 Handle file upload/download only once for each message (#742) 2019-02-27 20:52:05 +01:00
Wim
26a7e35f27 Add MediaConvertWebPToPNG option (telegram). (#741)
* Add MediaConvertWebPToPNG option (telegram).

When enabled matterbridge will convert .webp files to .png files
before uploading them to the mediaserver of the other bridges.

Fixes #398
2019-02-27 00:41:50 +01:00
Wim
d44d2a5f00 Build on all branches 2019-02-26 20:47:30 +01:00
Wim
7f1d86b338 Fail gracefully on incorrect human input. Fixes #739 (#740) 2019-02-26 18:03:50 +01:00
Wim
d8816280f0 Update changelog 2019-02-26 17:44:35 +01:00
Wim
b09a73040f Print errors as string instead of %#v (#738) 2019-02-26 17:21:23 +01:00
Wim
740b5f2602 Keep reconnecting until succeed (zulip) (#737) 2019-02-26 17:08:20 +01:00
Wim
96841c70c7 Fix regression in HTML handling (telegram). Closes #734
* Revert back to blackfriday v1
* Add testing
2019-02-24 15:13:56 +01:00
Wim
f92735d35d Add goreleaser.yml 2019-02-24 01:09:53 +01:00
151 changed files with 8649 additions and 3414 deletions

34
.goreleaser.yml Normal file
View File

@@ -0,0 +1,34 @@
release:
prerelease: auto
name_template: "{{.ProjectName}} v{{.Version}}"
builds:
- env:
- CGO_ENABLED=0
goos:
- freebsd
- windows
- darwin
- linux
- dragonfly
- netbsd
- openbsd
goarch:
- amd64
- arm
- arm64
- 386
ldflags:
- -s -w -X main.githash={{.ShortCommit}}
archive:
name_template: "{{ .Binary }}-{{ .Version }}-{{ .Os }}-{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}"
format: binary
files:
- none*
replacements:
386: 32bit
amd64: 64bit
checksum:
name_template: 'checksums.txt'

View File

@@ -48,10 +48,16 @@ after_script:
- ./cc-test-reporter after-build --exit-code ${TRAVIS_TEST_RESULT}
deploy:
on:
all_branches: true
provider: bintray
on:
all_branches: true
edge:
branch: v1.8.47
file: ci/deploy.json
user: 42wim
on:
all_branches: true
key:
secure: "CeXXe6JOmt7HYR81MdWLua0ltQHhDdkIeRGBFbgd7hkb1wi8eF9DgpAcQrTso8NIlHNZmSAP46uhFgsRvkuezzX0ygalZ7DCJyAyn3sAMEh+UQSHV1WGThRehTtidqRGjetzsIGSwdrJOWil+XTfbO1Z8DGzfakhSuAZka8CM4BAoe3YeP9rYK8h+84x0GHfczvsLtXZ3mWLvQuwe4pK6+ItBCUg0ae7O7ZUpWHy0xQQkkWztY/6RAzXfaG7DuGjIw+20fhx3WOXRNpHCtZ6Bc3qERCpk0s1HhlQWlrN9wDaFTBWYwlvSnNgvxxMbNXJ6RrRJ0l0bA7FUswYwyroxhzrGLdzWDg8dHaQkypocngdalfhpsnoO9j3ApJhomUFJ3UoEq5nOGRUrKn8MPi+dP0zE4kNQ3e4VNa1ufNrvfpWolMg3xh8OXuhQdD5wIM5zFAbRJLqWSCVAjPq4DDPecmvXBOlIial7oa312lN5qnBnUjvAcxszZ+FUyDHT1Grxzna4tMwxY9obPzZUzm7359AOCCwIQFVB8GLqD2nwIstcXS0zGRz+fhviPipHuBa02q5bGUZwmkvrSNab0s8Jo7pCrel2Rz3nWPKaiCfq2WjbW1CLheSMkOQrjsdUd1hhbqNWFPUjJPInTc77NAKCfm5runv5uyowRLh4NNd0sI="

View File

@@ -237,10 +237,6 @@ See [changelog.md](https://github.com/42wim/matterbridge/blob/master/changelog.m
See [FAQ](https://github.com/42wim/matterbridge/wiki/FAQ)
Want to tip ?
* eth: 0xb3f9b5387c66ad6be892bcb7bbc67862f3abc16f
* btc: 1N7cKHj5SfqBHBzDJ6kad4BzeqUBBS2zhs
## Related projects
* [FOSSRIT/infrastructure - roles/matterbridge](https://github.com/FOSSRIT/infrastructure/tree/master/roles/matterbridge) (Ansible role used to automate deployments of Matterbridge)
* [matterbridge autoconfig](https://github.com/patcon/matterbridge-autoconfig)

View File

@@ -93,6 +93,7 @@ type Protocol struct {
MediaDownloadSize int // all protocols
MediaServerDownload string
MediaServerUpload string
MediaConvertWebPToPNG bool // telegram
MessageDelay int // IRC, time in millisecond to wait between messages
MessageFormat string // telegram
MessageLength int // IRC, max length of a message allowed

View File

@@ -246,7 +246,7 @@ func (b *Bdiscord) Send(msg config.Message) (string, error) {
b.Log.Debugf("Setting webhook channel to \"%s\"", msg.Channel)
_, err := b.c.WebhookEdit(wID, "", "", channelID)
if err != nil {
b.Log.Errorf("Could not set webhook channel: %v", err)
b.Log.Errorf("Could not set webhook channel: %s", err)
return "", err
}
}
@@ -278,7 +278,7 @@ func (b *Bdiscord) Send(msg config.Message) (string, error) {
for _, rmsg := range helper.HandleExtra(&msg, b.General) {
rmsg.Text = helper.ClipMessage(rmsg.Text, MessageLength)
if _, err := b.c.ChannelMessageSend(channelID, rmsg.Username+rmsg.Text); err != nil {
b.Log.Errorf("Could not send message %#v: %v", rmsg, err)
b.Log.Errorf("Could not send message %#v: %s", rmsg, err)
}
}
// check if we have files to upload (from slack, telegram or mattermost)
@@ -360,7 +360,7 @@ func (b *Bdiscord) handleUploadFile(msg *config.Message, channelID string) (stri
}
_, err = b.c.ChannelMessageSendComplex(channelID, &m)
if err != nil {
return "", fmt.Errorf("file upload failed: %#v", err)
return "", fmt.Errorf("file upload failed: %s", err)
}
}
return "", nil

View File

@@ -36,7 +36,7 @@ func (b *Bdiscord) messageCreate(s *discordgo.Session, m *discordgo.MessageCreat
return
}
// if using webhooks, do not relay if it's ours
if b.useWebhook() && m.Author.Bot && b.isWebhookID(m.Author.ID) {
if b.useWebhook() && m.Author.Bot { // && b.isWebhookID(m.Author.ID) {
return
}

View File

@@ -25,7 +25,7 @@ func (b *Bdiscord) getNick(user *discordgo.User) string {
// If we didn't find nick, search for it.
member, err := b.c.GuildMember(b.guildID, user.ID)
if err != nil {
b.Log.Warnf("Failed to fetch information for member %#v: %#v", user, err)
b.Log.Warnf("Failed to fetch information for member %#v: %s", user, err)
return user.Username
} else if member == nil {
b.Log.Warnf("Got no information for member %#v", user)

View File

@@ -3,6 +3,7 @@ package helper
import (
"bytes"
"fmt"
"image/png"
"io"
"net/http"
"regexp"
@@ -10,6 +11,8 @@ import (
"time"
"unicode/utf8"
"golang.org/x/image/webp"
"github.com/42wim/matterbridge/bridge/config"
"github.com/sirupsen/logrus"
"gitlab.com/golang-commonmark/markdown"
@@ -177,3 +180,19 @@ func ParseMarkdown(input string) string {
md := markdown.New(markdown.XHTMLOutput(true), markdown.Breaks(true))
return (md.RenderToString([]byte(input)))
}
// ConvertWebPToPNG convert input data (which should be WebP format to PNG format)
func ConvertWebPToPNG(data *[]byte) error {
r := bytes.NewReader(*data)
m, err := webp.Decode(r)
if err != nil {
return err
}
var output []byte
w := bytes.NewBuffer(output)
if err := png.Encode(w, m); err != nil {
return err
}
*data = w.Bytes()
return nil
}

View File

@@ -1,6 +1,8 @@
package helper
import (
"io/ioutil"
"os"
"testing"
"github.com/stretchr/testify/assert"
@@ -103,3 +105,22 @@ func TestGetSubLines(t *testing.T) {
assert.Equalf(t, testcase.nonSplitOutput, nonSplitLines, "'%s' testcase should give expected lines without splitting.", testname)
}
}
func TestConvertWebPToPNG(t *testing.T) {
if os.Getenv("LOCAL_TEST") == "" {
t.Skip()
}
input, err := ioutil.ReadFile("test.webp")
if err != nil {
t.Fail()
}
d := &input
err = ConvertWebPToPNG(d)
if err != nil {
t.Fail()
}
err = ioutil.WriteFile("test.png", *d, 0644)
if err != nil {
t.Fail()
}
}

View File

@@ -40,6 +40,11 @@ func (b *Brocketchat) handleRocketHook(messages chan *config.Message) {
func (b *Brocketchat) handleRocketClient(messages chan *config.Message) {
for message := range b.messageChan {
// skip messages with same ID, apparently messages get duplicated for an unknown reason
if _, ok := b.cache.Get(message.ID); ok {
continue
}
b.cache.Add(message.ID, true)
b.Log.Debugf("message %#v", message)
m := message
if b.skipMessage(&m) {

View File

@@ -9,16 +9,18 @@ import (
"github.com/42wim/matterbridge/bridge/helper"
"github.com/42wim/matterbridge/hook/rockethook"
"github.com/42wim/matterbridge/matterhook"
lru "github.com/hashicorp/golang-lru"
"github.com/matterbridge/Rocket.Chat.Go.SDK/models"
"github.com/matterbridge/Rocket.Chat.Go.SDK/realtime"
"github.com/matterbridge/Rocket.Chat.Go.SDK/rest"
)
type Brocketchat struct {
mh *matterhook.Client
rh *rockethook.Client
c *realtime.Client
r *rest.Client
mh *matterhook.Client
rh *rockethook.Client
c *realtime.Client
r *rest.Client
cache *lru.Cache
*bridge.Config
messageChan chan models.Message
channelMap map[string]string
@@ -27,9 +29,16 @@ type Brocketchat struct {
}
func New(cfg *bridge.Config) bridge.Bridger {
b := &Brocketchat{Config: cfg}
b.messageChan = make(chan models.Message)
b.channelMap = make(map[string]string)
newCache, err := lru.New(100)
if err != nil {
cfg.Log.Fatalf("Could not create LRU cache for rocketchat bridge: %v", err)
}
b := &Brocketchat{
Config: cfg,
messageChan: make(chan models.Message),
channelMap: make(map[string]string),
cache: newCache,
}
b.Log.Debugf("enabling rocketchat")
return b
}

View File

@@ -144,6 +144,9 @@ func (b *Btelegram) handleRecv(updates <-chan tgbotapi.Update) {
// quote the previous message
b.handleQuoting(&rmsg, message)
// handle entities (adding URLs)
b.handleEntities(&rmsg, message)
if rmsg.Text != "" || len(rmsg.Extra) > 0 {
rmsg.Text = helper.RemoveEmptyNewLines(rmsg.Text)
// channels don't have (always?) user information. see #410
@@ -245,6 +248,15 @@ func (b *Btelegram) handleDownload(rmsg *config.Message, message *tgbotapi.Messa
if err != nil {
return err
}
if strings.HasSuffix(name, ".webp") && b.GetBool("MediaConvertWebPToPNG") {
b.Log.Debugf("WebP to PNG conversion enabled, converting %s", name)
err := helper.ConvertWebPToPNG(data)
if err != nil {
b.Log.Errorf("conversion failed: %s", err)
} else {
name = strings.Replace(name, ".webp", ".png", 1)
}
}
helper.HandleDownloadData(b.Log, rmsg, name, message.Caption, "", data, b.General)
return nil
}
@@ -344,3 +356,22 @@ func (b *Btelegram) handleQuote(message, quoteNick, quoteMessage string) string
format = strings.Replace(format, "{QUOTEMESSAGE}", quoteMessage, -1)
return format
}
// handleEntities handles messageEntities
func (b *Btelegram) handleEntities(rmsg *config.Message, message *tgbotapi.Message) {
if message.Entities == nil {
return
}
// for now only do URL replacements
for _, e := range *message.Entities {
if e.Type == "text_link" {
url, err := e.ParseURL()
if err != nil {
b.Log.Errorf("entity text_link url parse failed: %s", err)
continue
}
link := rmsg.Text[e.Offset : e.Offset+e.Length]
rmsg.Text = strings.Replace(rmsg.Text, link, url.String(), 1)
}
}
}

View File

@@ -3,7 +3,6 @@ package btelegram
import (
"bytes"
"html"
"io"
"github.com/russross/blackfriday"
)
@@ -33,7 +32,7 @@ func (options *customHTML) Header(out *bytes.Buffer, text func() bool, level int
options.Paragraph(out, text)
}
func (options *customHTML) HRule(out io.ByteWriter) {
func (options *customHTML) HRule(out *bytes.Buffer) {
out.WriteByte('\n') //nolint:errcheck
}
@@ -54,16 +53,13 @@ func (options *customHTML) ListItem(out *bytes.Buffer, text []byte, flags int) {
}
func makeHTML(input string) string {
extensions := blackfriday.NoIntraEmphasis |
blackfriday.FencedCode |
blackfriday.Autolink |
blackfriday.SpaceHeadings |
blackfriday.HeadingIDs |
blackfriday.BackslashLineBreak |
blackfriday.DefinitionLists
renderer := &customHTML{blackfriday.NewHTMLRenderer(blackfriday.HTMLRendererParameters{
Flags: blackfriday.UseXHTML | blackfriday.SkipImages,
})}
return string(blackfriday.Run([]byte(input), blackfriday.WithExtensions(extensions), blackfriday.WithRenderer(renderer)))
return string(blackfriday.Markdown([]byte(input),
&customHTML{blackfriday.HtmlRenderer(blackfriday.HTML_USE_XHTML|blackfriday.HTML_SKIP_IMAGES, "", "")},
blackfriday.EXTENSION_NO_INTRA_EMPHASIS|
blackfriday.EXTENSION_FENCED_CODE|
blackfriday.EXTENSION_AUTOLINK|
blackfriday.EXTENSION_SPACE_HEADERS|
blackfriday.EXTENSION_HEADER_IDS|
blackfriday.EXTENSION_BACKSLASH_LINE_BREAK|
blackfriday.EXTENSION_DEFINITION_LISTS))
}

View File

@@ -6,9 +6,9 @@ import (
"github.com/42wim/matterbridge/bridge/config"
"github.com/Rhymen/go-whatsapp"
"github.com/matterbridge/go-whatsapp"
whatsappExt "maunium.net/go/mautrix-whatsapp/whatsapp-ext"
whatsappExt "github.com/matterbridge/mautrix-whatsapp/whatsapp-ext"
)
/*

View File

@@ -6,7 +6,7 @@ import (
"os"
qrcodeTerminal "github.com/Baozisoftware/qrcode-terminal-go"
"github.com/Rhymen/go-whatsapp"
"github.com/matterbridge/go-whatsapp"
)
func qrFromTerminal(invert bool) chan string {

View File

@@ -12,9 +12,9 @@ import (
"github.com/42wim/matterbridge/bridge"
"github.com/42wim/matterbridge/bridge/config"
"github.com/Rhymen/go-whatsapp"
"github.com/matterbridge/go-whatsapp"
whatsappExt "maunium.net/go/mautrix-whatsapp/whatsapp-ext"
whatsappExt "github.com/matterbridge/mautrix-whatsapp/whatsapp-ext"
)
const (

View File

@@ -4,6 +4,7 @@ import (
"encoding/json"
"io/ioutil"
"strconv"
"strings"
"sync"
"time"
@@ -18,12 +19,11 @@ type Bzulip struct {
bot *gzb.Bot
streams map[int]string
*bridge.Config
channelToTopic map[string]string
sync.RWMutex
}
func New(cfg *bridge.Config) bridge.Bridger {
return &Bzulip{Config: cfg, streams: make(map[int]string), channelToTopic: make(map[string]string)}
return &Bzulip{Config: cfg, streams: make(map[int]string)}
}
func (b *Bzulip) Connect() error {
@@ -48,9 +48,6 @@ func (b *Bzulip) Disconnect() error {
}
func (b *Bzulip) JoinChannel(channel config.ChannelInfo) error {
b.Lock()
defer b.Unlock()
b.channelToTopic[channel.Name] = channel.Options.Topic
return nil
}
@@ -116,11 +113,13 @@ func (b *Bzulip) handleQueue() error {
case gzb.BadEventQueueError:
b.Log.Info("got a bad event queue id error, reconnecting")
b.bot.Queues = nil
b.q, err = b.bot.RegisterAll()
if err != nil {
b.Log.Errorf("reconnecting failed: %s. Sleeping 10 seconds", err)
time.Sleep(time.Second * 10)
continue
for {
b.q, err = b.bot.RegisterAll()
if err != nil {
b.Log.Errorf("reconnecting failed: %s. Sleeping 10 seconds", err)
time.Sleep(time.Second * 10)
}
break
}
case gzb.HeartbeatError:
b.Log.Debug("heartbeat received.")
@@ -136,7 +135,14 @@ func (b *Bzulip) handleQueue() error {
if m.SenderEmail == b.GetString("login") {
continue
}
rmsg := config.Message{Username: m.SenderFullName, Text: m.Content, Channel: b.getChannel(m.StreamID), Account: b.Account, UserID: strconv.Itoa(m.SenderID), Avatar: m.AvatarURL}
rmsg := config.Message{
Username: m.SenderFullName,
Text: m.Content,
Channel: b.getChannel(m.StreamID) + "/topic:" + m.Subject,
Account: b.Account,
UserID: strconv.Itoa(m.SenderID),
Avatar: m.AvatarURL,
}
b.Log.Debugf("<= Sending message from %s on %s to gateway", rmsg.Username, b.Account)
b.Log.Debugf("<= Message is %#v", rmsg)
b.Remote <- rmsg
@@ -147,12 +153,11 @@ func (b *Bzulip) handleQueue() error {
}
func (b *Bzulip) sendMessage(msg config.Message) (string, error) {
topic := "matterbridge"
if b.GetString("topic") != "" {
topic = b.GetString("topic")
}
if res := b.getTopic(msg.Channel); res != "" {
topic = res
topic := ""
if strings.Contains(msg.Channel, "/topic:") {
res := strings.Split(msg.Channel, "/topic:")
topic = res[1]
msg.Channel = res[0]
}
m := gzb.Message{
Stream: msg.Channel,
@@ -200,9 +205,3 @@ func (b *Bzulip) handleUploadFile(msg *config.Message) (string, error) {
}
return "", nil
}
func (b *Bzulip) getTopic(channel string) string {
b.RLock()
defer b.RUnlock()
return b.channelToTopic[channel]
}

View File

@@ -1,4 +1,7 @@
# v1.14.0-rc1
# v1.14.0
## Breaking
* zulip: Need to specify /topic:mytopic for channel configuration (zulip). (#751)
## New features
* whatsapp: new protocol added. Add initial WhatsApp support (#711) Thanks to @KrzysztofMadejski
@@ -10,11 +13,17 @@
* rocketchat: add support for the rocketchat API. Sending to rocketchat now supports uploading of files, editing and deleting of messages.
* discord: Support join/leaves from discord. Closes #654 (#721)
* discord: Allow sending discriminator with Discord username (#726). See `UseDiscriminator` in matterbridge.toml.sample
* zulip: Allow zulip bridge to specify topic per channel. Closes #701 (#723). See `Topic` in matterbridge.toml.sample
* slack: Add extra debug option (slack). See `Debug` in the slack section in matterbridge.toml.sample
* telegram: Add support for URL in messageEntities (telegram). Fixes #735 (#736)
* telegram: Add MediaConvertWebPToPNG option (telegram). (#741). See `MediaConvertWebPToPNG` in matterbridge.toml.sample
## Enhancements
* general: Fail gracefully on incorrect human input. Fixes #739 (#740)
## Bugfix
* general: Handle file upload/download only once for each message (#742)
* zulip: Fix error handling on bad event queue id (zulip). Closes #694
* zulip: Keep reconnecting until succeed (zulip) (#737)
* irc: add support for (older) unrealircd versions. #708
* irc: Support quits from irc correctly. Fixes #722 (#724)
* matrix: Send username when uploading video/images (matrix). Fixes #715 (#717)
@@ -22,6 +31,9 @@
* matrix: Detect html nicks in RemoteNickFormat (matrix). Fixes #696 (#719)
* slack: Hint at thread replies when messages are unthreaded (slack) (#684)
* xmpp: Do not send topic changes on connect (xmpp). Fixes #732 (#733)
* telegram: Fix regression in HTML handling (telegram). Closes #734
* discord: Do not relay any bot messages (discord) (#743)
* rocketchat: Do not send duplicate messages (rocketchat). Fixes #745 (#752)
## Contributors
This release couldn't exist without the following contributors:

View File

@@ -92,6 +92,9 @@ func (gw *Gateway) AddBridge(cfg *config.Bridge) error {
Bridge: br,
}
// add the actual bridger for this protocol to this bridge using the bridgeMap
if _, ok := gw.Router.BridgeMap[br.Protocol]; !ok {
gw.logger.Fatalf("Incorrect protocol %s specified in gateway configuration %s, exiting.", br.Protocol, cfg.Account)
}
br.Bridger = gw.Router.BridgeMap[br.Protocol](brconfig)
}
gw.mapChannelsToBridge(br)
@@ -156,6 +159,10 @@ func (gw *Gateway) mapChannelConfig(cfg []config.Bridge, direction string) {
gw.logger.Errorf("Mattermost channels do not start with a #: remove the # in %s", br.Channel)
os.Exit(1)
}
if strings.HasPrefix(br.Account, "zulip.") && !strings.Contains(br.Channel, "/topic:") {
gw.logger.Errorf("Breaking change, since matterbridge 1.14.0 zulip channels need to specify the topic with channel/topic:mytopic in %s of %s", br.Channel, br.Account)
os.Exit(1)
}
ID := br.Channel + br.Account
if _, ok := gw.Channels[ID]; !ok {
channel := &config.ChannelInfo{

View File

@@ -125,6 +125,7 @@ func (r *Router) handleReceive() {
r.handleEventGetChannelMembers(&msg)
r.handleEventFailure(&msg)
r.handleEventRejoinChannels(&msg)
idx := 0
for _, gw := range r.Gateways {
// record all the message ID's of the different bridges
var msgIDs []*BrMsgID
@@ -133,7 +134,9 @@ func (r *Router) handleReceive() {
}
msg.Timestamp = time.Now()
gw.modifyMessage(&msg)
gw.handleFiles(&msg)
if idx == 0 {
gw.handleFiles(&msg)
}
for _, br := range gw.Bridges {
msgIDs = append(msgIDs, gw.handleMessage(&msg, br)...)
}
@@ -141,6 +144,7 @@ func (r *Router) handleReceive() {
if _, ok := gw.Messages.Get(msg.Protocol + " " + msg.ID); !ok && msg.ID != "" {
gw.Messages.Add(msg.Protocol+" "+msg.ID, msgIDs)
}
idx++
}
}
}

7
go.mod
View File

@@ -6,7 +6,6 @@ require (
github.com/BurntSushi/toml v0.0.0-20170318202913-d94612f9fc14 // indirect
github.com/Jeffail/gabs v1.1.1 // indirect
github.com/Philipp15b/go-steam v1.0.1-0.20180818081528-681bd9573329
github.com/Rhymen/go-whatsapp v0.0.0-20190208184307-c9a81e957884
github.com/bwmarrin/discordgo v0.19.0
github.com/d5/tengo v1.9.2
github.com/dfordsoft/golib v0.0.0-20180902042739-76ee6ab99bec
@@ -28,10 +27,12 @@ require (
github.com/lusis/go-slackbot v0.0.0-20180109053408-401027ccfef5 // indirect
github.com/lusis/slack-test v0.0.0-20180109053238-3c758769bfa6 // indirect
github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20190210153444-cc9d05784d5d
github.com/matterbridge/go-whatsapp v0.0.1-0.20190301204034-f2f1b29d441b
github.com/matterbridge/go-xmpp v0.0.0-20180529212104-cd19799fba91
github.com/matterbridge/gomatrix v0.0.0-20190102230110-6f9631ca6dea
github.com/matterbridge/gozulipbot v0.0.0-20190212232658-7aa251978a18
github.com/matterbridge/logrus-prefixed-formatter v0.0.0-20180806162718-01618749af61
github.com/matterbridge/mautrix-whatsapp v0.0.0-20190301210046-3539cf52ed6e
github.com/mattermost/mattermost-server v5.5.0+incompatible
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474 // indirect
@@ -46,7 +47,7 @@ require (
github.com/peterhellberg/emojilib v0.0.0-20190124112554-c18758d55320
github.com/pkg/errors v0.8.0 // indirect
github.com/rs/xid v1.2.1
github.com/russross/blackfriday v2.0.0+incompatible
github.com/russross/blackfriday v1.5.2
github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca
github.com/shazow/ssh-chat v0.0.0-20190125184227-81d7e1686296
github.com/sirupsen/logrus v1.3.0
@@ -66,8 +67,8 @@ require (
go.uber.org/atomic v1.3.2 // indirect
go.uber.org/multierr v1.1.0 // indirect
go.uber.org/zap v1.9.1 // indirect
golang.org/x/image v0.0.0-20190220214146-31aff87c08e9
gopkg.in/fsnotify.v1 v1.4.7 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
maunium.net/go/mautrix-whatsapp v0.0.0-20190127121751-281b3e8f77f3
)

41
go.sum
View File

@@ -8,11 +8,6 @@ github.com/Jeffail/gabs v1.1.1 h1:V0uzR08Hj22EX8+8QMhyI9sX2hwRu+/RJhJUmnwda/E=
github.com/Jeffail/gabs v1.1.1/go.mod h1:6xMvQMK4k33lb7GUUpaAPh6nKMmemQeg5d4gn7/bOXc=
github.com/Philipp15b/go-steam v1.0.1-0.20180818081528-681bd9573329 h1:xZBoq249G9MSt+XuY7sVQzcfONJ6IQuwpCK+KAaOpnY=
github.com/Philipp15b/go-steam v1.0.1-0.20180818081528-681bd9573329/go.mod h1:HuVM+sZFzumUdKPWiz+IlCMb4RdsKdT3T+nQBKL+sYg=
github.com/Rhymen/go-whatsapp v0.0.0-20181218094654-2ca6af00572c h1:ldRXgMEfKmzBomrZusl3edG9AGEeztA7jovLEQy62us=
github.com/Rhymen/go-whatsapp v0.0.0-20181218094654-2ca6af00572c/go.mod h1:MSDmePOOkbFFbVW2WRRppBcbA+aabwpXRgyIIG7jDFQ=
github.com/Rhymen/go-whatsapp v0.0.0-20190208184307-c9a81e957884 h1:2AxfzkQi2L4QGBvUCZoWD6hQuUJa5MG54wiYyNqJlf4=
github.com/Rhymen/go-whatsapp v0.0.0-20190208184307-c9a81e957884/go.mod h1:rdQr95g2C1xcOfM7QGOhza58HeI3I+tZ/bbluv7VazA=
github.com/alexcesaro/log v0.0.0-20150915221235-61e686294e58 h1:MkpmYfld/S8kXqTYI68DfL8/hHXjHogL120Dy00TIxc=
github.com/alexcesaro/log v0.0.0-20150915221235-61e686294e58/go.mod h1:YNfsMyWSs+h+PaYkxGeMVmVCX75Zj/pqdjbu12ciCYE=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/bwmarrin/discordgo v0.19.0 h1:kMED/DB0NR1QhRcalb85w0Cu3Ep2OrGAqZH1R5awQiY=
@@ -43,6 +38,7 @@ github.com/gopackage/ddp v0.0.0-20170117053602-652027933df4/go.mod h1:lEO7XoHJ/x
github.com/gopherjs/gopherjs v0.0.0-20180628210949-0892b62f0d9f h1:FDM3EtwZLyhW48YRiyqjivNlNZjAObv4xt4NnJaU+NQ=
github.com/gopherjs/gopherjs v0.0.0-20180628210949-0892b62f0d9f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/schema v1.0.2 h1:sAgNfOcNYvdDSrzGHVy9nzCQahG+qmsg+nE8dK85QRA=
github.com/gorilla/schema v1.0.2/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU=
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
@@ -82,6 +78,8 @@ github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDe
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20190210153444-cc9d05784d5d h1:F+Sr+C0ojSlYQ37BLylQtSFmyQULe3jbAygcyXQ9mVs=
github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20190210153444-cc9d05784d5d/go.mod h1:c6MxwqHD+0HvtAJjsHMIdPCiAwGiQwPRPTp69ACMg8A=
github.com/matterbridge/go-whatsapp v0.0.1-0.20190301204034-f2f1b29d441b h1:cO6Z+yj4Ivq/ay/IxSrV90oSIW/SSXWLa+XHsiLKMrw=
github.com/matterbridge/go-whatsapp v0.0.1-0.20190301204034-f2f1b29d441b/go.mod h1:dW19fYkkdUZsBAx7zv9fDh0n6NRqYIaKwB2JEBw8d0U=
github.com/matterbridge/go-xmpp v0.0.0-20180529212104-cd19799fba91 h1:KzDEcy8eDbTx881giW8a6llsAck3e2bJvMyKvh1IK+k=
github.com/matterbridge/go-xmpp v0.0.0-20180529212104-cd19799fba91/go.mod h1:ECDRehsR9TYTKCAsRS8/wLeOk6UUqDydw47ln7wG41Q=
github.com/matterbridge/gomatrix v0.0.0-20190102230110-6f9631ca6dea h1:kaADGqpK4gGO2BpzEyJrBxq2Jc57Rsar4i2EUxcACUc=
@@ -90,12 +88,16 @@ github.com/matterbridge/gozulipbot v0.0.0-20190212232658-7aa251978a18 h1:fLhwXtW
github.com/matterbridge/gozulipbot v0.0.0-20190212232658-7aa251978a18/go.mod h1:yAjnZ34DuDyPHMPHHjOsTk/FefW4JJjoMMCGt/8uuQA=
github.com/matterbridge/logrus-prefixed-formatter v0.0.0-20180806162718-01618749af61 h1:R/MgM/eUyRBQx2FiH6JVmXck8PaAuKfe2M1tWIzW7nE=
github.com/matterbridge/logrus-prefixed-formatter v0.0.0-20180806162718-01618749af61/go.mod h1:iXGEotOvwI1R1SjLxRc+BF5rUORTMtE0iMZBT2lxqAU=
github.com/matterbridge/mautrix-whatsapp v0.0.0-20190301210046-3539cf52ed6e h1:1NqciL8sz+0UYeFrd/UQlL8tJPhFxOBmg+a94DN2sJU=
github.com/matterbridge/mautrix-whatsapp v0.0.0-20190301210046-3539cf52ed6e/go.mod h1:DrIFGcFumRlEW5k3PJjWGKPd4+w37d3SwOxlh1ZAL+4=
github.com/mattermost/mattermost-server v5.5.0+incompatible h1:0wcLGgYtd+YImtLDPf2AOfpBHxbU4suATx+6XKw1XbU=
github.com/mattermost/mattermost-server v5.5.0+incompatible/go.mod h1:5L6MjAec+XXQwMIt791Ganu45GKsSiM+I0tLR9wUj8Y=
github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs=
github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.5 h1:tHXDdz1cpzGaovsTB+TVB8q90WEokoVmfMqoVcrLUgw=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
@@ -129,8 +131,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rs/xid v1.2.1 h1:mhH9Nq+C1fY2l1XIpgxIiUOfNpRBYH1kKcr+qfKgjRc=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/russross/blackfriday v2.0.0+incompatible h1:cBXrhZNUf9C+La9/YpS+UHpUT8YD6Td9ZMSU9APFcsk=
github.com/russross/blackfriday v2.0.0+incompatible/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca h1:NugYot0LIVPxTvN8n+Kvkn6TrbMyxQiuvKdEwFdR9vI=
github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU=
@@ -138,11 +140,9 @@ github.com/shazow/rateio v0.0.0-20150116013248-e8e00881e5c1 h1:Lx3BlDGFElJt4u/zK
github.com/shazow/rateio v0.0.0-20150116013248-e8e00881e5c1/go.mod h1:vt2jWY/3Qw1bIzle5thrJWucsLuuX9iUNnp20CqCciI=
github.com/shazow/ssh-chat v0.0.0-20190125184227-81d7e1686296 h1:8RLq547MSVc6vhOuCl4Ca0TsAQknj6NX6ZLSZ3+xmio=
github.com/shazow/ssh-chat v0.0.0-20190125184227-81d7e1686296/go.mod h1:1GLXsL4esywkpNId3v4QWuMf3THtWGitWvtQ/L3aSA4=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.3.0 h1:hI/7Q+DtNZ2kINb6qt/lS+IyXnHQe9e90POfeewL/ME=
github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/skip2/go-qrcode v0.0.0-20171229120447-cf5f9fa2f0d8/go.mod h1:PLPIyL7ikehBD1OAjmKKiOEhbvWyHGaNDjquXMcYABo=
github.com/skip2/go-qrcode v0.0.0-20190110000554-dc11ecdae0a9 h1:lpEzuenPuO1XNTeikEmvqYFcU37GVLl8SRNblzyvGBE=
github.com/skip2/go-qrcode v0.0.0-20190110000554-dc11ecdae0a9/go.mod h1:PLPIyL7ikehBD1OAjmKKiOEhbvWyHGaNDjquXMcYABo=
github.com/smartystreets/assertions v0.0.0-20180803164922-886ec427f6b9 h1:lXQ+j+KwZcbwrbgU0Rp4Eglg3EJLHbuZU3BbOqAGBmg=
@@ -160,9 +160,7 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn
github.com/spf13/viper v1.3.1 h1:5+8j8FTpnFV4nEImW/ofkzEt8VoOiLXxdYIDsB73T38=
github.com/spf13/viper v1.3.1/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
@@ -197,25 +195,24 @@ go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/
go.uber.org/zap v1.9.1 h1:XCJQEf3W6eZaVwhRBof6ImoYGJSITeKWsyeh3HFu/5o=
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16 h1:y6ce7gCWtnH+m3dCjzQ1PCuwl28DDIc3VNnvY29DlIA=
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190103213133-ff983b9c42bc/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190130090550-b01c7a725664 h1:YbZJ76lQ1BqNhVe7dKTSB67wDrc2VPRR75IyGyyPDX8=
golang.org/x/crypto v0.0.0-20190130090550-b01c7a725664/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190131182504-b8fe1690c613 h1:MQ/ZZiDsUapFFiMS+vzwXkCTeEKaum+Do5rINYJDmxc=
golang.org/x/crypto v0.0.0-20190131182504-b8fe1690c613/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190222235706-ffb98f73852f h1:qWFY9ZxP3tfI37wYIs/MnIAqK0vlXp1xnYEa5HxFSSY=
golang.org/x/crypto v0.0.0-20190222235706-ffb98f73852f/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/image v0.0.0-20190220214146-31aff87c08e9 h1:+vH8qNweCrORN49012OX3h0oWEXO3p+rRnpAGQinddk=
golang.org/x/image v0.0.0-20190220214146-31aff87c08e9/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/net v0.0.0-20190110200230-915654e7eabc h1:Yx9JGxI1SBhVLFjpAkWMaO1TF+xyqtHLjZpvQboJGiM=
golang.org/x/net v0.0.0-20190110200230-915654e7eabc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181212120007-b05ddf57801d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190109145017-48ac38b7c8cb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc h1:WiYx1rIFmx8c0mXAFtv5D/mHyKe1+jmuP7PViuwqwuQ=
golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222171317-cd391775e71e h1:oF7qaQxUH6KzFdKN4ww7NpPdo53SZi4UlcksLrb2y/o=
golang.org/x/sys v0.0.0-20190222171317-cd391775e71e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -233,5 +230,3 @@ maunium.net/go/mauflag v1.0.0/go.mod h1:nLivPOpTpHnpzEh8jEdSL9UqO9+/KBJFmNRlwKfk
maunium.net/go/maulogger/v2 v2.0.0/go.mod h1:Hbbkq3NV6jvJodByZu1mgEF3fpT7Kz9z0MjEZ3/BusI=
maunium.net/go/mautrix v0.1.0-alpha.3/go.mod h1:GTVu6WDHR+98DKOrYetWsXorvUeKQV3jsSWO6ScbuFI=
maunium.net/go/mautrix-appservice v0.1.0-alpha.3/go.mod h1:wOnWOIuprYad7ly12rHIo3JLCPh4jwvx1prVrAB9RhM=
maunium.net/go/mautrix-whatsapp v0.0.0-20190127121751-281b3e8f77f3 h1:A18t5Lp7I3aK0V7B7zdpb0hb/PBlu0X/Ai2AyU/XEk4=
maunium.net/go/mautrix-whatsapp v0.0.0-20190127121751-281b3e8f77f3/go.mod h1:r5E3J4urDEsjfui9OYZYMLBfCliaAqcCwM2xeczta6k=

View File

@@ -15,7 +15,7 @@ import (
)
var (
version = "1.14.0-rc1"
version = "1.14.0-rc2"
githash string
flagConfig = flag.String("conf", "matterbridge.toml", "config file")

View File

@@ -913,6 +913,11 @@ QuoteDisable=false
#OPTIONAL (default "{MESSAGE} (re @{QUOTENICK}: {QUOTEMESSAGE})")
QuoteFormat="{MESSAGE} (re @{QUOTENICK}: {QUOTEMESSAGE})"
#Convert WebP images to PNG before upload.
#https://github.com/42wim/matterbridge/issues/398
#OPTIONAL (default false)
MediaConvertWebPToPNG=false
#Disable sending of edits to other bridges
#OPTIONAL (default false)
EditDisable=false
@@ -1358,12 +1363,6 @@ Login="yourbot-bot@yourserver.zulipchat.com"
#REQUIRED
Server="https://yourserver.zulipchat.com"
#Topic of the messages matterbridge will use
#OPTIONAL (default "matterbridge")
#You can specify a specific topic for each channel using [gateway.inout.options]
#See more information below at the gateway configuration
Topic="matterbridge"
## RELOADABLE SETTINGS
## Settings below can be reloaded by editing the file
@@ -1603,7 +1602,7 @@ enable=true
# if you specify an empty string bridge will list all the possibilities
# - "Group Name" if you specify a group name the bridge will hint its JID to specify
# as group names might change in time and contain weird emoticons
# zulip - stream (without the #)
# zulip - stream/topic:topicname (without the #)
#
# REQUIRED
channel="#testing"
@@ -1645,10 +1644,7 @@ enable=true
[[gateway.inout]]
account="zulip.streamchat"
channel="general"
#OPTIONAL - topic only works for zulip
[gateway.inout.options]
topic="topic1"
channel="general/topic:mytopic"
#API example
#[[gateway.inout]]

View File

@@ -2,7 +2,7 @@ package binary
import (
"fmt"
"github.com/Rhymen/go-whatsapp/binary/token"
"github.com/matterbridge/go-whatsapp/binary/token"
"io"
"strconv"
)

View File

@@ -2,7 +2,7 @@ package binary
import (
"fmt"
"github.com/Rhymen/go-whatsapp/binary/token"
"github.com/matterbridge/go-whatsapp/binary/token"
"math"
"strconv"
"strings"

View File

@@ -2,7 +2,7 @@ package binary
import (
"fmt"
pb "github.com/Rhymen/go-whatsapp/binary/proto"
pb "github.com/matterbridge/go-whatsapp/binary/proto"
"github.com/golang/protobuf/proto"
)

View File

@@ -14,9 +14,9 @@ import (
"sync"
"time"
"github.com/Rhymen/go-whatsapp/binary"
"github.com/Rhymen/go-whatsapp/crypto/cbc"
"github.com/gorilla/websocket"
"github.com/matterbridge/go-whatsapp/binary"
"github.com/matterbridge/go-whatsapp/crypto/cbc"
)
type metric byte
@@ -128,7 +128,7 @@ func NewConn(timeout time.Duration) (*Conn, error) {
go wac.readPump()
go wac.writePump()
go wac.keepAlive(20000, 90000)
go wac.keepAlive(20000, 60000)
return wac, nil
}

View File

@@ -2,7 +2,7 @@ package whatsapp
import (
"fmt"
"github.com/Rhymen/go-whatsapp/binary"
"github.com/matterbridge/go-whatsapp/binary"
"strconv"
"time"
)
@@ -13,8 +13,8 @@ const (
PresenceAvailable = "available"
PresenceUnavailable = "unavailable"
PresenceComposing = "composing"
PresenceRecording = "recording"
PresencePaused = "paused"
PresenceRecording = "recording"
PresencePaused = "paused"
)
//TODO: filename? WhatsApp uses Store.Contacts for these functions
@@ -30,44 +30,11 @@ func (wac *Conn) GetStatus(jid string) (<-chan string, error) {
return wac.write(data)
}
func (wac *Conn) GetGroupMetaData(jid string) (<-chan string, error) {
data := []interface{}{"query", "GroupMetadata", jid}
return wac.write(data)
}
func (wac *Conn) SubscribePresence(jid string) (<-chan string, error) {
data := []interface{}{"action", "presence", "subscribe", jid}
return wac.write(data)
}
func (wac *Conn) CreateGroup(subject string, participants []string) (<-chan string, error) {
return wac.setGroup("create", "", subject, participants)
}
func (wac *Conn) UpdateGroupSubject(subject string, jid string) (<-chan string, error) {
return wac.setGroup("subject", jid, subject, nil)
}
func (wac *Conn) SetAdmin(jid string, participants []string) (<-chan string, error) {
return wac.setGroup("promote", jid, "", participants)
}
func (wac *Conn) RemoveAdmin(jid string, participants []string) (<-chan string, error) {
return wac.setGroup("demote", jid, "", participants)
}
func (wac *Conn) AddMember(jid string, participants []string) (<-chan string, error) {
return wac.setGroup("add", jid, "", participants)
}
func (wac *Conn) RemoveMember(jid string, participants []string) (<-chan string, error) {
return wac.setGroup("remove", jid, "", participants)
}
func (wac *Conn) LeaveGroup(jid string) (<-chan string, error) {
return wac.setGroup("leave", jid, "", nil)
}
func (wac *Conn) Search(search string, count, page int) (*binary.Node, error) {
return wac.query("search", "", "", "", "", search, count, page)
}

View File

@@ -1,4 +1,4 @@
module github.com/Rhymen/go-whatsapp
module github.com/matterbridge/go-whatsapp
require (
github.com/golang/protobuf v1.2.0

View File

@@ -1,4 +1,7 @@
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
golang.org/x/crypto v0.0.0-20190131182504-b8fe1690c613 h1:MQ/ZZiDsUapFFiMS+vzwXkCTeEKaum+Do5rINYJDmxc=
golang.org/x/crypto v0.0.0-20190131182504-b8fe1690c613/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=

65
vendor/github.com/matterbridge/go-whatsapp/group.go generated vendored Normal file
View File

@@ -0,0 +1,65 @@
package whatsapp
import (
"encoding/json"
"fmt"
"time"
)
func (wac *Conn) GetGroupMetaData(jid string) (<-chan string, error) {
data := []interface{}{"query", "GroupMetadata", jid}
return wac.write(data)
}
func (wac *Conn) CreateGroup(subject string, participants []string) (<-chan string, error) {
return wac.setGroup("create", "", subject, participants)
}
func (wac *Conn) UpdateGroupSubject(subject string, jid string) (<-chan string, error) {
return wac.setGroup("subject", jid, subject, nil)
}
func (wac *Conn) SetAdmin(jid string, participants []string) (<-chan string, error) {
return wac.setGroup("promote", jid, "", participants)
}
func (wac *Conn) RemoveAdmin(jid string, participants []string) (<-chan string, error) {
return wac.setGroup("demote", jid, "", participants)
}
func (wac *Conn) AddMember(jid string, participants []string) (<-chan string, error) {
return wac.setGroup("add", jid, "", participants)
}
func (wac *Conn) RemoveMember(jid string, participants []string) (<-chan string, error) {
return wac.setGroup("remove", jid, "", participants)
}
func (wac *Conn) LeaveGroup(jid string) (<-chan string, error) {
return wac.setGroup("leave", jid, "", nil)
}
func (wac *Conn) GroupInviteLink(jid string) (string, error) {
request := []interface{}{"query", "inviteCode", jid}
ch, err := wac.write(request)
if err != nil {
return "", err
}
var response map[string]interface{}
select {
case r := <-ch:
if err := json.Unmarshal([]byte(r), &response); err != nil {
return "", fmt.Errorf("error decoding response message: %v\n", err)
}
case <-time.After(wac.msgTimeout):
return "", fmt.Errorf("request timed out")
}
if int(response["status"].(float64)) != 200 {
return "", fmt.Errorf("request responded with %d", response["status"])
}
return response["code"].(string), nil
}

View File

@@ -2,8 +2,8 @@ package whatsapp
import (
"fmt"
"github.com/Rhymen/go-whatsapp/binary"
"github.com/Rhymen/go-whatsapp/binary/proto"
"github.com/matterbridge/go-whatsapp/binary"
"github.com/matterbridge/go-whatsapp/binary/proto"
"os"
)

View File

@@ -8,8 +8,8 @@ import (
"encoding/base64"
"encoding/json"
"fmt"
"github.com/Rhymen/go-whatsapp/crypto/cbc"
"github.com/Rhymen/go-whatsapp/crypto/hkdf"
"github.com/matterbridge/go-whatsapp/crypto/cbc"
"github.com/matterbridge/go-whatsapp/crypto/hkdf"
"io"
"io/ioutil"
"mime/multipart"

View File

@@ -4,8 +4,8 @@ import (
"encoding/hex"
"encoding/json"
"fmt"
"github.com/Rhymen/go-whatsapp/binary"
"github.com/Rhymen/go-whatsapp/binary/proto"
"github.com/matterbridge/go-whatsapp/binary"
"github.com/matterbridge/go-whatsapp/binary/proto"
"io"
"math/rand"
"strconv"
@@ -363,6 +363,7 @@ type DocumentMessage struct {
Title string
PageCount uint32
Type string
FileName string
Thumbnail []byte
Content io.Reader
url string
@@ -376,15 +377,16 @@ func getDocumentMessage(msg *proto.WebMessageInfo) DocumentMessage {
doc := msg.GetMessage().GetDocumentMessage()
return DocumentMessage{
Info: getMessageInfo(msg),
Title: doc.GetTitle(),
PageCount: doc.GetPageCount(),
Type: doc.GetMimetype(),
FileName: doc.GetFileName(),
Thumbnail: doc.GetJpegThumbnail(),
url: doc.GetUrl(),
mediaKey: doc.GetMediaKey(),
fileEncSha256: doc.GetFileEncSha256(),
fileSha256: doc.GetFileSha256(),
fileLength: doc.GetFileLength(),
PageCount: doc.GetPageCount(),
Title: doc.GetTitle(),
Type: doc.GetMimetype(),
}
}

View File

@@ -9,9 +9,9 @@ import (
"fmt"
"time"
"github.com/Rhymen/go-whatsapp/crypto/cbc"
"github.com/Rhymen/go-whatsapp/crypto/curve25519"
"github.com/Rhymen/go-whatsapp/crypto/hkdf"
"github.com/matterbridge/go-whatsapp/crypto/cbc"
"github.com/matterbridge/go-whatsapp/crypto/curve25519"
"github.com/matterbridge/go-whatsapp/crypto/hkdf"
)
/*

View File

@@ -1,7 +1,7 @@
package whatsapp
import (
"github.com/Rhymen/go-whatsapp/binary"
"github.com/matterbridge/go-whatsapp/binary"
"strings"
)

View File

@@ -20,7 +20,7 @@ import (
"encoding/json"
"strings"
"github.com/Rhymen/go-whatsapp"
"github.com/matterbridge/go-whatsapp"
)
type ChatUpdateCommand string

View File

@@ -20,7 +20,7 @@ import (
"encoding/json"
"strings"
"github.com/Rhymen/go-whatsapp"
"github.com/matterbridge/go-whatsapp"
)
type CommandType string

View File

@@ -19,7 +19,7 @@ package whatsappExt
import (
"encoding/json"
"github.com/Rhymen/go-whatsapp"
"github.com/matterbridge/go-whatsapp"
)
type ConnInfo struct {

View File

@@ -19,7 +19,7 @@ package whatsappExt
import (
"encoding/json"
"github.com/Rhymen/go-whatsapp"
"github.com/matterbridge/go-whatsapp"
)
type JSONMessage []json.RawMessage

View File

@@ -20,7 +20,7 @@ import (
"encoding/json"
"strings"
"github.com/Rhymen/go-whatsapp"
"github.com/matterbridge/go-whatsapp"
)
type MsgInfoCommand string

View File

@@ -20,7 +20,7 @@ import (
"encoding/json"
"strings"
"github.com/Rhymen/go-whatsapp"
"github.com/matterbridge/go-whatsapp"
)
type PresenceType string

View File

@@ -19,7 +19,7 @@ package whatsappExt
import (
"encoding/json"
"github.com/Rhymen/go-whatsapp"
"github.com/matterbridge/go-whatsapp"
)
type ProtocolProps struct {

View File

@@ -19,7 +19,7 @@ package whatsappExt
import (
"encoding/json"
"github.com/Rhymen/go-whatsapp"
"github.com/matterbridge/go-whatsapp"
)
type StreamType string

View File

@@ -24,7 +24,7 @@ import (
"net/http"
"strings"
"github.com/Rhymen/go-whatsapp"
"github.com/matterbridge/go-whatsapp"
)
const (

View File

@@ -29,6 +29,15 @@ const (
backgroundMask = (backgroundRed | backgroundBlue | backgroundGreen | backgroundIntensity)
)
const (
genericRead = 0x80000000
genericWrite = 0x40000000
)
const (
consoleTextmodeBuffer = 0x1
)
type wchar uint16
type short int16
type dword uint32
@@ -69,14 +78,17 @@ var (
procGetConsoleCursorInfo = kernel32.NewProc("GetConsoleCursorInfo")
procSetConsoleCursorInfo = kernel32.NewProc("SetConsoleCursorInfo")
procSetConsoleTitle = kernel32.NewProc("SetConsoleTitleW")
procCreateConsoleScreenBuffer = kernel32.NewProc("CreateConsoleScreenBuffer")
)
// Writer provide colorable Writer to the console
type Writer struct {
out io.Writer
handle syscall.Handle
oldattr word
oldpos coord
out io.Writer
handle syscall.Handle
althandle syscall.Handle
oldattr word
oldpos coord
rest bytes.Buffer
}
// NewColorable return new instance of Writer which handle escape sequence from File.
@@ -407,7 +419,18 @@ func (w *Writer) Write(data []byte) (n int, err error) {
var csbi consoleScreenBufferInfo
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
er := bytes.NewReader(data)
handle := w.handle
var er *bytes.Reader
if w.rest.Len() > 0 {
var rest bytes.Buffer
w.rest.WriteTo(&rest)
w.rest.Reset()
rest.Write(data)
er = bytes.NewReader(rest.Bytes())
} else {
er = bytes.NewReader(data)
}
var bw [1]byte
loop:
for {
@@ -425,29 +448,55 @@ loop:
break loop
}
if c2 == ']' {
if err := doTitleSequence(er); err != nil {
switch c2 {
case '>':
continue
case ']':
w.rest.WriteByte(c1)
w.rest.WriteByte(c2)
er.WriteTo(&w.rest)
if bytes.IndexByte(w.rest.Bytes(), 0x07) == -1 {
break loop
}
continue
}
if c2 != 0x5b {
continue
}
var buf bytes.Buffer
var m byte
for {
c, err := er.ReadByte()
er = bytes.NewReader(w.rest.Bytes()[2:])
err := doTitleSequence(er)
if err != nil {
break loop
}
w.rest.Reset()
continue
// https://github.com/mattn/go-colorable/issues/27
case '7':
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
w.oldpos = csbi.cursorPosition
continue
case '8':
procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&w.oldpos)))
continue
case 0x5b:
// execute part after switch
default:
continue
}
w.rest.WriteByte(c1)
w.rest.WriteByte(c2)
er.WriteTo(&w.rest)
var buf bytes.Buffer
var m byte
for i, c := range w.rest.Bytes()[2:] {
if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' {
m = c
er = bytes.NewReader(w.rest.Bytes()[2+i+1:])
w.rest.Reset()
break
}
buf.Write([]byte(string(c)))
}
if m == 0 {
break loop
}
switch m {
case 'A':
@@ -455,61 +504,64 @@ loop:
if err != nil {
continue
}
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
csbi.cursorPosition.y -= short(n)
procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
case 'B':
n, err = strconv.Atoi(buf.String())
if err != nil {
continue
}
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
csbi.cursorPosition.y += short(n)
procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
case 'C':
n, err = strconv.Atoi(buf.String())
if err != nil {
continue
}
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
csbi.cursorPosition.x += short(n)
procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
case 'D':
n, err = strconv.Atoi(buf.String())
if err != nil {
continue
}
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
csbi.cursorPosition.x -= short(n)
procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
if csbi.cursorPosition.x < 0 {
csbi.cursorPosition.x = 0
}
procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
case 'E':
n, err = strconv.Atoi(buf.String())
if err != nil {
continue
}
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
csbi.cursorPosition.x = 0
csbi.cursorPosition.y += short(n)
procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
case 'F':
n, err = strconv.Atoi(buf.String())
if err != nil {
continue
}
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
csbi.cursorPosition.x = 0
csbi.cursorPosition.y -= short(n)
procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
case 'G':
n, err = strconv.Atoi(buf.String())
if err != nil {
continue
}
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
csbi.cursorPosition.x = short(n - 1)
procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
case 'H', 'f':
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
if buf.Len() > 0 {
token := strings.Split(buf.String(), ";")
switch len(token) {
@@ -534,7 +586,7 @@ loop:
} else {
csbi.cursorPosition.y = 0
}
procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
case 'J':
n := 0
if buf.Len() > 0 {
@@ -545,20 +597,20 @@ loop:
}
var count, written dword
var cursor coord
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
switch n {
case 0:
cursor = coord{x: csbi.cursorPosition.x, y: csbi.cursorPosition.y}
count = dword(csbi.size.x - csbi.cursorPosition.x + (csbi.size.y-csbi.cursorPosition.y)*csbi.size.x)
count = dword(csbi.size.x) - dword(csbi.cursorPosition.x) + dword(csbi.size.y-csbi.cursorPosition.y)*dword(csbi.size.x)
case 1:
cursor = coord{x: csbi.window.left, y: csbi.window.top}
count = dword(csbi.size.x - csbi.cursorPosition.x + (csbi.window.top-csbi.cursorPosition.y)*csbi.size.x)
count = dword(csbi.size.x) - dword(csbi.cursorPosition.x) + dword(csbi.window.top-csbi.cursorPosition.y)*dword(csbi.size.x)
case 2:
cursor = coord{x: csbi.window.left, y: csbi.window.top}
count = dword(csbi.size.x - csbi.cursorPosition.x + (csbi.size.y-csbi.cursorPosition.y)*csbi.size.x)
count = dword(csbi.size.x) - dword(csbi.cursorPosition.x) + dword(csbi.size.y-csbi.cursorPosition.y)*dword(csbi.size.x)
}
procFillConsoleOutputCharacter.Call(uintptr(w.handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
procFillConsoleOutputAttribute.Call(uintptr(w.handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
procFillConsoleOutputCharacter.Call(uintptr(handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
procFillConsoleOutputAttribute.Call(uintptr(handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
case 'K':
n := 0
if buf.Len() > 0 {
@@ -567,28 +619,28 @@ loop:
continue
}
}
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
var cursor coord
var count, written dword
switch n {
case 0:
cursor = coord{x: csbi.cursorPosition.x + 1, y: csbi.cursorPosition.y}
count = dword(csbi.size.x - csbi.cursorPosition.x - 1)
cursor = coord{x: csbi.cursorPosition.x, y: csbi.cursorPosition.y}
count = dword(csbi.size.x - csbi.cursorPosition.x)
case 1:
cursor = coord{x: csbi.window.left, y: csbi.window.top + csbi.cursorPosition.y}
cursor = coord{x: csbi.window.left, y: csbi.cursorPosition.y}
count = dword(csbi.size.x - csbi.cursorPosition.x)
case 2:
cursor = coord{x: csbi.window.left, y: csbi.window.top + csbi.cursorPosition.y}
cursor = coord{x: csbi.window.left, y: csbi.cursorPosition.y}
count = dword(csbi.size.x)
}
procFillConsoleOutputCharacter.Call(uintptr(w.handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
procFillConsoleOutputAttribute.Call(uintptr(w.handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
procFillConsoleOutputCharacter.Call(uintptr(handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
procFillConsoleOutputAttribute.Call(uintptr(handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
case 'm':
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
attr := csbi.attributes
cs := buf.String()
if cs == "" {
procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(w.oldattr))
procSetConsoleTextAttribute.Call(uintptr(handle), uintptr(w.oldattr))
continue
}
token := strings.Split(cs, ";")
@@ -627,6 +679,21 @@ loop:
attr |= n256foreAttr[n256]
i += 2
}
} else if len(token) == 5 && token[i+1] == "2" {
var r, g, b int
r, _ = strconv.Atoi(token[i+2])
g, _ = strconv.Atoi(token[i+3])
b, _ = strconv.Atoi(token[i+4])
i += 4
if r > 127 {
attr |= foregroundRed
}
if g > 127 {
attr |= foregroundGreen
}
if b > 127 {
attr |= foregroundBlue
}
} else {
attr = attr & (w.oldattr & backgroundMask)
}
@@ -654,6 +721,21 @@ loop:
attr |= n256backAttr[n256]
i += 2
}
} else if len(token) == 5 && token[i+1] == "2" {
var r, g, b int
r, _ = strconv.Atoi(token[i+2])
g, _ = strconv.Atoi(token[i+3])
b, _ = strconv.Atoi(token[i+4])
i += 4
if r > 127 {
attr |= backgroundRed
}
if g > 127 {
attr |= backgroundGreen
}
if b > 127 {
attr |= backgroundBlue
}
} else {
attr = attr & (w.oldattr & foregroundMask)
}
@@ -685,38 +767,52 @@ loop:
attr |= backgroundBlue
}
}
procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(attr))
procSetConsoleTextAttribute.Call(uintptr(handle), uintptr(attr))
}
}
case 'h':
var ci consoleCursorInfo
cs := buf.String()
if cs == "5>" {
procGetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci)))
ci.visible = 0
procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci)))
} else if cs == "?25" {
procGetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci)))
ci.visible = 1
procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci)))
} else if cs == "?1049" {
if w.althandle == 0 {
h, _, _ := procCreateConsoleScreenBuffer.Call(uintptr(genericRead|genericWrite), 0, 0, uintptr(consoleTextmodeBuffer), 0, 0)
w.althandle = syscall.Handle(h)
if w.althandle != 0 {
handle = w.althandle
}
}
}
case 'l':
var ci consoleCursorInfo
cs := buf.String()
if cs == "5>" {
procGetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci)))
ci.visible = 1
procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci)))
} else if cs == "?25" {
procGetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci)))
ci.visible = 0
procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci)))
procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci)))
} else if cs == "?1049" {
if w.althandle != 0 {
syscall.CloseHandle(w.althandle)
w.althandle = 0
handle = w.handle
}
}
case 's':
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
w.oldpos = csbi.cursorPosition
case 'u':
procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&w.oldpos)))
procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&w.oldpos)))
}
}

3
vendor/github.com/mattn/go-colorable/go.mod generated vendored Normal file
View File

@@ -0,0 +1,3 @@
module github.com/mattn/go-colorable
require github.com/mattn/go-isatty v0.0.5

4
vendor/github.com/mattn/go-colorable/go.sum generated vendored Normal file
View File

@@ -0,0 +1,4 @@
github.com/mattn/go-isatty v0.0.5 h1:tHXDdz1cpzGaovsTB+TVB8q90WEokoVmfMqoVcrLUgw=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=

3
vendor/github.com/mattn/go-isatty/go.mod generated vendored Normal file
View File

@@ -0,0 +1,3 @@
module github.com/mattn/go-isatty
require golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223

2
vendor/github.com/mattn/go-isatty/go.sum generated vendored Normal file
View File

@@ -0,0 +1,2 @@
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=

View File

@@ -1,15 +0,0 @@
// +build appengine
package isatty
// IsTerminal returns true if the file descriptor is terminal which
// is always false on on appengine classic which is a sandboxed PaaS.
func IsTerminal(fd uintptr) bool {
return false
}
// IsCygwinTerminal() return true if the file descriptor is a cygwin or msys2
// terminal. This is also always false on this environment.
func IsCygwinTerminal(fd uintptr) bool {
return false
}

View File

@@ -16,3 +16,9 @@ func IsTerminal(fd uintptr) bool {
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
return err == 0
}
// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2
// terminal. This is also always false on this environment.
func IsCygwinTerminal(fd uintptr) bool {
return false
}

View File

@@ -1,18 +1,18 @@
// +build linux
// +build !appengine,!ppc64,!ppc64le
// +build !appengine
package isatty
import (
"syscall"
"unsafe"
)
const ioctlReadTermios = syscall.TCGETS
import "golang.org/x/sys/unix"
// IsTerminal return true if the file descriptor is terminal.
func IsTerminal(fd uintptr) bool {
var termios syscall.Termios
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
return err == 0
_, err := unix.IoctlGetTermios(int(fd), unix.TCGETS)
return err == nil
}
// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2
// terminal. This is also always false on this environment.
func IsCygwinTerminal(fd uintptr) bool {
return false
}

View File

@@ -1,19 +0,0 @@
// +build linux
// +build ppc64 ppc64le
package isatty
import (
"unsafe"
syscall "golang.org/x/sys/unix"
)
const ioctlReadTermios = syscall.TCGETS
// IsTerminal return true if the file descriptor is terminal.
func IsTerminal(fd uintptr) bool {
var termios syscall.Termios
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
return err == 0
}

View File

@@ -1,9 +1,14 @@
// +build !windows
// +build !appengine
// +build appengine js
package isatty
// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2
// IsTerminal returns true if the file descriptor is terminal which
// is always false on js and appengine classic which is a sandboxed PaaS.
func IsTerminal(fd uintptr) bool {
return false
}
// IsCygwinTerminal() return true if the file descriptor is a cygwin or msys2
// terminal. This is also always false on this environment.
func IsCygwinTerminal(fd uintptr) bool {
return false

View File

@@ -14,3 +14,9 @@ func IsTerminal(fd uintptr) bool {
err := unix.IoctlSetTermio(int(fd), unix.TCGETA, &termio)
return err == nil
}
// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2
// terminal. This is also always false on this environment.
func IsCygwinTerminal(fd uintptr) bool {
return false
}

View File

@@ -1,18 +1,17 @@
# Travis CI (http://travis-ci.org/) is a continuous integration service for
# open source projects. This file configures it to run unit tests for
# blackfriday.
sudo: false
language: go
go:
- 1.5
- 1.6
- 1.7
- "1.9.x"
- "1.10.x"
- tip
matrix:
fast_finish: true
allow_failures:
- go: tip
install:
- go get -d -t -v ./...
- go build -v ./...
- # Do nothing. This is needed to prevent default install action "go get -t -v ./..." from happening here (we want it to happen inside script step).
script:
- go test -v ./...
- go test -run=^$ -bench=BenchmarkReference -benchmem
- go get -t -v ./...
- diff -u <(echo -n) <(gofmt -d -s .)
- go tool vet .
- go test -v -race ./...

View File

@@ -1,4 +1,6 @@
Blackfriday [![Build Status](https://travis-ci.org/russross/blackfriday.svg?branch=master)](https://travis-ci.org/russross/blackfriday)
Blackfriday
[![Build Status][BuildSVG]][BuildURL]
[![Godoc][GodocV2SVG]][GodocV2URL]
===========
Blackfriday is a [Markdown][1] processor implemented in [Go][2]. It
@@ -16,27 +18,27 @@ It started as a translation from C of [Sundown][3].
Installation
------------
Blackfriday is compatible with any modern Go release. With Go 1.7 and git
installed:
Blackfriday is compatible with any modern Go release. With Go and git installed:
go get gopkg.in/russross/blackfriday.v2
go get -u gopkg.in/russross/blackfriday.v2
will download, compile, and install the package into your `$GOPATH`
directory hierarchy. Alternatively, you can achieve the same if you
import it into a project:
import "gopkg.in/russross/blackfriday.v2"
and `go get` without parameters.
will download, compile, and install the package into your `$GOPATH` directory
hierarchy.
Versions
--------
Currently maintained and recommended version of Blackfriday is `v2`. It's being
developed on its own branch: https://github.com/russross/blackfriday/v2. You
should install and import it via [gopkg.in][6] at
`gopkg.in/russross/blackfriday.v2`.
developed on its own branch: https://github.com/russross/blackfriday/tree/v2 and the
documentation is available at
https://godoc.org/gopkg.in/russross/blackfriday.v2.
It is `go get`-able via [gopkg.in][6] at `gopkg.in/russross/blackfriday.v2`,
but we highly recommend using package management tool like [dep][7] or
[Glide][8] and make use of semantic versioning. With package management you
should import `github.com/russross/blackfriday` and specify that you're using
version 2.0.0.
Version 2 offers a number of improvements over v1:
@@ -56,9 +58,43 @@ Potential drawbacks:
v2. See issue [#348](https://github.com/russross/blackfriday/issues/348) for
tracking.
If you are still interested in the legacy `v1`, you can import it from
`github.com/russross/blackfriday`. Documentation for the legacy v1 can be found
here: https://godoc.org/github.com/russross/blackfriday
### Known issue with `dep`
There is a known problem with using Blackfriday v1 _transitively_ and `dep`.
Currently `dep` prioritizes semver versions over anything else, and picks the
latest one, plus it does not apply a `[[constraint]]` specifier to transitively
pulled in packages. So if you're using something that uses Blackfriday v1, but
that something does not use `dep` yet, you will get Blackfriday v2 pulled in and
your first dependency will fail to build.
There are couple of fixes for it, documented here:
https://github.com/golang/dep/blob/master/docs/FAQ.md#how-do-i-constrain-a-transitive-dependencys-version
Meanwhile, `dep` team is working on a more general solution to the constraints
on transitive dependencies problem: https://github.com/golang/dep/issues/1124.
Usage
-----
### v1
For basic usage, it is as simple as getting your input into a byte
slice and calling:
output := blackfriday.MarkdownBasic(input)
This renders it with no extensions enabled. To get a more useful
feature set, use this instead:
output := blackfriday.MarkdownCommon(input)
### v2
For the most sensible markdown processing, it is as simple as getting your input
into a byte slice and calling:
@@ -85,7 +121,7 @@ Here's an example of simple usage of Blackfriday together with Bluemonday:
```go
import (
"github.com/microcosm-cc/bluemonday"
"github.com/russross/blackfriday"
"gopkg.in/russross/blackfriday.v2"
)
// ...
@@ -93,11 +129,21 @@ unsafe := blackfriday.Run(input)
html := bluemonday.UGCPolicy().SanitizeBytes(unsafe)
```
### Custom options
### Custom options, v1
If you want to customize the set of options, first get a renderer
(currently only the HTML output engine), then use it to
call the more general `Markdown` function. For examples, see the
implementations of `MarkdownBasic` and `MarkdownCommon` in
`markdown.go`.
### Custom options, v2
If you want to customize the set of options, use `blackfriday.WithExtensions`,
`blackfriday.WithRenderer` and `blackfriday.WithRefOverride`.
### `blackfriday-tool`
You can also check out `blackfriday-tool` for a more complete example
of how to use it. Download and install it using:
@@ -117,6 +163,22 @@ installed in `$GOPATH/bin`. This is a statically-linked binary that
can be copied to wherever you need it without worrying about
dependencies and library versions.
### Sanitized anchor names
Blackfriday includes an algorithm for creating sanitized anchor names
corresponding to a given input text. This algorithm is used to create
anchors for headings when `EXTENSION_AUTO_HEADER_IDS` is enabled. The
algorithm has a specification, so that other packages can create
compatible anchor names and links to those anchors.
The specification is located at https://godoc.org/github.com/russross/blackfriday#hdr-Sanitized_Anchor_Names.
[`SanitizedAnchorName`](https://godoc.org/github.com/russross/blackfriday#SanitizedAnchorName) exposes this functionality, and can be used to
create compatible links to the anchor names generated by blackfriday.
This algorithm is also implemented in a small standalone package at
[`github.com/shurcooL/sanitized_anchor_name`](https://godoc.org/github.com/shurcooL/sanitized_anchor_name). It can be useful for clients
that want a small package and don't need full functionality of blackfriday.
Features
--------
@@ -184,7 +246,7 @@ implements the following extensions:
and supply a language (to make syntax highlighting simple). Just
mark it like this:
```go
``` go
func getTrue() bool {
return true
}
@@ -193,6 +255,15 @@ implements the following extensions:
You can use 3 or more backticks to mark the beginning of the
block, and the same number to mark the end of the block.
To preserve classes of fenced code blocks while using the bluemonday
HTML sanitizer, use the following policy:
``` go
p := bluemonday.UGCPolicy()
p.AllowAttrs("class").Matching(regexp.MustCompile("^language-[a-zA-Z0-9]+$")).OnElements("code")
html := p.SanitizeBytes(unsafe)
```
* **Definition lists**. A simple definition list is made of a single-line
term followed by a colon and the definition for that term.
@@ -218,8 +289,10 @@ implements the following extensions:
* **Strikethrough**. Use two tildes (`~~`) to mark text that
should be crossed out.
* **Hard line breaks**. With this extension enabled newlines in the input
translate into line breaks in the output. This extension is off by default.
* **Hard line breaks**. With this extension enabled (it is off by
default in the `MarkdownBasic` and `MarkdownCommon` convenience
functions), newlines in the input translate into line breaks in
the output.
* **Smart quotes**. Smartypants-style punctuation substitution is
supported, turning normal double- and single-quote marks into
@@ -258,15 +331,21 @@ are a few of note:
* [LaTeX output](https://bitbucket.org/ambrevar/blackfriday-latex):
renders output as LaTeX.
* [bfchroma](https://github.com/Depado/bfchroma/): provides convenience
integration with the [Chroma](https://github.com/alecthomas/chroma) code
highlighting library. bfchroma is only compatible with v2 of Blackfriday and
provides a drop-in renderer ready to use with Blackfriday, as well as
options and means for further customization.
Todo
TODO
----
* More unit testing
* Improve unicode support. It does not understand all unicode
* Improve Unicode support. It does not understand all Unicode
rules (about what constitutes a letter, a punctuation symbol,
etc.), so it may fail to detect word boundaries correctly in
some instances. It is safe on all utf-8 input.
some instances. It is safe on all UTF-8 input.
License
@@ -281,3 +360,10 @@ License
[4]: https://godoc.org/gopkg.in/russross/blackfriday.v2#Parse "Parse func"
[5]: https://github.com/microcosm-cc/bluemonday "Bluemonday"
[6]: https://labix.org/gopkg.in "gopkg.in"
[7]: https://github.com/golang/dep/ "dep"
[8]: https://github.com/Masterminds/glide "Glide"
[BuildSVG]: https://travis-ci.org/russross/blackfriday.svg?branch=master
[BuildURL]: https://travis-ci.org/russross/blackfriday
[GodocV2SVG]: https://godoc.org/gopkg.in/russross/blackfriday.v2?status.svg
[GodocV2URL]: https://godoc.org/gopkg.in/russross/blackfriday.v2

File diff suppressed because it is too large Load Diff

View File

@@ -1,18 +1,32 @@
// Package blackfriday is a markdown processor.
// Package blackfriday is a Markdown processor.
//
// It translates plain text with simple formatting rules into an AST, which can
// then be further processed to HTML (provided by Blackfriday itself) or other
// formats (provided by the community).
// It translates plain text with simple formatting rules into HTML or LaTeX.
//
// The simplest way to invoke Blackfriday is to call the Run function. It will
// take a text input and produce a text output in HTML (or other format).
// Sanitized Anchor Names
//
// A slightly more sophisticated way to use Blackfriday is to create a Markdown
// processor and to call Parse, which returns a syntax tree for the input
// document. You can leverage Blackfriday's parsing for content extraction from
// markdown documents. You can assign a custom renderer and set various options
// to the Markdown processor.
// Blackfriday includes an algorithm for creating sanitized anchor names
// corresponding to a given input text. This algorithm is used to create
// anchors for headings when EXTENSION_AUTO_HEADER_IDS is enabled. The
// algorithm is specified below, so that other packages can create
// compatible anchor names and links to those anchors.
//
// If you're interested in calling Blackfriday from command line, see
// https://github.com/russross/blackfriday-tool.
// The algorithm iterates over the input text, interpreted as UTF-8,
// one Unicode code point (rune) at a time. All runes that are letters (category L)
// or numbers (category N) are considered valid characters. They are mapped to
// lower case, and included in the output. All other runes are considered
// invalid characters. Invalid characters that preceed the first valid character,
// as well as invalid character that follow the last valid character
// are dropped completely. All other sequences of invalid characters
// between two valid characters are replaced with a single dash character '-'.
//
// SanitizedAnchorName exposes this functionality, and can be used to
// create compatible links to the anchor names generated by blackfriday.
// This algorithm is also implemented in a small standalone package at
// github.com/shurcooL/sanitized_anchor_name. It can be useful for clients
// that want a small package and don't need full functionality of blackfriday.
package blackfriday
// NOTE: Keep Sanitized Anchor Name algorithm in sync with package
// github.com/shurcooL/sanitized_anchor_name.
// Otherwise, users of sanitized_anchor_name will get anchor names
// that are incompatible with those generated by blackfriday.

View File

@@ -1,34 +0,0 @@
package blackfriday
import (
"html"
"io"
)
var htmlEscaper = [256][]byte{
'&': []byte("&amp;"),
'<': []byte("&lt;"),
'>': []byte("&gt;"),
'"': []byte("&quot;"),
}
func escapeHTML(w io.Writer, s []byte) {
var start, end int
for end < len(s) {
escSeq := htmlEscaper[s[end]]
if escSeq != nil {
w.Write(s[start:end])
w.Write(escSeq)
start = end + 1
}
end++
}
if start < len(s) && end <= len(s) {
w.Write(s[start:end])
}
}
func escLink(w io.Writer, text []byte) {
unesc := html.UnescapeString(string(text))
escapeHTML(w, []byte(unesc))
}

1
vendor/github.com/russross/blackfriday/go.mod generated vendored Normal file
View File

@@ -0,0 +1 @@
module github.com/russross/blackfriday

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

334
vendor/github.com/russross/blackfriday/latex.go generated vendored Normal file
View File

@@ -0,0 +1,334 @@
//
// Blackfriday Markdown Processor
// Available at http://github.com/russross/blackfriday
//
// Copyright © 2011 Russ Ross <russ@russross.com>.
// Distributed under the Simplified BSD License.
// See README.md for details.
//
//
//
// LaTeX rendering backend
//
//
package blackfriday
import (
"bytes"
"strings"
)
// Latex is a type that implements the Renderer interface for LaTeX output.
//
// Do not create this directly, instead use the LatexRenderer function.
type Latex struct {
}
// LatexRenderer creates and configures a Latex object, which
// satisfies the Renderer interface.
//
// flags is a set of LATEX_* options ORed together (currently no such options
// are defined).
func LatexRenderer(flags int) Renderer {
return &Latex{}
}
func (options *Latex) GetFlags() int {
return 0
}
// render code chunks using verbatim, or listings if we have a language
func (options *Latex) BlockCode(out *bytes.Buffer, text []byte, info string) {
if info == "" {
out.WriteString("\n\\begin{verbatim}\n")
} else {
lang := strings.Fields(info)[0]
out.WriteString("\n\\begin{lstlisting}[language=")
out.WriteString(lang)
out.WriteString("]\n")
}
out.Write(text)
if info == "" {
out.WriteString("\n\\end{verbatim}\n")
} else {
out.WriteString("\n\\end{lstlisting}\n")
}
}
func (options *Latex) TitleBlock(out *bytes.Buffer, text []byte) {
}
func (options *Latex) BlockQuote(out *bytes.Buffer, text []byte) {
out.WriteString("\n\\begin{quotation}\n")
out.Write(text)
out.WriteString("\n\\end{quotation}\n")
}
func (options *Latex) BlockHtml(out *bytes.Buffer, text []byte) {
// a pretty lame thing to do...
out.WriteString("\n\\begin{verbatim}\n")
out.Write(text)
out.WriteString("\n\\end{verbatim}\n")
}
func (options *Latex) Header(out *bytes.Buffer, text func() bool, level int, id string) {
marker := out.Len()
switch level {
case 1:
out.WriteString("\n\\section{")
case 2:
out.WriteString("\n\\subsection{")
case 3:
out.WriteString("\n\\subsubsection{")
case 4:
out.WriteString("\n\\paragraph{")
case 5:
out.WriteString("\n\\subparagraph{")
case 6:
out.WriteString("\n\\textbf{")
}
if !text() {
out.Truncate(marker)
return
}
out.WriteString("}\n")
}
func (options *Latex) HRule(out *bytes.Buffer) {
out.WriteString("\n\\HRule\n")
}
func (options *Latex) List(out *bytes.Buffer, text func() bool, flags int) {
marker := out.Len()
if flags&LIST_TYPE_ORDERED != 0 {
out.WriteString("\n\\begin{enumerate}\n")
} else {
out.WriteString("\n\\begin{itemize}\n")
}
if !text() {
out.Truncate(marker)
return
}
if flags&LIST_TYPE_ORDERED != 0 {
out.WriteString("\n\\end{enumerate}\n")
} else {
out.WriteString("\n\\end{itemize}\n")
}
}
func (options *Latex) ListItem(out *bytes.Buffer, text []byte, flags int) {
out.WriteString("\n\\item ")
out.Write(text)
}
func (options *Latex) Paragraph(out *bytes.Buffer, text func() bool) {
marker := out.Len()
out.WriteString("\n")
if !text() {
out.Truncate(marker)
return
}
out.WriteString("\n")
}
func (options *Latex) Table(out *bytes.Buffer, header []byte, body []byte, columnData []int) {
out.WriteString("\n\\begin{tabular}{")
for _, elt := range columnData {
switch elt {
case TABLE_ALIGNMENT_LEFT:
out.WriteByte('l')
case TABLE_ALIGNMENT_RIGHT:
out.WriteByte('r')
default:
out.WriteByte('c')
}
}
out.WriteString("}\n")
out.Write(header)
out.WriteString(" \\\\\n\\hline\n")
out.Write(body)
out.WriteString("\n\\end{tabular}\n")
}
func (options *Latex) TableRow(out *bytes.Buffer, text []byte) {
if out.Len() > 0 {
out.WriteString(" \\\\\n")
}
out.Write(text)
}
func (options *Latex) TableHeaderCell(out *bytes.Buffer, text []byte, align int) {
if out.Len() > 0 {
out.WriteString(" & ")
}
out.Write(text)
}
func (options *Latex) TableCell(out *bytes.Buffer, text []byte, align int) {
if out.Len() > 0 {
out.WriteString(" & ")
}
out.Write(text)
}
// TODO: this
func (options *Latex) Footnotes(out *bytes.Buffer, text func() bool) {
}
func (options *Latex) FootnoteItem(out *bytes.Buffer, name, text []byte, flags int) {
}
func (options *Latex) AutoLink(out *bytes.Buffer, link []byte, kind int) {
out.WriteString("\\href{")
if kind == LINK_TYPE_EMAIL {
out.WriteString("mailto:")
}
out.Write(link)
out.WriteString("}{")
out.Write(link)
out.WriteString("}")
}
func (options *Latex) CodeSpan(out *bytes.Buffer, text []byte) {
out.WriteString("\\texttt{")
escapeSpecialChars(out, text)
out.WriteString("}")
}
func (options *Latex) DoubleEmphasis(out *bytes.Buffer, text []byte) {
out.WriteString("\\textbf{")
out.Write(text)
out.WriteString("}")
}
func (options *Latex) Emphasis(out *bytes.Buffer, text []byte) {
out.WriteString("\\textit{")
out.Write(text)
out.WriteString("}")
}
func (options *Latex) Image(out *bytes.Buffer, link []byte, title []byte, alt []byte) {
if bytes.HasPrefix(link, []byte("http://")) || bytes.HasPrefix(link, []byte("https://")) {
// treat it like a link
out.WriteString("\\href{")
out.Write(link)
out.WriteString("}{")
out.Write(alt)
out.WriteString("}")
} else {
out.WriteString("\\includegraphics{")
out.Write(link)
out.WriteString("}")
}
}
func (options *Latex) LineBreak(out *bytes.Buffer) {
out.WriteString(" \\\\\n")
}
func (options *Latex) Link(out *bytes.Buffer, link []byte, title []byte, content []byte) {
out.WriteString("\\href{")
out.Write(link)
out.WriteString("}{")
out.Write(content)
out.WriteString("}")
}
func (options *Latex) RawHtmlTag(out *bytes.Buffer, tag []byte) {
}
func (options *Latex) TripleEmphasis(out *bytes.Buffer, text []byte) {
out.WriteString("\\textbf{\\textit{")
out.Write(text)
out.WriteString("}}")
}
func (options *Latex) StrikeThrough(out *bytes.Buffer, text []byte) {
out.WriteString("\\sout{")
out.Write(text)
out.WriteString("}")
}
// TODO: this
func (options *Latex) FootnoteRef(out *bytes.Buffer, ref []byte, id int) {
}
func needsBackslash(c byte) bool {
for _, r := range []byte("_{}%$&\\~#") {
if c == r {
return true
}
}
return false
}
func escapeSpecialChars(out *bytes.Buffer, text []byte) {
for i := 0; i < len(text); i++ {
// directly copy normal characters
org := i
for i < len(text) && !needsBackslash(text[i]) {
i++
}
if i > org {
out.Write(text[org:i])
}
// escape a character
if i >= len(text) {
break
}
out.WriteByte('\\')
out.WriteByte(text[i])
}
}
func (options *Latex) Entity(out *bytes.Buffer, entity []byte) {
// TODO: convert this into a unicode character or something
out.Write(entity)
}
func (options *Latex) NormalText(out *bytes.Buffer, text []byte) {
escapeSpecialChars(out, text)
}
// header and footer
func (options *Latex) DocumentHeader(out *bytes.Buffer) {
out.WriteString("\\documentclass{article}\n")
out.WriteString("\n")
out.WriteString("\\usepackage{graphicx}\n")
out.WriteString("\\usepackage{listings}\n")
out.WriteString("\\usepackage[margin=1in]{geometry}\n")
out.WriteString("\\usepackage[utf8]{inputenc}\n")
out.WriteString("\\usepackage{verbatim}\n")
out.WriteString("\\usepackage[normalem]{ulem}\n")
out.WriteString("\\usepackage{hyperref}\n")
out.WriteString("\n")
out.WriteString("\\hypersetup{colorlinks,%\n")
out.WriteString(" citecolor=black,%\n")
out.WriteString(" filecolor=black,%\n")
out.WriteString(" linkcolor=black,%\n")
out.WriteString(" urlcolor=black,%\n")
out.WriteString(" pdfstartview=FitH,%\n")
out.WriteString(" breaklinks=true,%\n")
out.WriteString(" pdfauthor={Blackfriday Markdown Processor v")
out.WriteString(VERSION)
out.WriteString("}}\n")
out.WriteString("\n")
out.WriteString("\\newcommand{\\HRule}{\\rule{\\linewidth}{0.5mm}}\n")
out.WriteString("\\addtolength{\\parskip}{0.5\\baselineskip}\n")
out.WriteString("\\parindent=0pt\n")
out.WriteString("\n")
out.WriteString("\\begin{document}\n")
}
func (options *Latex) DocumentFooter(out *bytes.Buffer) {
out.WriteString("\n\\end{document}\n")
}

View File

@@ -1,200 +1,230 @@
//
// Blackfriday Markdown Processor
// Available at http://github.com/russross/blackfriday
//
// Copyright © 2011 Russ Ross <russ@russross.com>.
// Distributed under the Simplified BSD License.
// See README.md for details.
//
//
//
// Markdown parsing and processing
//
//
package blackfriday
import (
"bytes"
"fmt"
"io"
"strings"
"unicode/utf8"
)
//
// Markdown parsing and processing
//
// Version string of the package. Appears in the rendered document when
// CompletePage flag is on.
const Version = "2.0"
// Extensions is a bitwise or'ed collection of enabled Blackfriday's
// extensions.
type Extensions int
const VERSION = "1.5"
// These are the supported markdown parsing extensions.
// OR these values together to select multiple extensions.
const (
NoExtensions Extensions = 0
NoIntraEmphasis Extensions = 1 << iota // Ignore emphasis markers inside words
Tables // Render tables
FencedCode // Render fenced code blocks
Autolink // Detect embedded URLs that are not explicitly marked
Strikethrough // Strikethrough text using ~~test~~
LaxHTMLBlocks // Loosen up HTML block parsing rules
SpaceHeadings // Be strict about prefix heading rules
HardLineBreak // Translate newlines into line breaks
TabSizeEight // Expand tabs to eight spaces instead of four
Footnotes // Pandoc-style footnotes
NoEmptyLineBeforeBlock // No need to insert an empty line to start a (code, quote, ordered list, unordered list) block
HeadingIDs // specify heading IDs with {#id}
Titleblock // Titleblock ala pandoc
AutoHeadingIDs // Create the heading ID from the text
BackslashLineBreak // Translate trailing backslashes into line breaks
DefinitionLists // Render definition lists
EXTENSION_NO_INTRA_EMPHASIS = 1 << iota // ignore emphasis markers inside words
EXTENSION_TABLES // render tables
EXTENSION_FENCED_CODE // render fenced code blocks
EXTENSION_AUTOLINK // detect embedded URLs that are not explicitly marked
EXTENSION_STRIKETHROUGH // strikethrough text using ~~test~~
EXTENSION_LAX_HTML_BLOCKS // loosen up HTML block parsing rules
EXTENSION_SPACE_HEADERS // be strict about prefix header rules
EXTENSION_HARD_LINE_BREAK // translate newlines into line breaks
EXTENSION_TAB_SIZE_EIGHT // expand tabs to eight spaces instead of four
EXTENSION_FOOTNOTES // Pandoc-style footnotes
EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK // No need to insert an empty line to start a (code, quote, ordered list, unordered list) block
EXTENSION_HEADER_IDS // specify header IDs with {#id}
EXTENSION_TITLEBLOCK // Titleblock ala pandoc
EXTENSION_AUTO_HEADER_IDS // Create the header ID from the text
EXTENSION_BACKSLASH_LINE_BREAK // translate trailing backslashes into line breaks
EXTENSION_DEFINITION_LISTS // render definition lists
EXTENSION_JOIN_LINES // delete newline and join lines
CommonHTMLFlags HTMLFlags = UseXHTML | Smartypants |
SmartypantsFractions | SmartypantsDashes | SmartypantsLatexDashes
commonHtmlFlags = 0 |
HTML_USE_XHTML |
HTML_USE_SMARTYPANTS |
HTML_SMARTYPANTS_FRACTIONS |
HTML_SMARTYPANTS_DASHES |
HTML_SMARTYPANTS_LATEX_DASHES
CommonExtensions Extensions = NoIntraEmphasis | Tables | FencedCode |
Autolink | Strikethrough | SpaceHeadings | HeadingIDs |
BackslashLineBreak | DefinitionLists
commonExtensions = 0 |
EXTENSION_NO_INTRA_EMPHASIS |
EXTENSION_TABLES |
EXTENSION_FENCED_CODE |
EXTENSION_AUTOLINK |
EXTENSION_STRIKETHROUGH |
EXTENSION_SPACE_HEADERS |
EXTENSION_HEADER_IDS |
EXTENSION_BACKSLASH_LINE_BREAK |
EXTENSION_DEFINITION_LISTS
)
// ListType contains bitwise or'ed flags for list and list item objects.
type ListType int
// These are the possible flag values for the link renderer.
// Only a single one of these values will be used; they are not ORed together.
// These are mostly of interest if you are writing a new output format.
const (
LINK_TYPE_NOT_AUTOLINK = iota
LINK_TYPE_NORMAL
LINK_TYPE_EMAIL
)
// These are the possible flag values for the ListItem renderer.
// Multiple flag values may be ORed together.
// These are mostly of interest if you are writing a new output format.
const (
ListTypeOrdered ListType = 1 << iota
ListTypeDefinition
ListTypeTerm
ListItemContainsBlock
ListItemBeginningOfList // TODO: figure out if this is of any use now
ListItemEndOfList
LIST_TYPE_ORDERED = 1 << iota
LIST_TYPE_DEFINITION
LIST_TYPE_TERM
LIST_ITEM_CONTAINS_BLOCK
LIST_ITEM_BEGINNING_OF_LIST
LIST_ITEM_END_OF_LIST
)
// CellAlignFlags holds a type of alignment in a table cell.
type CellAlignFlags int
// These are the possible flag values for the table cell renderer.
// Only a single one of these values will be used; they are not ORed together.
// These are mostly of interest if you are writing a new output format.
const (
TableAlignmentLeft CellAlignFlags = 1 << iota
TableAlignmentRight
TableAlignmentCenter = (TableAlignmentLeft | TableAlignmentRight)
TABLE_ALIGNMENT_LEFT = 1 << iota
TABLE_ALIGNMENT_RIGHT
TABLE_ALIGNMENT_CENTER = (TABLE_ALIGNMENT_LEFT | TABLE_ALIGNMENT_RIGHT)
)
// The size of a tab stop.
const (
TabSizeDefault = 4
TabSizeDouble = 8
TAB_SIZE_DEFAULT = 4
TAB_SIZE_EIGHT = 8
)
// blockTags is a set of tags that are recognized as HTML block tags.
// Any of these can be included in markdown text without special escaping.
var blockTags = map[string]struct{}{
"blockquote": struct{}{},
"del": struct{}{},
"div": struct{}{},
"dl": struct{}{},
"fieldset": struct{}{},
"form": struct{}{},
"h1": struct{}{},
"h2": struct{}{},
"h3": struct{}{},
"h4": struct{}{},
"h5": struct{}{},
"h6": struct{}{},
"iframe": struct{}{},
"ins": struct{}{},
"math": struct{}{},
"noscript": struct{}{},
"ol": struct{}{},
"pre": struct{}{},
"p": struct{}{},
"script": struct{}{},
"style": struct{}{},
"table": struct{}{},
"ul": struct{}{},
"blockquote": {},
"del": {},
"div": {},
"dl": {},
"fieldset": {},
"form": {},
"h1": {},
"h2": {},
"h3": {},
"h4": {},
"h5": {},
"h6": {},
"iframe": {},
"ins": {},
"math": {},
"noscript": {},
"ol": {},
"pre": {},
"p": {},
"script": {},
"style": {},
"table": {},
"ul": {},
// HTML5
"address": struct{}{},
"article": struct{}{},
"aside": struct{}{},
"canvas": struct{}{},
"figcaption": struct{}{},
"figure": struct{}{},
"footer": struct{}{},
"header": struct{}{},
"hgroup": struct{}{},
"main": struct{}{},
"nav": struct{}{},
"output": struct{}{},
"progress": struct{}{},
"section": struct{}{},
"video": struct{}{},
"address": {},
"article": {},
"aside": {},
"canvas": {},
"figcaption": {},
"figure": {},
"footer": {},
"header": {},
"hgroup": {},
"main": {},
"nav": {},
"output": {},
"progress": {},
"section": {},
"video": {},
}
// Renderer is the rendering interface. This is mostly of interest if you are
// implementing a new rendering format.
// Renderer is the rendering interface.
// This is mostly of interest if you are implementing a new rendering format.
//
// Only an HTML implementation is provided in this repository, see the README
// for external implementations.
// When a byte slice is provided, it contains the (rendered) contents of the
// element.
//
// When a callback is provided instead, it will write the contents of the
// respective element directly to the output buffer and return true on success.
// If the callback returns false, the rendering function should reset the
// output buffer as though it had never been called.
//
// Currently Html and Latex implementations are provided
type Renderer interface {
// RenderNode is the main rendering method. It will be called once for
// every leaf node and twice for every non-leaf node (first with
// entering=true, then with entering=false). The method should write its
// rendition of the node to the supplied writer w.
RenderNode(w io.Writer, node *Node, entering bool) WalkStatus
// block-level callbacks
BlockCode(out *bytes.Buffer, text []byte, infoString string)
BlockQuote(out *bytes.Buffer, text []byte)
BlockHtml(out *bytes.Buffer, text []byte)
Header(out *bytes.Buffer, text func() bool, level int, id string)
HRule(out *bytes.Buffer)
List(out *bytes.Buffer, text func() bool, flags int)
ListItem(out *bytes.Buffer, text []byte, flags int)
Paragraph(out *bytes.Buffer, text func() bool)
Table(out *bytes.Buffer, header []byte, body []byte, columnData []int)
TableRow(out *bytes.Buffer, text []byte)
TableHeaderCell(out *bytes.Buffer, text []byte, flags int)
TableCell(out *bytes.Buffer, text []byte, flags int)
Footnotes(out *bytes.Buffer, text func() bool)
FootnoteItem(out *bytes.Buffer, name, text []byte, flags int)
TitleBlock(out *bytes.Buffer, text []byte)
// RenderHeader is a method that allows the renderer to produce some
// content preceding the main body of the output document. The header is
// understood in the broad sense here. For example, the default HTML
// renderer will write not only the HTML document preamble, but also the
// table of contents if it was requested.
//
// The method will be passed an entire document tree, in case a particular
// implementation needs to inspect it to produce output.
//
// The output should be written to the supplied writer w. If your
// implementation has no header to write, supply an empty implementation.
RenderHeader(w io.Writer, ast *Node)
// Span-level callbacks
AutoLink(out *bytes.Buffer, link []byte, kind int)
CodeSpan(out *bytes.Buffer, text []byte)
DoubleEmphasis(out *bytes.Buffer, text []byte)
Emphasis(out *bytes.Buffer, text []byte)
Image(out *bytes.Buffer, link []byte, title []byte, alt []byte)
LineBreak(out *bytes.Buffer)
Link(out *bytes.Buffer, link []byte, title []byte, content []byte)
RawHtmlTag(out *bytes.Buffer, tag []byte)
TripleEmphasis(out *bytes.Buffer, text []byte)
StrikeThrough(out *bytes.Buffer, text []byte)
FootnoteRef(out *bytes.Buffer, ref []byte, id int)
// RenderFooter is a symmetric counterpart of RenderHeader.
RenderFooter(w io.Writer, ast *Node)
// Low-level callbacks
Entity(out *bytes.Buffer, entity []byte)
NormalText(out *bytes.Buffer, text []byte)
// Header and footer
DocumentHeader(out *bytes.Buffer)
DocumentFooter(out *bytes.Buffer)
GetFlags() int
}
// Callback functions for inline parsing. One such function is defined
// for each character that triggers a response when parsing inline data.
type inlineParser func(p *Markdown, data []byte, offset int) (int, *Node)
type inlineParser func(p *parser, out *bytes.Buffer, data []byte, offset int) int
// Markdown is a type that holds extensions and the runtime state used by
// Parse, and the renderer. You can not use it directly, construct it with New.
type Markdown struct {
renderer Renderer
referenceOverride ReferenceOverrideFunc
refs map[string]*reference
inlineCallback [256]inlineParser
extensions Extensions
nesting int
maxNesting int
insideLink bool
// Parser holds runtime state used by the parser.
// This is constructed by the Markdown function.
type parser struct {
r Renderer
refOverride ReferenceOverrideFunc
refs map[string]*reference
inlineCallback [256]inlineParser
flags int
nesting int
maxNesting int
insideLink bool
// Footnotes need to be ordered as well as available to quickly check for
// presence. If a ref is also a footnote, it's stored both in refs and here
// in notes. Slice is nil if footnotes not enabled.
notes []*reference
doc *Node
tip *Node // = doc
oldTip *Node
lastMatchedContainer *Node // = doc
allClosed bool
notes []*reference
notesRecord map[string]struct{}
}
func (p *Markdown) getRef(refid string) (ref *reference, found bool) {
if p.referenceOverride != nil {
r, overridden := p.referenceOverride(refid)
func (p *parser) getRef(refid string) (ref *reference, found bool) {
if p.refOverride != nil {
r, overridden := p.refOverride(refid)
if overridden {
if r == nil {
return nil, false
@@ -202,7 +232,7 @@ func (p *Markdown) getRef(refid string) (ref *reference, found bool) {
return &reference{
link: []byte(r.Link),
title: []byte(r.Title),
noteID: 0,
noteId: 0,
hasBlock: false,
text: []byte(r.Text)}, true
}
@@ -212,34 +242,9 @@ func (p *Markdown) getRef(refid string) (ref *reference, found bool) {
return ref, found
}
func (p *Markdown) finalize(block *Node) {
above := block.Parent
block.open = false
p.tip = above
}
func (p *Markdown) addChild(node NodeType, offset uint32) *Node {
return p.addExistingChild(NewNode(node), offset)
}
func (p *Markdown) addExistingChild(node *Node, offset uint32) *Node {
for !p.tip.canContain(node.Type) {
p.finalize(p.tip)
}
p.tip.AppendChild(node)
p.tip = node
return node
}
func (p *Markdown) closeUnmatchedBlocks() {
if !p.allClosed {
for p.oldTip != p.lastMatchedContainer {
parent := p.oldTip.Parent
p.finalize(p.oldTip)
p.oldTip = parent
}
p.allClosed = true
}
func (p *parser) isFootnote(ref *reference) bool {
_, ok := p.notesRecord[string(ref.link)]
return ok
}
//
@@ -266,27 +271,102 @@ type Reference struct {
// See the documentation in Options for more details on use-case.
type ReferenceOverrideFunc func(reference string) (ref *Reference, overridden bool)
// New constructs a Markdown processor. You can use the same With* functions as
// for Run() to customize parser's behavior and the renderer.
func New(opts ...Option) *Markdown {
var p Markdown
for _, opt := range opts {
opt(&p)
// Options represents configurable overrides and callbacks (in addition to the
// extension flag set) for configuring a Markdown parse.
type Options struct {
// Extensions is a flag set of bit-wise ORed extension bits. See the
// EXTENSION_* flags defined in this package.
Extensions int
// ReferenceOverride is an optional function callback that is called every
// time a reference is resolved.
//
// In Markdown, the link reference syntax can be made to resolve a link to
// a reference instead of an inline URL, in one of the following ways:
//
// * [link text][refid]
// * [refid][]
//
// Usually, the refid is defined at the bottom of the Markdown document. If
// this override function is provided, the refid is passed to the override
// function first, before consulting the defined refids at the bottom. If
// the override function indicates an override did not occur, the refids at
// the bottom will be used to fill in the link details.
ReferenceOverride ReferenceOverrideFunc
}
// MarkdownBasic is a convenience function for simple rendering.
// It processes markdown input with no extensions enabled.
func MarkdownBasic(input []byte) []byte {
// set up the HTML renderer
htmlFlags := HTML_USE_XHTML
renderer := HtmlRenderer(htmlFlags, "", "")
// set up the parser
return MarkdownOptions(input, renderer, Options{Extensions: 0})
}
// Call Markdown with most useful extensions enabled
// MarkdownCommon is a convenience function for simple rendering.
// It processes markdown input with common extensions enabled, including:
//
// * Smartypants processing with smart fractions and LaTeX dashes
//
// * Intra-word emphasis suppression
//
// * Tables
//
// * Fenced code blocks
//
// * Autolinking
//
// * Strikethrough support
//
// * Strict header parsing
//
// * Custom Header IDs
func MarkdownCommon(input []byte) []byte {
// set up the HTML renderer
renderer := HtmlRenderer(commonHtmlFlags, "", "")
return MarkdownOptions(input, renderer, Options{
Extensions: commonExtensions})
}
// Markdown is the main rendering function.
// It parses and renders a block of markdown-encoded text.
// The supplied Renderer is used to format the output, and extensions dictates
// which non-standard extensions are enabled.
//
// To use the supplied Html or LaTeX renderers, see HtmlRenderer and
// LatexRenderer, respectively.
func Markdown(input []byte, renderer Renderer, extensions int) []byte {
return MarkdownOptions(input, renderer, Options{
Extensions: extensions})
}
// MarkdownOptions is just like Markdown but takes additional options through
// the Options struct.
func MarkdownOptions(input []byte, renderer Renderer, opts Options) []byte {
// no point in parsing if we can't render
if renderer == nil {
return nil
}
extensions := opts.Extensions
// fill in the render structure
p := new(parser)
p.r = renderer
p.flags = extensions
p.refOverride = opts.ReferenceOverride
p.refs = make(map[string]*reference)
p.maxNesting = 16
p.insideLink = false
docNode := NewNode(Document)
p.doc = docNode
p.tip = docNode
p.oldTip = docNode
p.lastMatchedContainer = docNode
p.allClosed = true
// register inline parsers
p.inlineCallback[' '] = maybeLineBreak
p.inlineCallback['*'] = emphasis
p.inlineCallback['_'] = emphasis
if p.extensions&Strikethrough != 0 {
if extensions&EXTENSION_STRIKETHROUGH != 0 {
p.inlineCallback['~'] = emphasis
}
p.inlineCallback['`'] = codeSpan
@@ -295,166 +375,116 @@ func New(opts ...Option) *Markdown {
p.inlineCallback['<'] = leftAngle
p.inlineCallback['\\'] = escape
p.inlineCallback['&'] = entity
p.inlineCallback['!'] = maybeImage
p.inlineCallback['^'] = maybeInlineFootnote
if p.extensions&Autolink != 0 {
p.inlineCallback['h'] = maybeAutoLink
p.inlineCallback['m'] = maybeAutoLink
p.inlineCallback['f'] = maybeAutoLink
p.inlineCallback['H'] = maybeAutoLink
p.inlineCallback['M'] = maybeAutoLink
p.inlineCallback['F'] = maybeAutoLink
if extensions&EXTENSION_AUTOLINK != 0 {
p.inlineCallback[':'] = autoLink
}
if p.extensions&Footnotes != 0 {
if extensions&EXTENSION_FOOTNOTES != 0 {
p.notes = make([]*reference, 0)
p.notesRecord = make(map[string]struct{})
}
return &p
first := firstPass(p, input)
second := secondPass(p, first)
return second
}
// Option customizes the Markdown processor's default behavior.
type Option func(*Markdown)
// WithRenderer allows you to override the default renderer.
func WithRenderer(r Renderer) Option {
return func(p *Markdown) {
p.renderer = r
// first pass:
// - normalize newlines
// - extract references (outside of fenced code blocks)
// - expand tabs (outside of fenced code blocks)
// - copy everything else
func firstPass(p *parser, input []byte) []byte {
var out bytes.Buffer
tabSize := TAB_SIZE_DEFAULT
if p.flags&EXTENSION_TAB_SIZE_EIGHT != 0 {
tabSize = TAB_SIZE_EIGHT
}
beg := 0
lastFencedCodeBlockEnd := 0
for beg < len(input) {
// Find end of this line, then process the line.
end := beg
for end < len(input) && input[end] != '\n' && input[end] != '\r' {
end++
}
if p.flags&EXTENSION_FENCED_CODE != 0 {
// track fenced code block boundaries to suppress tab expansion
// and reference extraction inside them:
if beg >= lastFencedCodeBlockEnd {
if i := p.fencedCodeBlock(&out, input[beg:], false); i > 0 {
lastFencedCodeBlockEnd = beg + i
}
}
}
// add the line body if present
if end > beg {
if end < lastFencedCodeBlockEnd { // Do not expand tabs while inside fenced code blocks.
out.Write(input[beg:end])
} else if refEnd := isReference(p, input[beg:], tabSize); refEnd > 0 {
beg += refEnd
continue
} else {
expandTabs(&out, input[beg:end], tabSize)
}
}
if end < len(input) && input[end] == '\r' {
end++
}
if end < len(input) && input[end] == '\n' {
end++
}
out.WriteByte('\n')
beg = end
}
// empty input?
if out.Len() == 0 {
out.WriteByte('\n')
}
return out.Bytes()
}
// WithExtensions allows you to pick some of the many extensions provided by
// Blackfriday. You can bitwise OR them.
func WithExtensions(e Extensions) Option {
return func(p *Markdown) {
p.extensions = e
}
}
// second pass: actual rendering
func secondPass(p *parser, input []byte) []byte {
var output bytes.Buffer
// WithNoExtensions turns off all extensions and custom behavior.
func WithNoExtensions() Option {
return func(p *Markdown) {
p.extensions = NoExtensions
p.renderer = NewHTMLRenderer(HTMLRendererParameters{
Flags: HTMLFlagsNone,
p.r.DocumentHeader(&output)
p.block(&output, input)
if p.flags&EXTENSION_FOOTNOTES != 0 && len(p.notes) > 0 {
p.r.Footnotes(&output, func() bool {
flags := LIST_ITEM_BEGINNING_OF_LIST
for i := 0; i < len(p.notes); i += 1 {
ref := p.notes[i]
var buf bytes.Buffer
if ref.hasBlock {
flags |= LIST_ITEM_CONTAINS_BLOCK
p.block(&buf, ref.title)
} else {
p.inline(&buf, ref.title)
}
p.r.FootnoteItem(&output, ref.link, buf.Bytes(), flags)
flags &^= LIST_ITEM_BEGINNING_OF_LIST | LIST_ITEM_CONTAINS_BLOCK
}
return true
})
}
}
// WithRefOverride sets an optional function callback that is called every
// time a reference is resolved.
//
// In Markdown, the link reference syntax can be made to resolve a link to
// a reference instead of an inline URL, in one of the following ways:
//
// * [link text][refid]
// * [refid][]
//
// Usually, the refid is defined at the bottom of the Markdown document. If
// this override function is provided, the refid is passed to the override
// function first, before consulting the defined refids at the bottom. If
// the override function indicates an override did not occur, the refids at
// the bottom will be used to fill in the link details.
func WithRefOverride(o ReferenceOverrideFunc) Option {
return func(p *Markdown) {
p.referenceOverride = o
}
}
p.r.DocumentFooter(&output)
// Run is the main entry point to Blackfriday. It parses and renders a
// block of markdown-encoded text.
//
// The simplest invocation of Run takes one argument, input:
// output := Run(input)
// This will parse the input with CommonExtensions enabled and render it with
// the default HTMLRenderer (with CommonHTMLFlags).
//
// Variadic arguments opts can customize the default behavior. Since Markdown
// type does not contain exported fields, you can not use it directly. Instead,
// use the With* functions. For example, this will call the most basic
// functionality, with no extensions:
// output := Run(input, WithNoExtensions())
//
// You can use any number of With* arguments, even contradicting ones. They
// will be applied in order of appearance and the latter will override the
// former:
// output := Run(input, WithNoExtensions(), WithExtensions(exts),
// WithRenderer(yourRenderer))
func Run(input []byte, opts ...Option) []byte {
r := NewHTMLRenderer(HTMLRendererParameters{
Flags: CommonHTMLFlags,
})
optList := []Option{WithRenderer(r), WithExtensions(CommonExtensions)}
optList = append(optList, opts...)
parser := New(optList...)
ast := parser.Parse(input)
var buf bytes.Buffer
parser.renderer.RenderHeader(&buf, ast)
ast.Walk(func(node *Node, entering bool) WalkStatus {
return parser.renderer.RenderNode(&buf, node, entering)
})
parser.renderer.RenderFooter(&buf, ast)
return buf.Bytes()
}
if p.nesting != 0 {
panic("Nesting level did not end at zero")
}
// Parse is an entry point to the parsing part of Blackfriday. It takes an
// input markdown document and produces a syntax tree for its contents. This
// tree can then be rendered with a default or custom renderer, or
// analyzed/transformed by the caller to whatever non-standard needs they have.
// The return value is the root node of the syntax tree.
func (p *Markdown) Parse(input []byte) *Node {
p.block(input)
// Walk the tree and finish up some of unfinished blocks
for p.tip != nil {
p.finalize(p.tip)
}
// Walk the tree again and process inline markdown in each block
p.doc.Walk(func(node *Node, entering bool) WalkStatus {
if node.Type == Paragraph || node.Type == Heading || node.Type == TableCell {
p.inline(node, node.content)
node.content = nil
}
return GoToNext
})
p.parseRefsToAST()
return p.doc
}
func (p *Markdown) parseRefsToAST() {
if p.extensions&Footnotes == 0 || len(p.notes) == 0 {
return
}
p.tip = p.doc
block := p.addBlock(List, nil)
block.IsFootnotesList = true
block.ListFlags = ListTypeOrdered
flags := ListItemBeginningOfList
// Note: this loop is intentionally explicit, not range-form. This is
// because the body of the loop will append nested footnotes to p.notes and
// we need to process those late additions. Range form would only walk over
// the fixed initial set.
for i := 0; i < len(p.notes); i++ {
ref := p.notes[i]
p.addExistingChild(ref.footnote, 0)
block := ref.footnote
block.ListFlags = flags | ListTypeOrdered
block.RefLink = ref.link
if ref.hasBlock {
flags |= ListItemContainsBlock
p.block(ref.title)
} else {
p.inline(block, ref.title)
}
flags &^= ListItemBeginningOfList | ListItemContainsBlock
}
above := block.Parent
finalizeList(block)
p.tip = above
block.Walk(func(node *Node, entering bool) WalkStatus {
if node.Type == Paragraph || node.Type == Heading {
p.inline(node, node.content)
node.content = nil
}
return GoToNext
})
return output.Bytes()
}
//
@@ -486,56 +516,18 @@ func (p *Markdown) parseRefsToAST() {
//
// are not yet supported.
// reference holds all information necessary for a reference-style links or
// footnotes.
//
// Consider this markdown with reference-style links:
//
// [link][ref]
//
// [ref]: /url/ "tooltip title"
//
// It will be ultimately converted to this HTML:
//
// <p><a href=\"/url/\" title=\"title\">link</a></p>
//
// And a reference structure will be populated as follows:
//
// p.refs["ref"] = &reference{
// link: "/url/",
// title: "tooltip title",
// }
//
// Alternatively, reference can contain information about a footnote. Consider
// this markdown:
//
// Text needing a footnote.[^a]
//
// [^a]: This is the note
//
// A reference structure will be populated as follows:
//
// p.refs["a"] = &reference{
// link: "a",
// title: "This is the note",
// noteID: <some positive int>,
// }
//
// TODO: As you can see, it begs for splitting into two dedicated structures
// for refs and for footnotes.
// References are parsed and stored in this struct.
type reference struct {
link []byte
title []byte
noteID int // 0 if not a footnote ref
noteId int // 0 if not a footnote ref
hasBlock bool
footnote *Node // a link to the Item node within a list of footnotes
text []byte // only gets populated by refOverride feature with Reference.Text
text []byte
}
func (r *reference) String() string {
return fmt.Sprintf("{link: %q, title: %q, text: %q, noteID: %d, hasBlock: %v}",
r.link, r.title, r.text, r.noteID, r.hasBlock)
return fmt.Sprintf("{link: %q, title: %q, text: %q, noteId: %d, hasBlock: %v}",
r.link, r.title, r.text, r.noteId, r.hasBlock)
}
// Check whether or not data starts with a reference link.
@@ -543,7 +535,7 @@ func (r *reference) String() string {
// (in the render struct).
// Returns the number of bytes to skip to move past it,
// or zero if the first line is not a reference.
func isReference(p *Markdown, data []byte, tabSize int) int {
func isReference(p *parser, data []byte, tabSize int) int {
// up to 3 optional leading spaces
if len(data) < 4 {
return 0
@@ -553,18 +545,18 @@ func isReference(p *Markdown, data []byte, tabSize int) int {
i++
}
noteID := 0
noteId := 0
// id part: anything but a newline between brackets
if data[i] != '[' {
return 0
}
i++
if p.extensions&Footnotes != 0 {
if p.flags&EXTENSION_FOOTNOTES != 0 {
if i < len(data) && data[i] == '^' {
// we can set it to anything here because the proper noteIds will
// be assigned later during the second pass. It just has to be != 0
noteID = 1
noteId = 1
i++
}
}
@@ -576,11 +568,7 @@ func isReference(p *Markdown, data []byte, tabSize int) int {
return 0
}
idEnd := i
// footnotes can have empty ID, like this: [^], but a reference can not be
// empty like this: []. Break early if it's not a footnote and there's no ID
if noteID == 0 && idOffset == idEnd {
return 0
}
// spacer: colon (space | tab)* newline? (space | tab)*
i++
if i >= len(data) || data[i] != ':' {
@@ -611,7 +599,7 @@ func isReference(p *Markdown, data []byte, tabSize int) int {
hasBlock bool
)
if p.extensions&Footnotes != 0 && noteID != 0 {
if p.flags&EXTENSION_FOOTNOTES != 0 && noteId != 0 {
linkOffset, linkEnd, raw, hasBlock = scanFootnote(p, data, i, tabSize)
lineEnd = linkEnd
} else {
@@ -624,11 +612,11 @@ func isReference(p *Markdown, data []byte, tabSize int) int {
// a valid ref has been found
ref := &reference{
noteID: noteID,
noteId: noteId,
hasBlock: hasBlock,
}
if noteID > 0 {
if noteId > 0 {
// reusing the link field for the id since footnotes don't have links
ref.link = data[idOffset:idEnd]
// if footnote, it's not really a title, it's the contained text
@@ -646,12 +634,15 @@ func isReference(p *Markdown, data []byte, tabSize int) int {
return lineEnd
}
func scanLinkRef(p *Markdown, data []byte, i int) (linkOffset, linkEnd, titleOffset, titleEnd, lineEnd int) {
func scanLinkRef(p *parser, data []byte, i int) (linkOffset, linkEnd, titleOffset, titleEnd, lineEnd int) {
// link: whitespace-free sequence, optionally between angle brackets
if data[i] == '<' {
i++
}
linkOffset = i
if i == len(data) {
return
}
for i < len(data) && data[i] != ' ' && data[i] != '\t' && data[i] != '\n' && data[i] != '\r' {
i++
}
@@ -714,13 +705,13 @@ func scanLinkRef(p *Markdown, data []byte, i int) (linkOffset, linkEnd, titleOff
return
}
// The first bit of this logic is the same as Parser.listItem, but the rest
// The first bit of this logic is the same as (*parser).listItem, but the rest
// is much simpler. This function simply finds the entire block and shifts it
// over by one tab if it is indeed a block (just returns the line if it's not).
// blockEnd is the end of the section in the input buffer, and contents is the
// extracted text that was shifted over one tab. It will need to be rendered at
// the end of the document.
func scanFootnote(p *Markdown, data []byte, i, indentSize int) (blockStart, blockEnd int, contents []byte, hasBlock bool) {
func scanFootnote(p *parser, data []byte, i, indentSize int) (blockStart, blockEnd int, contents []byte, hasBlock bool) {
if i == 0 || len(data) == 0 {
return
}
@@ -813,7 +804,17 @@ func ispunct(c byte) bool {
// Test if a character is a whitespace character.
func isspace(c byte) bool {
return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v'
return ishorizontalspace(c) || isverticalspace(c)
}
// Test if a character is a horizontal whitespace character.
func ishorizontalspace(c byte) bool {
return c == ' ' || c == '\t'
}
// Test if a character is a vertical whitespace character.
func isverticalspace(c byte) bool {
return c == '\n' || c == '\r' || c == '\f' || c == '\v'
}
// Test if a character is letter.

View File

@@ -1,354 +0,0 @@
package blackfriday
import (
"bytes"
"fmt"
)
// NodeType specifies a type of a single node of a syntax tree. Usually one
// node (and its type) corresponds to a single markdown feature, e.g. emphasis
// or code block.
type NodeType int
// Constants for identifying different types of nodes. See NodeType.
const (
Document NodeType = iota
BlockQuote
List
Item
Paragraph
Heading
HorizontalRule
Emph
Strong
Del
Link
Image
Text
HTMLBlock
CodeBlock
Softbreak
Hardbreak
Code
HTMLSpan
Table
TableCell
TableHead
TableBody
TableRow
)
var nodeTypeNames = []string{
Document: "Document",
BlockQuote: "BlockQuote",
List: "List",
Item: "Item",
Paragraph: "Paragraph",
Heading: "Heading",
HorizontalRule: "HorizontalRule",
Emph: "Emph",
Strong: "Strong",
Del: "Del",
Link: "Link",
Image: "Image",
Text: "Text",
HTMLBlock: "HTMLBlock",
CodeBlock: "CodeBlock",
Softbreak: "Softbreak",
Hardbreak: "Hardbreak",
Code: "Code",
HTMLSpan: "HTMLSpan",
Table: "Table",
TableCell: "TableCell",
TableHead: "TableHead",
TableBody: "TableBody",
TableRow: "TableRow",
}
func (t NodeType) String() string {
return nodeTypeNames[t]
}
// ListData contains fields relevant to a List and Item node type.
type ListData struct {
ListFlags ListType
Tight bool // Skip <p>s around list item data if true
BulletChar byte // '*', '+' or '-' in bullet lists
Delimiter byte // '.' or ')' after the number in ordered lists
RefLink []byte // If not nil, turns this list item into a footnote item and triggers different rendering
IsFootnotesList bool // This is a list of footnotes
}
// LinkData contains fields relevant to a Link node type.
type LinkData struct {
Destination []byte // Destination is what goes into a href
Title []byte // Title is the tooltip thing that goes in a title attribute
NoteID int // NoteID contains a serial number of a footnote, zero if it's not a footnote
Footnote *Node // If it's a footnote, this is a direct link to the footnote Node. Otherwise nil.
}
// CodeBlockData contains fields relevant to a CodeBlock node type.
type CodeBlockData struct {
IsFenced bool // Specifies whether it's a fenced code block or an indented one
Info []byte // This holds the info string
FenceChar byte
FenceLength int
FenceOffset int
}
// TableCellData contains fields relevant to a TableCell node type.
type TableCellData struct {
IsHeader bool // This tells if it's under the header row
Align CellAlignFlags // This holds the value for align attribute
}
// HeadingData contains fields relevant to a Heading node type.
type HeadingData struct {
Level int // This holds the heading level number
HeadingID string // This might hold heading ID, if present
IsTitleblock bool // Specifies whether it's a title block
}
// Node is a single element in the abstract syntax tree of the parsed document.
// It holds connections to the structurally neighboring nodes and, for certain
// types of nodes, additional information that might be needed when rendering.
type Node struct {
Type NodeType // Determines the type of the node
Parent *Node // Points to the parent
FirstChild *Node // Points to the first child, if any
LastChild *Node // Points to the last child, if any
Prev *Node // Previous sibling; nil if it's the first child
Next *Node // Next sibling; nil if it's the last child
Literal []byte // Text contents of the leaf nodes
HeadingData // Populated if Type is Heading
ListData // Populated if Type is List
CodeBlockData // Populated if Type is CodeBlock
LinkData // Populated if Type is Link
TableCellData // Populated if Type is TableCell
content []byte // Markdown content of the block nodes
open bool // Specifies an open block node that has not been finished to process yet
}
// NewNode allocates a node of a specified type.
func NewNode(typ NodeType) *Node {
return &Node{
Type: typ,
open: true,
}
}
func (n *Node) String() string {
ellipsis := ""
snippet := n.Literal
if len(snippet) > 16 {
snippet = snippet[:16]
ellipsis = "..."
}
return fmt.Sprintf("%s: '%s%s'", n.Type, snippet, ellipsis)
}
// Unlink removes node 'n' from the tree.
// It panics if the node is nil.
func (n *Node) Unlink() {
if n.Prev != nil {
n.Prev.Next = n.Next
} else if n.Parent != nil {
n.Parent.FirstChild = n.Next
}
if n.Next != nil {
n.Next.Prev = n.Prev
} else if n.Parent != nil {
n.Parent.LastChild = n.Prev
}
n.Parent = nil
n.Next = nil
n.Prev = nil
}
// AppendChild adds a node 'child' as a child of 'n'.
// It panics if either node is nil.
func (n *Node) AppendChild(child *Node) {
child.Unlink()
child.Parent = n
if n.LastChild != nil {
n.LastChild.Next = child
child.Prev = n.LastChild
n.LastChild = child
} else {
n.FirstChild = child
n.LastChild = child
}
}
// InsertBefore inserts 'sibling' immediately before 'n'.
// It panics if either node is nil.
func (n *Node) InsertBefore(sibling *Node) {
sibling.Unlink()
sibling.Prev = n.Prev
if sibling.Prev != nil {
sibling.Prev.Next = sibling
}
sibling.Next = n
n.Prev = sibling
sibling.Parent = n.Parent
if sibling.Prev == nil {
sibling.Parent.FirstChild = sibling
}
}
func (n *Node) isContainer() bool {
switch n.Type {
case Document:
fallthrough
case BlockQuote:
fallthrough
case List:
fallthrough
case Item:
fallthrough
case Paragraph:
fallthrough
case Heading:
fallthrough
case Emph:
fallthrough
case Strong:
fallthrough
case Del:
fallthrough
case Link:
fallthrough
case Image:
fallthrough
case Table:
fallthrough
case TableHead:
fallthrough
case TableBody:
fallthrough
case TableRow:
fallthrough
case TableCell:
return true
default:
return false
}
}
func (n *Node) canContain(t NodeType) bool {
if n.Type == List {
return t == Item
}
if n.Type == Document || n.Type == BlockQuote || n.Type == Item {
return t != Item
}
if n.Type == Table {
return t == TableHead || t == TableBody
}
if n.Type == TableHead || n.Type == TableBody {
return t == TableRow
}
if n.Type == TableRow {
return t == TableCell
}
return false
}
// WalkStatus allows NodeVisitor to have some control over the tree traversal.
// It is returned from NodeVisitor and different values allow Node.Walk to
// decide which node to go to next.
type WalkStatus int
const (
// GoToNext is the default traversal of every node.
GoToNext WalkStatus = iota
// SkipChildren tells walker to skip all children of current node.
SkipChildren
// Terminate tells walker to terminate the traversal.
Terminate
)
// NodeVisitor is a callback to be called when traversing the syntax tree.
// Called twice for every node: once with entering=true when the branch is
// first visited, then with entering=false after all the children are done.
type NodeVisitor func(node *Node, entering bool) WalkStatus
// Walk is a convenience method that instantiates a walker and starts a
// traversal of subtree rooted at n.
func (n *Node) Walk(visitor NodeVisitor) {
w := newNodeWalker(n)
for w.current != nil {
status := visitor(w.current, w.entering)
switch status {
case GoToNext:
w.next()
case SkipChildren:
w.entering = false
w.next()
case Terminate:
return
}
}
}
type nodeWalker struct {
current *Node
root *Node
entering bool
}
func newNodeWalker(root *Node) *nodeWalker {
return &nodeWalker{
current: root,
root: root,
entering: true,
}
}
func (nw *nodeWalker) next() {
if (!nw.current.isContainer() || !nw.entering) && nw.current == nw.root {
nw.current = nil
return
}
if nw.entering && nw.current.isContainer() {
if nw.current.FirstChild != nil {
nw.current = nw.current.FirstChild
nw.entering = true
} else {
nw.entering = false
}
} else if nw.current.Next == nil {
nw.current = nw.current.Parent
nw.entering = false
} else {
nw.current = nw.current.Next
nw.entering = true
}
}
func dump(ast *Node) {
fmt.Println(dumpString(ast))
}
func dumpR(ast *Node, depth int) string {
if ast == nil {
return ""
}
indent := bytes.Repeat([]byte("\t"), depth)
content := ast.Literal
if content == nil {
content = ast.content
}
result := fmt.Sprintf("%s%s(%q)\n", indent, ast.Type, content)
for n := ast.FirstChild; n != nil; n = n.Next {
result += dumpR(n, depth+1)
}
return result
}
func dumpString(ast *Node) string {
return dumpR(ast, 0)
}

View File

@@ -17,14 +17,11 @@ package blackfriday
import (
"bytes"
"io"
)
// SPRenderer is a struct containing state of a Smartypants renderer.
type SPRenderer struct {
type smartypantsData struct {
inSingleQuote bool
inDoubleQuote bool
callbacks [256]smartCallback
}
func wordBoundary(c byte) bool {
@@ -121,7 +118,7 @@ func smartQuoteHelper(out *bytes.Buffer, previousChar byte, nextChar byte, quote
return true
}
func (r *SPRenderer) smartSingleQuote(out *bytes.Buffer, previousChar byte, text []byte) int {
func smartSingleQuote(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
if len(text) >= 2 {
t1 := tolower(text[1])
@@ -130,7 +127,7 @@ func (r *SPRenderer) smartSingleQuote(out *bytes.Buffer, previousChar byte, text
if len(text) >= 3 {
nextChar = text[2]
}
if smartQuoteHelper(out, previousChar, nextChar, 'd', &r.inDoubleQuote, false) {
if smartQuoteHelper(out, previousChar, nextChar, 'd', &smrt.inDoubleQuote, false) {
return 1
}
}
@@ -155,7 +152,7 @@ func (r *SPRenderer) smartSingleQuote(out *bytes.Buffer, previousChar byte, text
if len(text) > 1 {
nextChar = text[1]
}
if smartQuoteHelper(out, previousChar, nextChar, 's', &r.inSingleQuote, false) {
if smartQuoteHelper(out, previousChar, nextChar, 's', &smrt.inSingleQuote, false) {
return 0
}
@@ -163,7 +160,7 @@ func (r *SPRenderer) smartSingleQuote(out *bytes.Buffer, previousChar byte, text
return 0
}
func (r *SPRenderer) smartParens(out *bytes.Buffer, previousChar byte, text []byte) int {
func smartParens(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
if len(text) >= 3 {
t1 := tolower(text[1])
t2 := tolower(text[2])
@@ -188,7 +185,7 @@ func (r *SPRenderer) smartParens(out *bytes.Buffer, previousChar byte, text []by
return 0
}
func (r *SPRenderer) smartDash(out *bytes.Buffer, previousChar byte, text []byte) int {
func smartDash(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
if len(text) >= 2 {
if text[1] == '-' {
out.WriteString("&mdash;")
@@ -205,7 +202,7 @@ func (r *SPRenderer) smartDash(out *bytes.Buffer, previousChar byte, text []byte
return 0
}
func (r *SPRenderer) smartDashLatex(out *bytes.Buffer, previousChar byte, text []byte) int {
func smartDashLatex(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
if len(text) >= 3 && text[1] == '-' && text[2] == '-' {
out.WriteString("&mdash;")
return 2
@@ -219,13 +216,13 @@ func (r *SPRenderer) smartDashLatex(out *bytes.Buffer, previousChar byte, text [
return 0
}
func (r *SPRenderer) smartAmpVariant(out *bytes.Buffer, previousChar byte, text []byte, quote byte, addNBSP bool) int {
func smartAmpVariant(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte, quote byte, addNBSP bool) int {
if bytes.HasPrefix(text, []byte("&quot;")) {
nextChar := byte(0)
if len(text) >= 7 {
nextChar = text[6]
}
if smartQuoteHelper(out, previousChar, nextChar, quote, &r.inDoubleQuote, addNBSP) {
if smartQuoteHelper(out, previousChar, nextChar, quote, &smrt.inDoubleQuote, addNBSP) {
return 5
}
}
@@ -238,18 +235,18 @@ func (r *SPRenderer) smartAmpVariant(out *bytes.Buffer, previousChar byte, text
return 0
}
func (r *SPRenderer) smartAmp(angledQuotes, addNBSP bool) func(*bytes.Buffer, byte, []byte) int {
func smartAmp(angledQuotes, addNBSP bool) func(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
var quote byte = 'd'
if angledQuotes {
quote = 'a'
}
return func(out *bytes.Buffer, previousChar byte, text []byte) int {
return r.smartAmpVariant(out, previousChar, text, quote, addNBSP)
return func(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
return smartAmpVariant(out, smrt, previousChar, text, quote, addNBSP)
}
}
func (r *SPRenderer) smartPeriod(out *bytes.Buffer, previousChar byte, text []byte) int {
func smartPeriod(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
if len(text) >= 3 && text[1] == '.' && text[2] == '.' {
out.WriteString("&hellip;")
return 2
@@ -264,13 +261,13 @@ func (r *SPRenderer) smartPeriod(out *bytes.Buffer, previousChar byte, text []by
return 0
}
func (r *SPRenderer) smartBacktick(out *bytes.Buffer, previousChar byte, text []byte) int {
func smartBacktick(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
if len(text) >= 2 && text[1] == '`' {
nextChar := byte(0)
if len(text) >= 3 {
nextChar = text[2]
}
if smartQuoteHelper(out, previousChar, nextChar, 'd', &r.inDoubleQuote, false) {
if smartQuoteHelper(out, previousChar, nextChar, 'd', &smrt.inDoubleQuote, false) {
return 1
}
}
@@ -279,7 +276,7 @@ func (r *SPRenderer) smartBacktick(out *bytes.Buffer, previousChar byte, text []
return 0
}
func (r *SPRenderer) smartNumberGeneric(out *bytes.Buffer, previousChar byte, text []byte) int {
func smartNumberGeneric(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
if wordBoundary(previousChar) && previousChar != '/' && len(text) >= 3 {
// is it of the form digits/digits(word boundary)?, i.e., \d+/\d+\b
// note: check for regular slash (/) or fraction slash (, 0x2044, or 0xe2 81 84 in utf-8)
@@ -321,7 +318,7 @@ func (r *SPRenderer) smartNumberGeneric(out *bytes.Buffer, previousChar byte, te
return 0
}
func (r *SPRenderer) smartNumber(out *bytes.Buffer, previousChar byte, text []byte) int {
func smartNumber(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
if wordBoundary(previousChar) && previousChar != '/' && len(text) >= 3 {
if text[0] == '1' && text[1] == '/' && text[2] == '2' {
if len(text) < 4 || wordBoundary(text[3]) && text[3] != '/' {
@@ -349,27 +346,27 @@ func (r *SPRenderer) smartNumber(out *bytes.Buffer, previousChar byte, text []by
return 0
}
func (r *SPRenderer) smartDoubleQuoteVariant(out *bytes.Buffer, previousChar byte, text []byte, quote byte) int {
func smartDoubleQuoteVariant(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte, quote byte) int {
nextChar := byte(0)
if len(text) > 1 {
nextChar = text[1]
}
if !smartQuoteHelper(out, previousChar, nextChar, quote, &r.inDoubleQuote, false) {
if !smartQuoteHelper(out, previousChar, nextChar, quote, &smrt.inDoubleQuote, false) {
out.WriteString("&quot;")
}
return 0
}
func (r *SPRenderer) smartDoubleQuote(out *bytes.Buffer, previousChar byte, text []byte) int {
return r.smartDoubleQuoteVariant(out, previousChar, text, 'd')
func smartDoubleQuote(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
return smartDoubleQuoteVariant(out, smrt, previousChar, text, 'd')
}
func (r *SPRenderer) smartAngledDoubleQuote(out *bytes.Buffer, previousChar byte, text []byte) int {
return r.smartDoubleQuoteVariant(out, previousChar, text, 'a')
func smartAngledDoubleQuote(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
return smartDoubleQuoteVariant(out, smrt, previousChar, text, 'a')
}
func (r *SPRenderer) smartLeftAngle(out *bytes.Buffer, previousChar byte, text []byte) int {
func smartLeftAngle(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
i := 0
for i < len(text) && text[i] != '>' {
@@ -380,78 +377,54 @@ func (r *SPRenderer) smartLeftAngle(out *bytes.Buffer, previousChar byte, text [
return i
}
type smartCallback func(out *bytes.Buffer, previousChar byte, text []byte) int
type smartCallback func(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int
// NewSmartypantsRenderer constructs a Smartypants renderer object.
func NewSmartypantsRenderer(flags HTMLFlags) *SPRenderer {
var (
r SPRenderer
type smartypantsRenderer [256]smartCallback
smartAmpAngled = r.smartAmp(true, false)
smartAmpAngledNBSP = r.smartAmp(true, true)
smartAmpRegular = r.smartAmp(false, false)
smartAmpRegularNBSP = r.smartAmp(false, true)
var (
smartAmpAngled = smartAmp(true, false)
smartAmpAngledNBSP = smartAmp(true, true)
smartAmpRegular = smartAmp(false, false)
smartAmpRegularNBSP = smartAmp(false, true)
)
addNBSP = flags&SmartypantsQuotesNBSP != 0
)
if flags&SmartypantsAngledQuotes == 0 {
r.callbacks['"'] = r.smartDoubleQuote
func smartypants(flags int) *smartypantsRenderer {
r := new(smartypantsRenderer)
addNBSP := flags&HTML_SMARTYPANTS_QUOTES_NBSP != 0
if flags&HTML_SMARTYPANTS_ANGLED_QUOTES == 0 {
r['"'] = smartDoubleQuote
if !addNBSP {
r.callbacks['&'] = smartAmpRegular
r['&'] = smartAmpRegular
} else {
r.callbacks['&'] = smartAmpRegularNBSP
r['&'] = smartAmpRegularNBSP
}
} else {
r.callbacks['"'] = r.smartAngledDoubleQuote
r['"'] = smartAngledDoubleQuote
if !addNBSP {
r.callbacks['&'] = smartAmpAngled
r['&'] = smartAmpAngled
} else {
r.callbacks['&'] = smartAmpAngledNBSP
r['&'] = smartAmpAngledNBSP
}
}
r.callbacks['\''] = r.smartSingleQuote
r.callbacks['('] = r.smartParens
if flags&SmartypantsDashes != 0 {
if flags&SmartypantsLatexDashes == 0 {
r.callbacks['-'] = r.smartDash
r['\''] = smartSingleQuote
r['('] = smartParens
if flags&HTML_SMARTYPANTS_DASHES != 0 {
if flags&HTML_SMARTYPANTS_LATEX_DASHES == 0 {
r['-'] = smartDash
} else {
r.callbacks['-'] = r.smartDashLatex
r['-'] = smartDashLatex
}
}
r.callbacks['.'] = r.smartPeriod
if flags&SmartypantsFractions == 0 {
r.callbacks['1'] = r.smartNumber
r.callbacks['3'] = r.smartNumber
r['.'] = smartPeriod
if flags&HTML_SMARTYPANTS_FRACTIONS == 0 {
r['1'] = smartNumber
r['3'] = smartNumber
} else {
for ch := '1'; ch <= '9'; ch++ {
r.callbacks[ch] = r.smartNumberGeneric
r[ch] = smartNumberGeneric
}
}
r.callbacks['<'] = r.smartLeftAngle
r.callbacks['`'] = r.smartBacktick
return &r
}
// Process is the entry point of the Smartypants renderer.
func (r *SPRenderer) Process(w io.Writer, text []byte) {
mark := 0
for i := 0; i < len(text); i++ {
if action := r.callbacks[text[i]]; action != nil {
if i > mark {
w.Write(text[mark:i])
}
previousChar := byte(0)
if i > 0 {
previousChar = text[i-1]
}
var tmp bytes.Buffer
i += action(&tmp, previousChar, text[i:])
w.Write(tmp.Bytes())
mark = i + 1
}
}
if mark < len(text) {
w.Write(text[mark:])
}
r['<'] = smartLeftAngle
r['`'] = smartBacktick
return r
}

View File

@@ -1,16 +0,0 @@
sudo: false
language: go
go:
- 1.x
- master
matrix:
allow_failures:
- go: master
fast_finish: true
install:
- # Do nothing. This is needed to prevent default install action "go get -t -v ./..." from happening here (we want it to happen inside script step).
script:
- go get -t -v ./...
- diff -u <(echo -n) <(gofmt -d -s .)
- go tool vet .
- go test -v -race ./...

View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2015 Dmitri Shuralyov
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.

View File

@@ -1,36 +0,0 @@
sanitized_anchor_name
=====================
[![Build Status](https://travis-ci.org/shurcooL/sanitized_anchor_name.svg?branch=master)](https://travis-ci.org/shurcooL/sanitized_anchor_name) [![GoDoc](https://godoc.org/github.com/shurcooL/sanitized_anchor_name?status.svg)](https://godoc.org/github.com/shurcooL/sanitized_anchor_name)
Package sanitized_anchor_name provides a func to create sanitized anchor names.
Its logic can be reused by multiple packages to create interoperable anchor names
and links to those anchors.
At this time, it does not try to ensure that generated anchor names
are unique, that responsibility falls on the caller.
Installation
------------
```bash
go get -u github.com/shurcooL/sanitized_anchor_name
```
Example
-------
```Go
anchorName := sanitized_anchor_name.Create("This is a header")
fmt.Println(anchorName)
// Output:
// this-is-a-header
```
License
-------
- [MIT License](LICENSE)

View File

@@ -1 +0,0 @@
module github.com/shurcooL/sanitized_anchor_name

View File

@@ -1,29 +0,0 @@
// Package sanitized_anchor_name provides a func to create sanitized anchor names.
//
// Its logic can be reused by multiple packages to create interoperable anchor names
// and links to those anchors.
//
// At this time, it does not try to ensure that generated anchor names
// are unique, that responsibility falls on the caller.
package sanitized_anchor_name // import "github.com/shurcooL/sanitized_anchor_name"
import "unicode"
// Create returns a sanitized anchor name for the given text.
func Create(text string) string {
var anchorName []rune
var futureDash = false
for _, r := range text {
switch {
case unicode.IsLetter(r) || unicode.IsNumber(r):
if futureDash && len(anchorName) > 0 {
anchorName = append(anchorName, '-')
}
futureDash = false
anchorName = append(anchorName, unicode.ToLower(r))
default:
futureDash = true
}
}
return string(anchorName)
}

View File

@@ -128,11 +128,7 @@ func (c *Client) Discover(ctx context.Context) (Directory, error) {
return *c.dir, nil
}
dirURL := c.DirectoryURL
if dirURL == "" {
dirURL = LetsEncryptURL
}
res, err := c.get(ctx, dirURL, wantStatus(http.StatusOK))
res, err := c.get(ctx, c.directoryURL(), wantStatus(http.StatusOK))
if err != nil {
return Directory{}, err
}
@@ -165,6 +161,13 @@ func (c *Client) Discover(ctx context.Context) (Directory, error) {
return *c.dir, nil
}
func (c *Client) directoryURL() string {
if c.DirectoryURL != "" {
return c.DirectoryURL
}
return LetsEncryptURL
}
// CreateCert requests a new certificate using the Certificate Signing Request csr encoded in DER format.
// The exp argument indicates the desired certificate validity duration. CA may issue a certificate
// with a different duration.
@@ -711,12 +714,18 @@ func (c *Client) doReg(ctx context.Context, url string, typ string, acct *Accoun
}
// popNonce returns a nonce value previously stored with c.addNonce
// or fetches a fresh one from the given URL.
// or fetches a fresh one from a URL by issuing a HEAD request.
// It first tries c.directoryURL() and then the provided url if the former fails.
func (c *Client) popNonce(ctx context.Context, url string) (string, error) {
c.noncesMu.Lock()
defer c.noncesMu.Unlock()
if len(c.nonces) == 0 {
return c.fetchNonce(ctx, url)
dirURL := c.directoryURL()
v, err := c.fetchNonce(ctx, dirURL)
if err != nil && url != dirURL {
v, err = c.fetchNonce(ctx, url)
}
return v, err
}
var nonce string
for nonce = range c.nonces {

View File

@@ -3,6 +3,14 @@
// license that can be found in the LICENSE file.
// Package blowfish implements Bruce Schneier's Blowfish encryption algorithm.
//
// Blowfish is a legacy cipher and its short block size makes it vulnerable to
// birthday bound attacks (see https://sweet32.info). It should only be used
// where compatibility with legacy systems, not security, is the goal.
//
// Deprecated: any new system should use AES (from crypto/aes, if necessary in
// an AEAD mode like crypto/cipher.NewGCM) or XChaCha20-Poly1305 (from
// golang.org/x/crypto/chacha20poly1305).
package blowfish // import "golang.org/x/crypto/blowfish"
// The code is a port of Bruce Schneier's C implementation.

View File

@@ -86,7 +86,7 @@ func feFromBytes(dst *fieldElement, src *[32]byte) {
h6 := load3(src[20:]) << 7
h7 := load3(src[23:]) << 5
h8 := load3(src[26:]) << 4
h9 := load3(src[29:]) << 2
h9 := (load3(src[29:]) & 0x7fffff) << 2
var carry [10]int64
carry[9] = (h9 + 1<<24) >> 25

View File

@@ -0,0 +1,308 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.11
// +build !gccgo,!appengine
#include "textflag.h"
#define NUM_ROUNDS 10
// func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32)
TEXT ·xorKeyStreamVX(SB), NOSPLIT, $0
MOVD dst+0(FP), R1
MOVD src+24(FP), R2
MOVD src_len+32(FP), R3
MOVD key+48(FP), R4
MOVD nonce+56(FP), R6
MOVD counter+64(FP), R7
MOVD $·constants(SB), R10
MOVD $·incRotMatrix(SB), R11
MOVW (R7), R20
AND $~255, R3, R13
ADD R2, R13, R12 // R12 for block end
AND $255, R3, R13
loop:
MOVD $NUM_ROUNDS, R21
VLD1 (R11), [V30.S4, V31.S4]
// load contants
// VLD4R (R10), [V0.S4, V1.S4, V2.S4, V3.S4]
WORD $0x4D60E940
// load keys
// VLD4R 16(R4), [V4.S4, V5.S4, V6.S4, V7.S4]
WORD $0x4DFFE884
// VLD4R 16(R4), [V8.S4, V9.S4, V10.S4, V11.S4]
WORD $0x4DFFE888
SUB $32, R4
// load counter + nonce
// VLD1R (R7), [V12.S4]
WORD $0x4D40C8EC
// VLD3R (R6), [V13.S4, V14.S4, V15.S4]
WORD $0x4D40E8CD
// update counter
VADD V30.S4, V12.S4, V12.S4
chacha:
// V0..V3 += V4..V7
// V12..V15 <<<= ((V12..V15 XOR V0..V3), 16)
VADD V0.S4, V4.S4, V0.S4
VADD V1.S4, V5.S4, V1.S4
VADD V2.S4, V6.S4, V2.S4
VADD V3.S4, V7.S4, V3.S4
VEOR V12.B16, V0.B16, V12.B16
VEOR V13.B16, V1.B16, V13.B16
VEOR V14.B16, V2.B16, V14.B16
VEOR V15.B16, V3.B16, V15.B16
VREV32 V12.H8, V12.H8
VREV32 V13.H8, V13.H8
VREV32 V14.H8, V14.H8
VREV32 V15.H8, V15.H8
// V8..V11 += V12..V15
// V4..V7 <<<= ((V4..V7 XOR V8..V11), 12)
VADD V8.S4, V12.S4, V8.S4
VADD V9.S4, V13.S4, V9.S4
VADD V10.S4, V14.S4, V10.S4
VADD V11.S4, V15.S4, V11.S4
VEOR V8.B16, V4.B16, V16.B16
VEOR V9.B16, V5.B16, V17.B16
VEOR V10.B16, V6.B16, V18.B16
VEOR V11.B16, V7.B16, V19.B16
VSHL $12, V16.S4, V4.S4
VSHL $12, V17.S4, V5.S4
VSHL $12, V18.S4, V6.S4
VSHL $12, V19.S4, V7.S4
VSRI $20, V16.S4, V4.S4
VSRI $20, V17.S4, V5.S4
VSRI $20, V18.S4, V6.S4
VSRI $20, V19.S4, V7.S4
// V0..V3 += V4..V7
// V12..V15 <<<= ((V12..V15 XOR V0..V3), 8)
VADD V0.S4, V4.S4, V0.S4
VADD V1.S4, V5.S4, V1.S4
VADD V2.S4, V6.S4, V2.S4
VADD V3.S4, V7.S4, V3.S4
VEOR V12.B16, V0.B16, V12.B16
VEOR V13.B16, V1.B16, V13.B16
VEOR V14.B16, V2.B16, V14.B16
VEOR V15.B16, V3.B16, V15.B16
VTBL V31.B16, [V12.B16], V12.B16
VTBL V31.B16, [V13.B16], V13.B16
VTBL V31.B16, [V14.B16], V14.B16
VTBL V31.B16, [V15.B16], V15.B16
// V8..V11 += V12..V15
// V4..V7 <<<= ((V4..V7 XOR V8..V11), 7)
VADD V12.S4, V8.S4, V8.S4
VADD V13.S4, V9.S4, V9.S4
VADD V14.S4, V10.S4, V10.S4
VADD V15.S4, V11.S4, V11.S4
VEOR V8.B16, V4.B16, V16.B16
VEOR V9.B16, V5.B16, V17.B16
VEOR V10.B16, V6.B16, V18.B16
VEOR V11.B16, V7.B16, V19.B16
VSHL $7, V16.S4, V4.S4
VSHL $7, V17.S4, V5.S4
VSHL $7, V18.S4, V6.S4
VSHL $7, V19.S4, V7.S4
VSRI $25, V16.S4, V4.S4
VSRI $25, V17.S4, V5.S4
VSRI $25, V18.S4, V6.S4
VSRI $25, V19.S4, V7.S4
// V0..V3 += V5..V7, V4
// V15,V12-V14 <<<= ((V15,V12-V14 XOR V0..V3), 16)
VADD V0.S4, V5.S4, V0.S4
VADD V1.S4, V6.S4, V1.S4
VADD V2.S4, V7.S4, V2.S4
VADD V3.S4, V4.S4, V3.S4
VEOR V15.B16, V0.B16, V15.B16
VEOR V12.B16, V1.B16, V12.B16
VEOR V13.B16, V2.B16, V13.B16
VEOR V14.B16, V3.B16, V14.B16
VREV32 V12.H8, V12.H8
VREV32 V13.H8, V13.H8
VREV32 V14.H8, V14.H8
VREV32 V15.H8, V15.H8
// V10 += V15; V5 <<<= ((V10 XOR V5), 12)
// ...
VADD V15.S4, V10.S4, V10.S4
VADD V12.S4, V11.S4, V11.S4
VADD V13.S4, V8.S4, V8.S4
VADD V14.S4, V9.S4, V9.S4
VEOR V10.B16, V5.B16, V16.B16
VEOR V11.B16, V6.B16, V17.B16
VEOR V8.B16, V7.B16, V18.B16
VEOR V9.B16, V4.B16, V19.B16
VSHL $12, V16.S4, V5.S4
VSHL $12, V17.S4, V6.S4
VSHL $12, V18.S4, V7.S4
VSHL $12, V19.S4, V4.S4
VSRI $20, V16.S4, V5.S4
VSRI $20, V17.S4, V6.S4
VSRI $20, V18.S4, V7.S4
VSRI $20, V19.S4, V4.S4
// V0 += V5; V15 <<<= ((V0 XOR V15), 8)
// ...
VADD V5.S4, V0.S4, V0.S4
VADD V6.S4, V1.S4, V1.S4
VADD V7.S4, V2.S4, V2.S4
VADD V4.S4, V3.S4, V3.S4
VEOR V0.B16, V15.B16, V15.B16
VEOR V1.B16, V12.B16, V12.B16
VEOR V2.B16, V13.B16, V13.B16
VEOR V3.B16, V14.B16, V14.B16
VTBL V31.B16, [V12.B16], V12.B16
VTBL V31.B16, [V13.B16], V13.B16
VTBL V31.B16, [V14.B16], V14.B16
VTBL V31.B16, [V15.B16], V15.B16
// V10 += V15; V5 <<<= ((V10 XOR V5), 7)
// ...
VADD V15.S4, V10.S4, V10.S4
VADD V12.S4, V11.S4, V11.S4
VADD V13.S4, V8.S4, V8.S4
VADD V14.S4, V9.S4, V9.S4
VEOR V10.B16, V5.B16, V16.B16
VEOR V11.B16, V6.B16, V17.B16
VEOR V8.B16, V7.B16, V18.B16
VEOR V9.B16, V4.B16, V19.B16
VSHL $7, V16.S4, V5.S4
VSHL $7, V17.S4, V6.S4
VSHL $7, V18.S4, V7.S4
VSHL $7, V19.S4, V4.S4
VSRI $25, V16.S4, V5.S4
VSRI $25, V17.S4, V6.S4
VSRI $25, V18.S4, V7.S4
VSRI $25, V19.S4, V4.S4
SUB $1, R21
CBNZ R21, chacha
// VLD4R (R10), [V16.S4, V17.S4, V18.S4, V19.S4]
WORD $0x4D60E950
// VLD4R 16(R4), [V20.S4, V21.S4, V22.S4, V23.S4]
WORD $0x4DFFE894
VADD V30.S4, V12.S4, V12.S4
VADD V16.S4, V0.S4, V0.S4
VADD V17.S4, V1.S4, V1.S4
VADD V18.S4, V2.S4, V2.S4
VADD V19.S4, V3.S4, V3.S4
// VLD4R 16(R4), [V24.S4, V25.S4, V26.S4, V27.S4]
WORD $0x4DFFE898
// restore R4
SUB $32, R4
// load counter + nonce
// VLD1R (R7), [V28.S4]
WORD $0x4D40C8FC
// VLD3R (R6), [V29.S4, V30.S4, V31.S4]
WORD $0x4D40E8DD
VADD V20.S4, V4.S4, V4.S4
VADD V21.S4, V5.S4, V5.S4
VADD V22.S4, V6.S4, V6.S4
VADD V23.S4, V7.S4, V7.S4
VADD V24.S4, V8.S4, V8.S4
VADD V25.S4, V9.S4, V9.S4
VADD V26.S4, V10.S4, V10.S4
VADD V27.S4, V11.S4, V11.S4
VADD V28.S4, V12.S4, V12.S4
VADD V29.S4, V13.S4, V13.S4
VADD V30.S4, V14.S4, V14.S4
VADD V31.S4, V15.S4, V15.S4
VZIP1 V1.S4, V0.S4, V16.S4
VZIP2 V1.S4, V0.S4, V17.S4
VZIP1 V3.S4, V2.S4, V18.S4
VZIP2 V3.S4, V2.S4, V19.S4
VZIP1 V5.S4, V4.S4, V20.S4
VZIP2 V5.S4, V4.S4, V21.S4
VZIP1 V7.S4, V6.S4, V22.S4
VZIP2 V7.S4, V6.S4, V23.S4
VZIP1 V9.S4, V8.S4, V24.S4
VZIP2 V9.S4, V8.S4, V25.S4
VZIP1 V11.S4, V10.S4, V26.S4
VZIP2 V11.S4, V10.S4, V27.S4
VZIP1 V13.S4, V12.S4, V28.S4
VZIP2 V13.S4, V12.S4, V29.S4
VZIP1 V15.S4, V14.S4, V30.S4
VZIP2 V15.S4, V14.S4, V31.S4
VZIP1 V18.D2, V16.D2, V0.D2
VZIP2 V18.D2, V16.D2, V4.D2
VZIP1 V19.D2, V17.D2, V8.D2
VZIP2 V19.D2, V17.D2, V12.D2
VLD1.P 64(R2), [V16.B16, V17.B16, V18.B16, V19.B16]
VZIP1 V22.D2, V20.D2, V1.D2
VZIP2 V22.D2, V20.D2, V5.D2
VZIP1 V23.D2, V21.D2, V9.D2
VZIP2 V23.D2, V21.D2, V13.D2
VLD1.P 64(R2), [V20.B16, V21.B16, V22.B16, V23.B16]
VZIP1 V26.D2, V24.D2, V2.D2
VZIP2 V26.D2, V24.D2, V6.D2
VZIP1 V27.D2, V25.D2, V10.D2
VZIP2 V27.D2, V25.D2, V14.D2
VLD1.P 64(R2), [V24.B16, V25.B16, V26.B16, V27.B16]
VZIP1 V30.D2, V28.D2, V3.D2
VZIP2 V30.D2, V28.D2, V7.D2
VZIP1 V31.D2, V29.D2, V11.D2
VZIP2 V31.D2, V29.D2, V15.D2
VLD1.P 64(R2), [V28.B16, V29.B16, V30.B16, V31.B16]
VEOR V0.B16, V16.B16, V16.B16
VEOR V1.B16, V17.B16, V17.B16
VEOR V2.B16, V18.B16, V18.B16
VEOR V3.B16, V19.B16, V19.B16
VST1.P [V16.B16, V17.B16, V18.B16, V19.B16], 64(R1)
VEOR V4.B16, V20.B16, V20.B16
VEOR V5.B16, V21.B16, V21.B16
VEOR V6.B16, V22.B16, V22.B16
VEOR V7.B16, V23.B16, V23.B16
VST1.P [V20.B16, V21.B16, V22.B16, V23.B16], 64(R1)
VEOR V8.B16, V24.B16, V24.B16
VEOR V9.B16, V25.B16, V25.B16
VEOR V10.B16, V26.B16, V26.B16
VEOR V11.B16, V27.B16, V27.B16
VST1.P [V24.B16, V25.B16, V26.B16, V27.B16], 64(R1)
VEOR V12.B16, V28.B16, V28.B16
VEOR V13.B16, V29.B16, V29.B16
VEOR V14.B16, V30.B16, V30.B16
VEOR V15.B16, V31.B16, V31.B16
VST1.P [V28.B16, V29.B16, V30.B16, V31.B16], 64(R1)
ADD $4, R20
MOVW R20, (R7) // update counter
CMP R2, R12
BGT loop
RET
DATA ·constants+0x00(SB)/4, $0x61707865
DATA ·constants+0x04(SB)/4, $0x3320646e
DATA ·constants+0x08(SB)/4, $0x79622d32
DATA ·constants+0x0c(SB)/4, $0x6b206574
GLOBL ·constants(SB), NOPTR|RODATA, $32
DATA ·incRotMatrix+0x00(SB)/4, $0x00000000
DATA ·incRotMatrix+0x04(SB)/4, $0x00000001
DATA ·incRotMatrix+0x08(SB)/4, $0x00000002
DATA ·incRotMatrix+0x0c(SB)/4, $0x00000003
DATA ·incRotMatrix+0x10(SB)/4, $0x02010003
DATA ·incRotMatrix+0x14(SB)/4, $0x06050407
DATA ·incRotMatrix+0x18(SB)/4, $0x0A09080B
DATA ·incRotMatrix+0x1c(SB)/4, $0x0E0D0C0F
GLOBL ·incRotMatrix(SB), NOPTR|RODATA, $32

View File

@@ -0,0 +1,31 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.11
// +build !gccgo
package chacha20
const (
haveAsm = true
bufSize = 256
)
//go:noescape
func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32)
func (c *Cipher) xorKeyStreamAsm(dst, src []byte) {
if len(src) >= bufSize {
xorKeyStreamVX(dst, src, &c.key, &c.nonce, &c.counter)
}
if len(src)%bufSize != 0 {
i := len(src) - len(src)%bufSize
c.buf = [bufSize]byte{}
copy(c.buf[:], src[i:])
xorKeyStreamVX(c.buf[:], c.buf[:], &c.key, &c.nonce, &c.counter)
c.len = bufSize - copy(dst[i:], c.buf[:len(src)%bufSize])
}
}

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !s390x gccgo appengine
// +build !arm64,!s390x arm64,!go1.11 gccgo appengine
package chacha20

3
vendor/golang.org/x/image/AUTHORS generated vendored Normal file
View File

@@ -0,0 +1,3 @@
# This source code refers to The Go Authors for copyright purposes.
# The master list of authors is in the main Go distribution,
# visible at http://tip.golang.org/AUTHORS.

3
vendor/golang.org/x/image/CONTRIBUTORS generated vendored Normal file
View File

@@ -0,0 +1,3 @@
# This source code was written by the Go contributors.
# The master list of contributors is in the main Go distribution,
# visible at http://tip.golang.org/CONTRIBUTORS.

27
vendor/golang.org/x/image/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,27 @@
Copyright (c) 2009 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

22
vendor/golang.org/x/image/PATENTS generated vendored Normal file
View File

@@ -0,0 +1,22 @@
Additional IP Rights Grant (Patents)
"This implementation" means the copyrightable works distributed by
Google as part of the Go project.
Google hereby grants to You a perpetual, worldwide, non-exclusive,
no-charge, royalty-free, irrevocable (except as stated in this section)
patent license to make, have made, use, offer to sell, sell, import,
transfer and otherwise run, modify and propagate the contents of this
implementation of Go, where such license applies only to those patent
claims, both currently owned or controlled by Google and acquired in
the future, licensable by Google that are necessarily infringed by this
implementation of Go. This grant does not include claims that would be
infringed only as a consequence of further modification of this
implementation. If you or your agent or exclusive licensee institute or
order or agree to the institution of patent litigation against any
entity (including a cross-claim or counterclaim in a lawsuit) alleging
that this implementation of Go or any code incorporated within this
implementation of Go constitutes direct or contributory patent
infringement, or inducement of patent infringement, then any patent
rights granted to you under this License for this implementation of Go
shall terminate as of the date such litigation is filed.

193
vendor/golang.org/x/image/riff/riff.go generated vendored Normal file
View File

@@ -0,0 +1,193 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package riff implements the Resource Interchange File Format, used by media
// formats such as AVI, WAVE and WEBP.
//
// A RIFF stream contains a sequence of chunks. Each chunk consists of an 8-byte
// header (containing a 4-byte chunk type and a 4-byte chunk length), the chunk
// data (presented as an io.Reader), and some padding bytes.
//
// A detailed description of the format is at
// http://www.tactilemedia.com/info/MCI_Control_Info.html
package riff // import "golang.org/x/image/riff"
import (
"errors"
"io"
"io/ioutil"
"math"
)
var (
errMissingPaddingByte = errors.New("riff: missing padding byte")
errMissingRIFFChunkHeader = errors.New("riff: missing RIFF chunk header")
errListSubchunkTooLong = errors.New("riff: list subchunk too long")
errShortChunkData = errors.New("riff: short chunk data")
errShortChunkHeader = errors.New("riff: short chunk header")
errStaleReader = errors.New("riff: stale reader")
)
// u32 decodes the first four bytes of b as a little-endian integer.
func u32(b []byte) uint32 {
return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
}
const chunkHeaderSize = 8
// FourCC is a four character code.
type FourCC [4]byte
// LIST is the "LIST" FourCC.
var LIST = FourCC{'L', 'I', 'S', 'T'}
// NewReader returns the RIFF stream's form type, such as "AVI " or "WAVE", and
// its chunks as a *Reader.
func NewReader(r io.Reader) (formType FourCC, data *Reader, err error) {
var buf [chunkHeaderSize]byte
if _, err := io.ReadFull(r, buf[:]); err != nil {
if err == io.EOF || err == io.ErrUnexpectedEOF {
err = errMissingRIFFChunkHeader
}
return FourCC{}, nil, err
}
if buf[0] != 'R' || buf[1] != 'I' || buf[2] != 'F' || buf[3] != 'F' {
return FourCC{}, nil, errMissingRIFFChunkHeader
}
return NewListReader(u32(buf[4:]), r)
}
// NewListReader returns a LIST chunk's list type, such as "movi" or "wavl",
// and its chunks as a *Reader.
func NewListReader(chunkLen uint32, chunkData io.Reader) (listType FourCC, data *Reader, err error) {
if chunkLen < 4 {
return FourCC{}, nil, errShortChunkData
}
z := &Reader{r: chunkData}
if _, err := io.ReadFull(chunkData, z.buf[:4]); err != nil {
if err == io.EOF || err == io.ErrUnexpectedEOF {
err = errShortChunkData
}
return FourCC{}, nil, err
}
z.totalLen = chunkLen - 4
return FourCC{z.buf[0], z.buf[1], z.buf[2], z.buf[3]}, z, nil
}
// Reader reads chunks from an underlying io.Reader.
type Reader struct {
r io.Reader
err error
totalLen uint32
chunkLen uint32
chunkReader *chunkReader
buf [chunkHeaderSize]byte
padded bool
}
// Next returns the next chunk's ID, length and data. It returns io.EOF if there
// are no more chunks. The io.Reader returned becomes stale after the next Next
// call, and should no longer be used.
//
// It is valid to call Next even if all of the previous chunk's data has not
// been read.
func (z *Reader) Next() (chunkID FourCC, chunkLen uint32, chunkData io.Reader, err error) {
if z.err != nil {
return FourCC{}, 0, nil, z.err
}
// Drain the rest of the previous chunk.
if z.chunkLen != 0 {
want := z.chunkLen
var got int64
got, z.err = io.Copy(ioutil.Discard, z.chunkReader)
if z.err == nil && uint32(got) != want {
z.err = errShortChunkData
}
if z.err != nil {
return FourCC{}, 0, nil, z.err
}
}
z.chunkReader = nil
if z.padded {
if z.totalLen == 0 {
z.err = errListSubchunkTooLong
return FourCC{}, 0, nil, z.err
}
z.totalLen--
_, z.err = io.ReadFull(z.r, z.buf[:1])
if z.err != nil {
if z.err == io.EOF {
z.err = errMissingPaddingByte
}
return FourCC{}, 0, nil, z.err
}
}
// We are done if we have no more data.
if z.totalLen == 0 {
z.err = io.EOF
return FourCC{}, 0, nil, z.err
}
// Read the next chunk header.
if z.totalLen < chunkHeaderSize {
z.err = errShortChunkHeader
return FourCC{}, 0, nil, z.err
}
z.totalLen -= chunkHeaderSize
if _, z.err = io.ReadFull(z.r, z.buf[:chunkHeaderSize]); z.err != nil {
if z.err == io.EOF || z.err == io.ErrUnexpectedEOF {
z.err = errShortChunkHeader
}
return FourCC{}, 0, nil, z.err
}
chunkID = FourCC{z.buf[0], z.buf[1], z.buf[2], z.buf[3]}
z.chunkLen = u32(z.buf[4:])
if z.chunkLen > z.totalLen {
z.err = errListSubchunkTooLong
return FourCC{}, 0, nil, z.err
}
z.padded = z.chunkLen&1 == 1
z.chunkReader = &chunkReader{z}
return chunkID, z.chunkLen, z.chunkReader, nil
}
type chunkReader struct {
z *Reader
}
func (c *chunkReader) Read(p []byte) (int, error) {
if c != c.z.chunkReader {
return 0, errStaleReader
}
z := c.z
if z.err != nil {
if z.err == io.EOF {
return 0, errStaleReader
}
return 0, z.err
}
n := int(z.chunkLen)
if n == 0 {
return 0, io.EOF
}
if n < 0 {
// Converting uint32 to int overflowed.
n = math.MaxInt32
}
if n > len(p) {
n = len(p)
}
n, err := z.r.Read(p[:n])
z.totalLen -= uint32(n)
z.chunkLen -= uint32(n)
if err != io.EOF {
z.err = err
}
return n, err
}

403
vendor/golang.org/x/image/vp8/decode.go generated vendored Normal file
View File

@@ -0,0 +1,403 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package vp8 implements a decoder for the VP8 lossy image format.
//
// The VP8 specification is RFC 6386.
package vp8 // import "golang.org/x/image/vp8"
// This file implements the top-level decoding algorithm.
import (
"errors"
"image"
"io"
)
// limitReader wraps an io.Reader to read at most n bytes from it.
type limitReader struct {
r io.Reader
n int
}
// ReadFull reads exactly len(p) bytes into p.
func (r *limitReader) ReadFull(p []byte) error {
if len(p) > r.n {
return io.ErrUnexpectedEOF
}
n, err := io.ReadFull(r.r, p)
r.n -= n
return err
}
// FrameHeader is a frame header, as specified in section 9.1.
type FrameHeader struct {
KeyFrame bool
VersionNumber uint8
ShowFrame bool
FirstPartitionLen uint32
Width int
Height int
XScale uint8
YScale uint8
}
const (
nSegment = 4
nSegmentProb = 3
)
// segmentHeader holds segment-related header information.
type segmentHeader struct {
useSegment bool
updateMap bool
relativeDelta bool
quantizer [nSegment]int8
filterStrength [nSegment]int8
prob [nSegmentProb]uint8
}
const (
nRefLFDelta = 4
nModeLFDelta = 4
)
// filterHeader holds filter-related header information.
type filterHeader struct {
simple bool
level int8
sharpness uint8
useLFDelta bool
refLFDelta [nRefLFDelta]int8
modeLFDelta [nModeLFDelta]int8
perSegmentLevel [nSegment]int8
}
// mb is the per-macroblock decode state. A decoder maintains mbw+1 of these
// as it is decoding macroblocks left-to-right and top-to-bottom: mbw for the
// macroblocks in the row above, and one for the macroblock to the left.
type mb struct {
// pred is the predictor mode for the 4 bottom or right 4x4 luma regions.
pred [4]uint8
// nzMask is a mask of 8 bits: 4 for the bottom or right 4x4 luma regions,
// and 2 + 2 for the bottom or right 4x4 chroma regions. A 1 bit indicates
// that region has non-zero coefficients.
nzMask uint8
// nzY16 is a 0/1 value that is 1 if the macroblock used Y16 prediction and
// had non-zero coefficients.
nzY16 uint8
}
// Decoder decodes VP8 bitstreams into frames. Decoding one frame consists of
// calling Init, DecodeFrameHeader and then DecodeFrame in that order.
// A Decoder can be re-used to decode multiple frames.
type Decoder struct {
// r is the input bitsream.
r limitReader
// scratch is a scratch buffer.
scratch [8]byte
// img is the YCbCr image to decode into.
img *image.YCbCr
// mbw and mbh are the number of 16x16 macroblocks wide and high the image is.
mbw, mbh int
// frameHeader is the frame header. When decoding multiple frames,
// frames that aren't key frames will inherit the Width, Height,
// XScale and YScale of the most recent key frame.
frameHeader FrameHeader
// Other headers.
segmentHeader segmentHeader
filterHeader filterHeader
// The image data is divided into a number of independent partitions.
// There is 1 "first partition" and between 1 and 8 "other partitions"
// for coefficient data.
fp partition
op [8]partition
nOP int
// Quantization factors.
quant [nSegment]quant
// DCT/WHT coefficient decoding probabilities.
tokenProb [nPlane][nBand][nContext][nProb]uint8
useSkipProb bool
skipProb uint8
// Loop filter parameters.
filterParams [nSegment][2]filterParam
perMBFilterParams []filterParam
// The eight fields below relate to the current macroblock being decoded.
//
// Segment-based adjustments.
segment int
// Per-macroblock state for the macroblock immediately left of and those
// macroblocks immediately above the current macroblock.
leftMB mb
upMB []mb
// Bitmasks for which 4x4 regions of coeff contain non-zero coefficients.
nzDCMask, nzACMask uint32
// Predictor modes.
usePredY16 bool // The libwebp C code calls this !is_i4x4_.
predY16 uint8
predC8 uint8
predY4 [4][4]uint8
// The two fields below form a workspace for reconstructing a macroblock.
// Their specific sizes are documented in reconstruct.go.
coeff [1*16*16 + 2*8*8 + 1*4*4]int16
ybr [1 + 16 + 1 + 8][32]uint8
}
// NewDecoder returns a new Decoder.
func NewDecoder() *Decoder {
return &Decoder{}
}
// Init initializes the decoder to read at most n bytes from r.
func (d *Decoder) Init(r io.Reader, n int) {
d.r = limitReader{r, n}
}
// DecodeFrameHeader decodes the frame header.
func (d *Decoder) DecodeFrameHeader() (fh FrameHeader, err error) {
// All frame headers are at least 3 bytes long.
b := d.scratch[:3]
if err = d.r.ReadFull(b); err != nil {
return
}
d.frameHeader.KeyFrame = (b[0] & 1) == 0
d.frameHeader.VersionNumber = (b[0] >> 1) & 7
d.frameHeader.ShowFrame = (b[0]>>4)&1 == 1
d.frameHeader.FirstPartitionLen = uint32(b[0])>>5 | uint32(b[1])<<3 | uint32(b[2])<<11
if !d.frameHeader.KeyFrame {
return d.frameHeader, nil
}
// Frame headers for key frames are an additional 7 bytes long.
b = d.scratch[:7]
if err = d.r.ReadFull(b); err != nil {
return
}
// Check the magic sync code.
if b[0] != 0x9d || b[1] != 0x01 || b[2] != 0x2a {
err = errors.New("vp8: invalid format")
return
}
d.frameHeader.Width = int(b[4]&0x3f)<<8 | int(b[3])
d.frameHeader.Height = int(b[6]&0x3f)<<8 | int(b[5])
d.frameHeader.XScale = b[4] >> 6
d.frameHeader.YScale = b[6] >> 6
d.mbw = (d.frameHeader.Width + 0x0f) >> 4
d.mbh = (d.frameHeader.Height + 0x0f) >> 4
d.segmentHeader = segmentHeader{
prob: [3]uint8{0xff, 0xff, 0xff},
}
d.tokenProb = defaultTokenProb
d.segment = 0
return d.frameHeader, nil
}
// ensureImg ensures that d.img is large enough to hold the decoded frame.
func (d *Decoder) ensureImg() {
if d.img != nil {
p0, p1 := d.img.Rect.Min, d.img.Rect.Max
if p0.X == 0 && p0.Y == 0 && p1.X >= 16*d.mbw && p1.Y >= 16*d.mbh {
return
}
}
m := image.NewYCbCr(image.Rect(0, 0, 16*d.mbw, 16*d.mbh), image.YCbCrSubsampleRatio420)
d.img = m.SubImage(image.Rect(0, 0, d.frameHeader.Width, d.frameHeader.Height)).(*image.YCbCr)
d.perMBFilterParams = make([]filterParam, d.mbw*d.mbh)
d.upMB = make([]mb, d.mbw)
}
// parseSegmentHeader parses the segment header, as specified in section 9.3.
func (d *Decoder) parseSegmentHeader() {
d.segmentHeader.useSegment = d.fp.readBit(uniformProb)
if !d.segmentHeader.useSegment {
d.segmentHeader.updateMap = false
return
}
d.segmentHeader.updateMap = d.fp.readBit(uniformProb)
if d.fp.readBit(uniformProb) {
d.segmentHeader.relativeDelta = !d.fp.readBit(uniformProb)
for i := range d.segmentHeader.quantizer {
d.segmentHeader.quantizer[i] = int8(d.fp.readOptionalInt(uniformProb, 7))
}
for i := range d.segmentHeader.filterStrength {
d.segmentHeader.filterStrength[i] = int8(d.fp.readOptionalInt(uniformProb, 6))
}
}
if !d.segmentHeader.updateMap {
return
}
for i := range d.segmentHeader.prob {
if d.fp.readBit(uniformProb) {
d.segmentHeader.prob[i] = uint8(d.fp.readUint(uniformProb, 8))
} else {
d.segmentHeader.prob[i] = 0xff
}
}
}
// parseFilterHeader parses the filter header, as specified in section 9.4.
func (d *Decoder) parseFilterHeader() {
d.filterHeader.simple = d.fp.readBit(uniformProb)
d.filterHeader.level = int8(d.fp.readUint(uniformProb, 6))
d.filterHeader.sharpness = uint8(d.fp.readUint(uniformProb, 3))
d.filterHeader.useLFDelta = d.fp.readBit(uniformProb)
if d.filterHeader.useLFDelta && d.fp.readBit(uniformProb) {
for i := range d.filterHeader.refLFDelta {
d.filterHeader.refLFDelta[i] = int8(d.fp.readOptionalInt(uniformProb, 6))
}
for i := range d.filterHeader.modeLFDelta {
d.filterHeader.modeLFDelta[i] = int8(d.fp.readOptionalInt(uniformProb, 6))
}
}
if d.filterHeader.level == 0 {
return
}
if d.segmentHeader.useSegment {
for i := range d.filterHeader.perSegmentLevel {
strength := d.segmentHeader.filterStrength[i]
if d.segmentHeader.relativeDelta {
strength += d.filterHeader.level
}
d.filterHeader.perSegmentLevel[i] = strength
}
} else {
d.filterHeader.perSegmentLevel[0] = d.filterHeader.level
}
d.computeFilterParams()
}
// parseOtherPartitions parses the other partitions, as specified in section 9.5.
func (d *Decoder) parseOtherPartitions() error {
const maxNOP = 1 << 3
var partLens [maxNOP]int
d.nOP = 1 << d.fp.readUint(uniformProb, 2)
// The final partition length is implied by the remaining chunk data
// (d.r.n) and the other d.nOP-1 partition lengths. Those d.nOP-1 partition
// lengths are stored as 24-bit uints, i.e. up to 16 MiB per partition.
n := 3 * (d.nOP - 1)
partLens[d.nOP-1] = d.r.n - n
if partLens[d.nOP-1] < 0 {
return io.ErrUnexpectedEOF
}
if n > 0 {
buf := make([]byte, n)
if err := d.r.ReadFull(buf); err != nil {
return err
}
for i := 0; i < d.nOP-1; i++ {
pl := int(buf[3*i+0]) | int(buf[3*i+1])<<8 | int(buf[3*i+2])<<16
if pl > partLens[d.nOP-1] {
return io.ErrUnexpectedEOF
}
partLens[i] = pl
partLens[d.nOP-1] -= pl
}
}
// We check if the final partition length can also fit into a 24-bit uint.
// Strictly speaking, this isn't part of the spec, but it guards against a
// malicious WEBP image that is too large to ReadFull the encoded DCT
// coefficients into memory, whether that's because the actual WEBP file is
// too large, or whether its RIFF metadata lists too large a chunk.
if 1<<24 <= partLens[d.nOP-1] {
return errors.New("vp8: too much data to decode")
}
buf := make([]byte, d.r.n)
if err := d.r.ReadFull(buf); err != nil {
return err
}
for i, pl := range partLens {
if i == d.nOP {
break
}
d.op[i].init(buf[:pl])
buf = buf[pl:]
}
return nil
}
// parseOtherHeaders parses header information other than the frame header.
func (d *Decoder) parseOtherHeaders() error {
// Initialize and parse the first partition.
firstPartition := make([]byte, d.frameHeader.FirstPartitionLen)
if err := d.r.ReadFull(firstPartition); err != nil {
return err
}
d.fp.init(firstPartition)
if d.frameHeader.KeyFrame {
// Read and ignore the color space and pixel clamp values. They are
// specified in section 9.2, but are unimplemented.
d.fp.readBit(uniformProb)
d.fp.readBit(uniformProb)
}
d.parseSegmentHeader()
d.parseFilterHeader()
if err := d.parseOtherPartitions(); err != nil {
return err
}
d.parseQuant()
if !d.frameHeader.KeyFrame {
// Golden and AltRef frames are specified in section 9.7.
// TODO(nigeltao): implement. Note that they are only used for video, not still images.
return errors.New("vp8: Golden / AltRef frames are not implemented")
}
// Read and ignore the refreshLastFrameBuffer bit, specified in section 9.8.
// It applies only to video, and not still images.
d.fp.readBit(uniformProb)
d.parseTokenProb()
d.useSkipProb = d.fp.readBit(uniformProb)
if d.useSkipProb {
d.skipProb = uint8(d.fp.readUint(uniformProb, 8))
}
if d.fp.unexpectedEOF {
return io.ErrUnexpectedEOF
}
return nil
}
// DecodeFrame decodes the frame and returns it as an YCbCr image.
// The image's contents are valid up until the next call to Decoder.Init.
func (d *Decoder) DecodeFrame() (*image.YCbCr, error) {
d.ensureImg()
if err := d.parseOtherHeaders(); err != nil {
return nil, err
}
// Reconstruct the rows.
for mbx := 0; mbx < d.mbw; mbx++ {
d.upMB[mbx] = mb{}
}
for mby := 0; mby < d.mbh; mby++ {
d.leftMB = mb{}
for mbx := 0; mbx < d.mbw; mbx++ {
skip := d.reconstruct(mbx, mby)
fs := d.filterParams[d.segment][btou(!d.usePredY16)]
fs.inner = fs.inner || !skip
d.perMBFilterParams[d.mbw*mby+mbx] = fs
}
}
if d.fp.unexpectedEOF {
return nil, io.ErrUnexpectedEOF
}
for i := 0; i < d.nOP; i++ {
if d.op[i].unexpectedEOF {
return nil, io.ErrUnexpectedEOF
}
}
// Apply the loop filter.
//
// Even if we are using per-segment levels, section 15 says that "loop
// filtering must be skipped entirely if loop_filter_level at either the
// frame header level or macroblock override level is 0".
if d.filterHeader.level != 0 {
if d.filterHeader.simple {
d.simpleFilter()
} else {
d.normalFilter()
}
}
return d.img, nil
}

273
vendor/golang.org/x/image/vp8/filter.go generated vendored Normal file
View File

@@ -0,0 +1,273 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package vp8
// filter2 modifies a 2-pixel wide or 2-pixel high band along an edge.
func filter2(pix []byte, level, index, iStep, jStep int) {
for n := 16; n > 0; n, index = n-1, index+iStep {
p1 := int(pix[index-2*jStep])
p0 := int(pix[index-1*jStep])
q0 := int(pix[index+0*jStep])
q1 := int(pix[index+1*jStep])
if abs(p0-q0)<<1+abs(p1-q1)>>1 > level {
continue
}
a := 3*(q0-p0) + clamp127(p1-q1)
a1 := clamp15((a + 4) >> 3)
a2 := clamp15((a + 3) >> 3)
pix[index-1*jStep] = clamp255(p0 + a2)
pix[index+0*jStep] = clamp255(q0 - a1)
}
}
// filter246 modifies a 2-, 4- or 6-pixel wide or high band along an edge.
func filter246(pix []byte, n, level, ilevel, hlevel, index, iStep, jStep int, fourNotSix bool) {
for ; n > 0; n, index = n-1, index+iStep {
p3 := int(pix[index-4*jStep])
p2 := int(pix[index-3*jStep])
p1 := int(pix[index-2*jStep])
p0 := int(pix[index-1*jStep])
q0 := int(pix[index+0*jStep])
q1 := int(pix[index+1*jStep])
q2 := int(pix[index+2*jStep])
q3 := int(pix[index+3*jStep])
if abs(p0-q0)<<1+abs(p1-q1)>>1 > level {
continue
}
if abs(p3-p2) > ilevel ||
abs(p2-p1) > ilevel ||
abs(p1-p0) > ilevel ||
abs(q1-q0) > ilevel ||
abs(q2-q1) > ilevel ||
abs(q3-q2) > ilevel {
continue
}
if abs(p1-p0) > hlevel || abs(q1-q0) > hlevel {
// Filter 2 pixels.
a := 3*(q0-p0) + clamp127(p1-q1)
a1 := clamp15((a + 4) >> 3)
a2 := clamp15((a + 3) >> 3)
pix[index-1*jStep] = clamp255(p0 + a2)
pix[index+0*jStep] = clamp255(q0 - a1)
} else if fourNotSix {
// Filter 4 pixels.
a := 3 * (q0 - p0)
a1 := clamp15((a + 4) >> 3)
a2 := clamp15((a + 3) >> 3)
a3 := (a1 + 1) >> 1
pix[index-2*jStep] = clamp255(p1 + a3)
pix[index-1*jStep] = clamp255(p0 + a2)
pix[index+0*jStep] = clamp255(q0 - a1)
pix[index+1*jStep] = clamp255(q1 - a3)
} else {
// Filter 6 pixels.
a := clamp127(3*(q0-p0) + clamp127(p1-q1))
a1 := (27*a + 63) >> 7
a2 := (18*a + 63) >> 7
a3 := (9*a + 63) >> 7
pix[index-3*jStep] = clamp255(p2 + a3)
pix[index-2*jStep] = clamp255(p1 + a2)
pix[index-1*jStep] = clamp255(p0 + a1)
pix[index+0*jStep] = clamp255(q0 - a1)
pix[index+1*jStep] = clamp255(q1 - a2)
pix[index+2*jStep] = clamp255(q2 - a3)
}
}
}
// simpleFilter implements the simple filter, as specified in section 15.2.
func (d *Decoder) simpleFilter() {
for mby := 0; mby < d.mbh; mby++ {
for mbx := 0; mbx < d.mbw; mbx++ {
f := d.perMBFilterParams[d.mbw*mby+mbx]
if f.level == 0 {
continue
}
l := int(f.level)
yIndex := (mby*d.img.YStride + mbx) * 16
if mbx > 0 {
filter2(d.img.Y, l+4, yIndex, d.img.YStride, 1)
}
if f.inner {
filter2(d.img.Y, l, yIndex+0x4, d.img.YStride, 1)
filter2(d.img.Y, l, yIndex+0x8, d.img.YStride, 1)
filter2(d.img.Y, l, yIndex+0xc, d.img.YStride, 1)
}
if mby > 0 {
filter2(d.img.Y, l+4, yIndex, 1, d.img.YStride)
}
if f.inner {
filter2(d.img.Y, l, yIndex+d.img.YStride*0x4, 1, d.img.YStride)
filter2(d.img.Y, l, yIndex+d.img.YStride*0x8, 1, d.img.YStride)
filter2(d.img.Y, l, yIndex+d.img.YStride*0xc, 1, d.img.YStride)
}
}
}
}
// normalFilter implements the normal filter, as specified in section 15.3.
func (d *Decoder) normalFilter() {
for mby := 0; mby < d.mbh; mby++ {
for mbx := 0; mbx < d.mbw; mbx++ {
f := d.perMBFilterParams[d.mbw*mby+mbx]
if f.level == 0 {
continue
}
l, il, hl := int(f.level), int(f.ilevel), int(f.hlevel)
yIndex := (mby*d.img.YStride + mbx) * 16
cIndex := (mby*d.img.CStride + mbx) * 8
if mbx > 0 {
filter246(d.img.Y, 16, l+4, il, hl, yIndex, d.img.YStride, 1, false)
filter246(d.img.Cb, 8, l+4, il, hl, cIndex, d.img.CStride, 1, false)
filter246(d.img.Cr, 8, l+4, il, hl, cIndex, d.img.CStride, 1, false)
}
if f.inner {
filter246(d.img.Y, 16, l, il, hl, yIndex+0x4, d.img.YStride, 1, true)
filter246(d.img.Y, 16, l, il, hl, yIndex+0x8, d.img.YStride, 1, true)
filter246(d.img.Y, 16, l, il, hl, yIndex+0xc, d.img.YStride, 1, true)
filter246(d.img.Cb, 8, l, il, hl, cIndex+0x4, d.img.CStride, 1, true)
filter246(d.img.Cr, 8, l, il, hl, cIndex+0x4, d.img.CStride, 1, true)
}
if mby > 0 {
filter246(d.img.Y, 16, l+4, il, hl, yIndex, 1, d.img.YStride, false)
filter246(d.img.Cb, 8, l+4, il, hl, cIndex, 1, d.img.CStride, false)
filter246(d.img.Cr, 8, l+4, il, hl, cIndex, 1, d.img.CStride, false)
}
if f.inner {
filter246(d.img.Y, 16, l, il, hl, yIndex+d.img.YStride*0x4, 1, d.img.YStride, true)
filter246(d.img.Y, 16, l, il, hl, yIndex+d.img.YStride*0x8, 1, d.img.YStride, true)
filter246(d.img.Y, 16, l, il, hl, yIndex+d.img.YStride*0xc, 1, d.img.YStride, true)
filter246(d.img.Cb, 8, l, il, hl, cIndex+d.img.CStride*0x4, 1, d.img.CStride, true)
filter246(d.img.Cr, 8, l, il, hl, cIndex+d.img.CStride*0x4, 1, d.img.CStride, true)
}
}
}
}
// filterParam holds the loop filter parameters for a macroblock.
type filterParam struct {
// The first three fields are thresholds used by the loop filter to smooth
// over the edges and interior of a macroblock. level is used by both the
// simple and normal filters. The inner level and high edge variance level
// are only used by the normal filter.
level, ilevel, hlevel uint8
// inner is whether the inner loop filter cannot be optimized out as a
// no-op for this particular macroblock.
inner bool
}
// computeFilterParams computes the loop filter parameters, as specified in
// section 15.4.
func (d *Decoder) computeFilterParams() {
for i := range d.filterParams {
baseLevel := d.filterHeader.level
if d.segmentHeader.useSegment {
baseLevel = d.segmentHeader.filterStrength[i]
if d.segmentHeader.relativeDelta {
baseLevel += d.filterHeader.level
}
}
for j := range d.filterParams[i] {
p := &d.filterParams[i][j]
p.inner = j != 0
level := baseLevel
if d.filterHeader.useLFDelta {
// The libwebp C code has a "TODO: only CURRENT is handled for now."
level += d.filterHeader.refLFDelta[0]
if j != 0 {
level += d.filterHeader.modeLFDelta[0]
}
}
if level <= 0 {
p.level = 0
continue
}
if level > 63 {
level = 63
}
ilevel := level
if d.filterHeader.sharpness > 0 {
if d.filterHeader.sharpness > 4 {
ilevel >>= 2
} else {
ilevel >>= 1
}
if x := int8(9 - d.filterHeader.sharpness); ilevel > x {
ilevel = x
}
}
if ilevel < 1 {
ilevel = 1
}
p.ilevel = uint8(ilevel)
p.level = uint8(2*level + ilevel)
if d.frameHeader.KeyFrame {
if level < 15 {
p.hlevel = 0
} else if level < 40 {
p.hlevel = 1
} else {
p.hlevel = 2
}
} else {
if level < 15 {
p.hlevel = 0
} else if level < 20 {
p.hlevel = 1
} else if level < 40 {
p.hlevel = 2
} else {
p.hlevel = 3
}
}
}
}
}
// intSize is either 32 or 64.
const intSize = 32 << (^uint(0) >> 63)
func abs(x int) int {
// m := -1 if x < 0. m := 0 otherwise.
m := x >> (intSize - 1)
// In two's complement representation, the negative number
// of any number (except the smallest one) can be computed
// by flipping all the bits and add 1. This is faster than
// code with a branch.
// See Hacker's Delight, section 2-4.
return (x ^ m) - m
}
func clamp15(x int) int {
if x < -16 {
return -16
}
if x > 15 {
return 15
}
return x
}
func clamp127(x int) int {
if x < -128 {
return -128
}
if x > 127 {
return 127
}
return x
}
func clamp255(x int) uint8 {
if x < 0 {
return 0
}
if x > 255 {
return 255
}
return uint8(x)
}

98
vendor/golang.org/x/image/vp8/idct.go generated vendored Normal file
View File

@@ -0,0 +1,98 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package vp8
// This file implements the inverse Discrete Cosine Transform and the inverse
// Walsh Hadamard Transform (WHT), as specified in sections 14.3 and 14.4.
func clip8(i int32) uint8 {
if i < 0 {
return 0
}
if i > 255 {
return 255
}
return uint8(i)
}
func (z *Decoder) inverseDCT4(y, x, coeffBase int) {
const (
c1 = 85627 // 65536 * cos(pi/8) * sqrt(2).
c2 = 35468 // 65536 * sin(pi/8) * sqrt(2).
)
var m [4][4]int32
for i := 0; i < 4; i++ {
a := int32(z.coeff[coeffBase+0]) + int32(z.coeff[coeffBase+8])
b := int32(z.coeff[coeffBase+0]) - int32(z.coeff[coeffBase+8])
c := (int32(z.coeff[coeffBase+4])*c2)>>16 - (int32(z.coeff[coeffBase+12])*c1)>>16
d := (int32(z.coeff[coeffBase+4])*c1)>>16 + (int32(z.coeff[coeffBase+12])*c2)>>16
m[i][0] = a + d
m[i][1] = b + c
m[i][2] = b - c
m[i][3] = a - d
coeffBase++
}
for j := 0; j < 4; j++ {
dc := m[0][j] + 4
a := dc + m[2][j]
b := dc - m[2][j]
c := (m[1][j]*c2)>>16 - (m[3][j]*c1)>>16
d := (m[1][j]*c1)>>16 + (m[3][j]*c2)>>16
z.ybr[y+j][x+0] = clip8(int32(z.ybr[y+j][x+0]) + (a+d)>>3)
z.ybr[y+j][x+1] = clip8(int32(z.ybr[y+j][x+1]) + (b+c)>>3)
z.ybr[y+j][x+2] = clip8(int32(z.ybr[y+j][x+2]) + (b-c)>>3)
z.ybr[y+j][x+3] = clip8(int32(z.ybr[y+j][x+3]) + (a-d)>>3)
}
}
func (z *Decoder) inverseDCT4DCOnly(y, x, coeffBase int) {
dc := (int32(z.coeff[coeffBase+0]) + 4) >> 3
for j := 0; j < 4; j++ {
for i := 0; i < 4; i++ {
z.ybr[y+j][x+i] = clip8(int32(z.ybr[y+j][x+i]) + dc)
}
}
}
func (z *Decoder) inverseDCT8(y, x, coeffBase int) {
z.inverseDCT4(y+0, x+0, coeffBase+0*16)
z.inverseDCT4(y+0, x+4, coeffBase+1*16)
z.inverseDCT4(y+4, x+0, coeffBase+2*16)
z.inverseDCT4(y+4, x+4, coeffBase+3*16)
}
func (z *Decoder) inverseDCT8DCOnly(y, x, coeffBase int) {
z.inverseDCT4DCOnly(y+0, x+0, coeffBase+0*16)
z.inverseDCT4DCOnly(y+0, x+4, coeffBase+1*16)
z.inverseDCT4DCOnly(y+4, x+0, coeffBase+2*16)
z.inverseDCT4DCOnly(y+4, x+4, coeffBase+3*16)
}
func (d *Decoder) inverseWHT16() {
var m [16]int32
for i := 0; i < 4; i++ {
a0 := int32(d.coeff[384+0+i]) + int32(d.coeff[384+12+i])
a1 := int32(d.coeff[384+4+i]) + int32(d.coeff[384+8+i])
a2 := int32(d.coeff[384+4+i]) - int32(d.coeff[384+8+i])
a3 := int32(d.coeff[384+0+i]) - int32(d.coeff[384+12+i])
m[0+i] = a0 + a1
m[8+i] = a0 - a1
m[4+i] = a3 + a2
m[12+i] = a3 - a2
}
out := 0
for i := 0; i < 4; i++ {
dc := m[0+i*4] + 3
a0 := dc + m[3+i*4]
a1 := m[1+i*4] + m[2+i*4]
a2 := m[1+i*4] - m[2+i*4]
a3 := dc - m[3+i*4]
d.coeff[out+0] = int16((a0 + a1) >> 3)
d.coeff[out+16] = int16((a3 + a2) >> 3)
d.coeff[out+32] = int16((a0 - a1) >> 3)
d.coeff[out+48] = int16((a3 - a2) >> 3)
out += 64
}
}

129
vendor/golang.org/x/image/vp8/partition.go generated vendored Normal file
View File

@@ -0,0 +1,129 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package vp8
// Each VP8 frame consists of between 2 and 9 bitstream partitions.
// Each partition is byte-aligned and is independently arithmetic-encoded.
//
// This file implements decoding a partition's bitstream, as specified in
// chapter 7. The implementation follows libwebp's approach instead of the
// specification's reference C implementation. For example, we use a look-up
// table instead of a for loop to recalibrate the encoded range.
var (
lutShift = [127]uint8{
7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
}
lutRangeM1 = [127]uint8{
127,
127, 191,
127, 159, 191, 223,
127, 143, 159, 175, 191, 207, 223, 239,
127, 135, 143, 151, 159, 167, 175, 183, 191, 199, 207, 215, 223, 231, 239, 247,
127, 131, 135, 139, 143, 147, 151, 155, 159, 163, 167, 171, 175, 179, 183, 187,
191, 195, 199, 203, 207, 211, 215, 219, 223, 227, 231, 235, 239, 243, 247, 251,
127, 129, 131, 133, 135, 137, 139, 141, 143, 145, 147, 149, 151, 153, 155, 157,
159, 161, 163, 165, 167, 169, 171, 173, 175, 177, 179, 181, 183, 185, 187, 189,
191, 193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215, 217, 219, 221,
223, 225, 227, 229, 231, 233, 235, 237, 239, 241, 243, 245, 247, 249, 251, 253,
}
)
// uniformProb represents a 50% probability that the next bit is 0.
const uniformProb = 128
// partition holds arithmetic-coded bits.
type partition struct {
// buf is the input bytes.
buf []byte
// r is how many of buf's bytes have been consumed.
r int
// rangeM1 is range minus 1, where range is in the arithmetic coding sense,
// not the Go language sense.
rangeM1 uint32
// bits and nBits hold those bits shifted out of buf but not yet consumed.
bits uint32
nBits uint8
// unexpectedEOF tells whether we tried to read past buf.
unexpectedEOF bool
}
// init initializes the partition.
func (p *partition) init(buf []byte) {
p.buf = buf
p.r = 0
p.rangeM1 = 254
p.bits = 0
p.nBits = 0
p.unexpectedEOF = false
}
// readBit returns the next bit.
func (p *partition) readBit(prob uint8) bool {
if p.nBits < 8 {
if p.r >= len(p.buf) {
p.unexpectedEOF = true
return false
}
// Expression split for 386 compiler.
x := uint32(p.buf[p.r])
p.bits |= x << (8 - p.nBits)
p.r++
p.nBits += 8
}
split := (p.rangeM1*uint32(prob))>>8 + 1
bit := p.bits >= split<<8
if bit {
p.rangeM1 -= split
p.bits -= split << 8
} else {
p.rangeM1 = split - 1
}
if p.rangeM1 < 127 {
shift := lutShift[p.rangeM1]
p.rangeM1 = uint32(lutRangeM1[p.rangeM1])
p.bits <<= shift
p.nBits -= shift
}
return bit
}
// readUint returns the next n-bit unsigned integer.
func (p *partition) readUint(prob, n uint8) uint32 {
var u uint32
for n > 0 {
n--
if p.readBit(prob) {
u |= 1 << n
}
}
return u
}
// readInt returns the next n-bit signed integer.
func (p *partition) readInt(prob, n uint8) int32 {
u := p.readUint(prob, n)
b := p.readBit(prob)
if b {
return -int32(u)
}
return int32(u)
}
// readOptionalInt returns the next n-bit signed integer in an encoding
// where the likely result is zero.
func (p *partition) readOptionalInt(prob, n uint8) int32 {
if !p.readBit(prob) {
return 0
}
return p.readInt(prob, n)
}

201
vendor/golang.org/x/image/vp8/pred.go generated vendored Normal file
View File

@@ -0,0 +1,201 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package vp8
// This file implements parsing the predictor modes, as specified in chapter
// 11.
func (d *Decoder) parsePredModeY16(mbx int) {
var p uint8
if !d.fp.readBit(156) {
if !d.fp.readBit(163) {
p = predDC
} else {
p = predVE
}
} else if !d.fp.readBit(128) {
p = predHE
} else {
p = predTM
}
for i := 0; i < 4; i++ {
d.upMB[mbx].pred[i] = p
d.leftMB.pred[i] = p
}
d.predY16 = p
}
func (d *Decoder) parsePredModeC8() {
if !d.fp.readBit(142) {
d.predC8 = predDC
} else if !d.fp.readBit(114) {
d.predC8 = predVE
} else if !d.fp.readBit(183) {
d.predC8 = predHE
} else {
d.predC8 = predTM
}
}
func (d *Decoder) parsePredModeY4(mbx int) {
for j := 0; j < 4; j++ {
p := d.leftMB.pred[j]
for i := 0; i < 4; i++ {
prob := &predProb[d.upMB[mbx].pred[i]][p]
if !d.fp.readBit(prob[0]) {
p = predDC
} else if !d.fp.readBit(prob[1]) {
p = predTM
} else if !d.fp.readBit(prob[2]) {
p = predVE
} else if !d.fp.readBit(prob[3]) {
if !d.fp.readBit(prob[4]) {
p = predHE
} else if !d.fp.readBit(prob[5]) {
p = predRD
} else {
p = predVR
}
} else if !d.fp.readBit(prob[6]) {
p = predLD
} else if !d.fp.readBit(prob[7]) {
p = predVL
} else if !d.fp.readBit(prob[8]) {
p = predHD
} else {
p = predHU
}
d.predY4[j][i] = p
d.upMB[mbx].pred[i] = p
}
d.leftMB.pred[j] = p
}
}
// predProb are the probabilities to decode a 4x4 region's predictor mode given
// the predictor modes of the regions above and left of it.
// These values are specified in section 11.5.
var predProb = [nPred][nPred][9]uint8{
{
{231, 120, 48, 89, 115, 113, 120, 152, 112},
{152, 179, 64, 126, 170, 118, 46, 70, 95},
{175, 69, 143, 80, 85, 82, 72, 155, 103},
{56, 58, 10, 171, 218, 189, 17, 13, 152},
{114, 26, 17, 163, 44, 195, 21, 10, 173},
{121, 24, 80, 195, 26, 62, 44, 64, 85},
{144, 71, 10, 38, 171, 213, 144, 34, 26},
{170, 46, 55, 19, 136, 160, 33, 206, 71},
{63, 20, 8, 114, 114, 208, 12, 9, 226},
{81, 40, 11, 96, 182, 84, 29, 16, 36},
},
{
{134, 183, 89, 137, 98, 101, 106, 165, 148},
{72, 187, 100, 130, 157, 111, 32, 75, 80},
{66, 102, 167, 99, 74, 62, 40, 234, 128},
{41, 53, 9, 178, 241, 141, 26, 8, 107},
{74, 43, 26, 146, 73, 166, 49, 23, 157},
{65, 38, 105, 160, 51, 52, 31, 115, 128},
{104, 79, 12, 27, 217, 255, 87, 17, 7},
{87, 68, 71, 44, 114, 51, 15, 186, 23},
{47, 41, 14, 110, 182, 183, 21, 17, 194},
{66, 45, 25, 102, 197, 189, 23, 18, 22},
},
{
{88, 88, 147, 150, 42, 46, 45, 196, 205},
{43, 97, 183, 117, 85, 38, 35, 179, 61},
{39, 53, 200, 87, 26, 21, 43, 232, 171},
{56, 34, 51, 104, 114, 102, 29, 93, 77},
{39, 28, 85, 171, 58, 165, 90, 98, 64},
{34, 22, 116, 206, 23, 34, 43, 166, 73},
{107, 54, 32, 26, 51, 1, 81, 43, 31},
{68, 25, 106, 22, 64, 171, 36, 225, 114},
{34, 19, 21, 102, 132, 188, 16, 76, 124},
{62, 18, 78, 95, 85, 57, 50, 48, 51},
},
{
{193, 101, 35, 159, 215, 111, 89, 46, 111},
{60, 148, 31, 172, 219, 228, 21, 18, 111},
{112, 113, 77, 85, 179, 255, 38, 120, 114},
{40, 42, 1, 196, 245, 209, 10, 25, 109},
{88, 43, 29, 140, 166, 213, 37, 43, 154},
{61, 63, 30, 155, 67, 45, 68, 1, 209},
{100, 80, 8, 43, 154, 1, 51, 26, 71},
{142, 78, 78, 16, 255, 128, 34, 197, 171},
{41, 40, 5, 102, 211, 183, 4, 1, 221},
{51, 50, 17, 168, 209, 192, 23, 25, 82},
},
{
{138, 31, 36, 171, 27, 166, 38, 44, 229},
{67, 87, 58, 169, 82, 115, 26, 59, 179},
{63, 59, 90, 180, 59, 166, 93, 73, 154},
{40, 40, 21, 116, 143, 209, 34, 39, 175},
{47, 15, 16, 183, 34, 223, 49, 45, 183},
{46, 17, 33, 183, 6, 98, 15, 32, 183},
{57, 46, 22, 24, 128, 1, 54, 17, 37},
{65, 32, 73, 115, 28, 128, 23, 128, 205},
{40, 3, 9, 115, 51, 192, 18, 6, 223},
{87, 37, 9, 115, 59, 77, 64, 21, 47},
},
{
{104, 55, 44, 218, 9, 54, 53, 130, 226},
{64, 90, 70, 205, 40, 41, 23, 26, 57},
{54, 57, 112, 184, 5, 41, 38, 166, 213},
{30, 34, 26, 133, 152, 116, 10, 32, 134},
{39, 19, 53, 221, 26, 114, 32, 73, 255},
{31, 9, 65, 234, 2, 15, 1, 118, 73},
{75, 32, 12, 51, 192, 255, 160, 43, 51},
{88, 31, 35, 67, 102, 85, 55, 186, 85},
{56, 21, 23, 111, 59, 205, 45, 37, 192},
{55, 38, 70, 124, 73, 102, 1, 34, 98},
},
{
{125, 98, 42, 88, 104, 85, 117, 175, 82},
{95, 84, 53, 89, 128, 100, 113, 101, 45},
{75, 79, 123, 47, 51, 128, 81, 171, 1},
{57, 17, 5, 71, 102, 57, 53, 41, 49},
{38, 33, 13, 121, 57, 73, 26, 1, 85},
{41, 10, 67, 138, 77, 110, 90, 47, 114},
{115, 21, 2, 10, 102, 255, 166, 23, 6},
{101, 29, 16, 10, 85, 128, 101, 196, 26},
{57, 18, 10, 102, 102, 213, 34, 20, 43},
{117, 20, 15, 36, 163, 128, 68, 1, 26},
},
{
{102, 61, 71, 37, 34, 53, 31, 243, 192},
{69, 60, 71, 38, 73, 119, 28, 222, 37},
{68, 45, 128, 34, 1, 47, 11, 245, 171},
{62, 17, 19, 70, 146, 85, 55, 62, 70},
{37, 43, 37, 154, 100, 163, 85, 160, 1},
{63, 9, 92, 136, 28, 64, 32, 201, 85},
{75, 15, 9, 9, 64, 255, 184, 119, 16},
{86, 6, 28, 5, 64, 255, 25, 248, 1},
{56, 8, 17, 132, 137, 255, 55, 116, 128},
{58, 15, 20, 82, 135, 57, 26, 121, 40},
},
{
{164, 50, 31, 137, 154, 133, 25, 35, 218},
{51, 103, 44, 131, 131, 123, 31, 6, 158},
{86, 40, 64, 135, 148, 224, 45, 183, 128},
{22, 26, 17, 131, 240, 154, 14, 1, 209},
{45, 16, 21, 91, 64, 222, 7, 1, 197},
{56, 21, 39, 155, 60, 138, 23, 102, 213},
{83, 12, 13, 54, 192, 255, 68, 47, 28},
{85, 26, 85, 85, 128, 128, 32, 146, 171},
{18, 11, 7, 63, 144, 171, 4, 4, 246},
{35, 27, 10, 146, 174, 171, 12, 26, 128},
},
{
{190, 80, 35, 99, 180, 80, 126, 54, 45},
{85, 126, 47, 87, 176, 51, 41, 20, 32},
{101, 75, 128, 139, 118, 146, 116, 128, 85},
{56, 41, 15, 176, 236, 85, 37, 9, 62},
{71, 30, 17, 119, 118, 255, 17, 18, 138},
{101, 38, 60, 138, 55, 70, 43, 26, 142},
{146, 36, 19, 30, 171, 255, 97, 27, 20},
{138, 45, 61, 62, 219, 1, 81, 188, 64},
{32, 41, 20, 117, 151, 142, 20, 21, 163},
{112, 19, 12, 61, 195, 128, 48, 4, 24},
},
}

Some files were not shown because too many files have changed in this diff Show More