<commit_before>package kwiscale

import (
	"fmt"
	"html/template"
	"io"
	"io/ioutil"
	"path/filepath"
	"reflect"
	"regexp"
	"strings"
)

var templateEngine = make(map[string]reflect.Type)

// TplOptions are template options to pass to template engines if needed
type TplOptions map[string]interface{}

// RegisterTemplateEngine records template engine that implements Template
// interface. The name is used to let config select the template engine.
func RegisterTemplateEngine(name string, tpl Template) {
	templateEngine[name] = reflect.ValueOf(tpl).Elem().Type()
}

// register basic template engine by default.
func init() {
	RegisterTemplateEngine("basic", &BuiltInTemplate{})
}

// Template should be implemented by other template implementation to
// allow RequestHandlers to use Render() method
type Template interface {
	// Render method to implement to compile and run template
	// then write to RequestHandler "w" that is a io.Writer.
	Render(w io.Writer, template string, ctx interface{}) error

	// SetTemplateDir should set the template base directory
	SetTemplateDir(string)

	// SetOptions pass TplOptions to template engine
	SetTemplateOptions(TplOptions)
}

// BuiltInTemplate is Basic template engine that use html/template.
type BuiltInTemplate struct {
	files  []string
	tpldir string
}

// SetTemplateDir set the directory where are found templates.
func (tpl *BuiltInTemplate) SetTemplateDir(path string) {
	t, err := filepath.Abs(path)

	if err != nil {
		panic(err)
	}
	tpl.tpldir = t
	Log("Template dir set to ", tpl.tpldir)
}

// Render method for the basic Template system.
// Allow {{/* override "path.html" */}}, no cache, very basic.
func (tpl *BuiltInTemplate) Render(w io.Writer, file string, ctx interface{}) error {
	var err error
	defer func() {
		if err != nil {
			Error(err)
		}
	}()

	file = filepath.Join(tpl.tpldir, file)

	tpl.files = make([]string, 0)
	content, err := ioutil.ReadFile(file)

	// panic if read file breaks
	if err != nil {
		panic(err)
	}

	tpl.parseOverride(content)

	tpl.files = append(tpl.files, file)

	Log(tpl.files)

	funcmap := template.FuncMap{
		"static": func(file string) string {
			app := w.(WebHandler).App()
			url, err := app.GetRoute("statics").URL("file", file)
			if err != nil {
				return err.Error()
			}
			return url.String()
		},
		"url": func(handler string, args ...interface{}) string {
			pairs := []string{}
			for _, p := range args {
				pairs = append(pairs, fmt.Sprintf("%v", p))
			}
			h := w.(WebHandler).App().GetRoutes(handler)
			base := []string{}
			for _, r := range h {
				url, err := r.URL(pairs...)
				if err != nil {
					continue
				}
				route := strings.Split(url.String(), "/")
				if len(route) >= len(base) {
					base = route
				}
			}
			if len(base) == 0 {
				return "handler url not realized - please check"
			}
			return strings.Join(base, "/")
		},
	}

	t, err := template.
		New(filepath.Base(tpl.files[0])).
		Funcs(funcmap).
		ParseFiles(tpl.files...)

	// panic if template breaks in parse
	if err != nil {
		panic(err)
	}

	err = t.Execute(w, ctx)
	// return error there !
	return err
}

// SetTemplateOptions set needed options to template engine. For BuiltInTemplate
// there are no option at this time.
func (tpl *BuiltInTemplate) SetTemplateOptions(TplOptions) {}

// parseOverride will append overriden templates to be integrating in the
// template list to render
func (tpl *BuiltInTemplate) parseOverride(content []byte) {

	re := regexp.MustCompile(`\{\{/\*\s*override\s*\"?(.*?)\"?\s*\*/\}\}`)
	matches := re.FindAllSubmatch(content, -1)

	for _, m := range matches {
		// find bottom templates
		tplfile := filepath.Join(tpl.tpldir, string(m[1]))
		c, _ := ioutil.ReadFile(tplfile)
		tpl.parseOverride(c)

		tpl.files = append(tpl.files, tplfile)
	}
}
<commit_msg>Add template options to add functions<commit_after>package kwiscale

import (
	"fmt"
	"html/template"
	"io"
	"io/ioutil"
	"path/filepath"
	"reflect"
	"regexp"
	"strings"
)

var templateEngine = make(map[string]reflect.Type)

// TplOptions are template options to pass to template engines if needed
type TplOptions map[string]interface{}

// RegisterTemplateEngine records template engine that implements Template
// interface. The name is used to let config select the template engine.
func RegisterTemplateEngine(name string, tpl Template) {
	templateEngine[name] = reflect.ValueOf(tpl).Elem().Type()
}

// register basic template engine by default.
func init() {
	RegisterTemplateEngine("basic", &BuiltInTemplate{})
}

// Template should be implemented by other template implementation to
// allow RequestHandlers to use Render() method
type Template interface {
	// Render method to implement to compile and run template
	// then write to RequestHandler "w" that is a io.Writer.
	Render(w io.Writer, template string, ctx interface{}) error

	// SetTemplateDir should set the template base directory
	SetTemplateDir(string)

	// SetOptions pass TplOptions to template engine
	SetTemplateOptions(TplOptions)
}

// BuiltInTemplate is Basic template engine that use html/template.
type BuiltInTemplate struct {
	files   []string
	tpldir  string
	funcMap template.FuncMap
}

// SetTemplateDir set the directory where are found templates.
func (tpl *BuiltInTemplate) SetTemplateDir(path string) {
	t, err := filepath.Abs(path)

	if err != nil {
		panic(err)
	}
	tpl.tpldir = t
	Log("Template dir set to ", tpl.tpldir)
}

// Render method for the basic Template system.
// Allow {{/* override "path.html" */}}, no cache, very basic.
func (tpl *BuiltInTemplate) Render(w io.Writer, file string, ctx interface{}) error {
	var err error
	defer func() {
		if err != nil {
			Error(err)
		}
	}()

	file = filepath.Join(tpl.tpldir, file)

	tpl.files = make([]string, 0)
	content, err := ioutil.ReadFile(file)

	// panic if read file breaks
	if err != nil {
		panic(err)
	}

	tpl.parseOverride(content)

	tpl.files = append(tpl.files, file)

	Log(tpl.files)

	funcmap := template.FuncMap{
		"static": func(file string) string {
			app := w.(WebHandler).App()
			url, err := app.GetRoute("statics").URL("file", file)
			if err != nil {
				return err.Error()
			}
			return url.String()
		},
		"url": func(handler string, args ...interface{}) string {
			pairs := []string{}
			for _, p := range args {
				pairs = append(pairs, fmt.Sprintf("%v", p))
			}
			h := w.(WebHandler).App().GetRoutes(handler)
			base := []string{}
			for _, r := range h {
				url, err := r.URL(pairs...)
				if err != nil {
					continue
				}
				route := strings.Split(url.String(), "/")
				if len(route) >= len(base) {
					base = route
				}
			}
			if len(base) == 0 {
				return "handler url not realized - please check"
			}
			return strings.Join(base, "/")
		},
	}

	t, err := template.
		New(filepath.Base(tpl.files[0])).
		Funcs(funcmap).
		ParseFiles(tpl.files...)

	// panic if template breaks in parse
	if err != nil {
		panic(err)
	}

	err = t.Execute(w, ctx)
	// return error there !
	return err
}

// SetTemplateOptions set needed options to template engine. For BuiltInTemplate
// there are no option at this time.
func (tpl *BuiltInTemplate) SetTemplateOptions(opts TplOptions) {
	if m, ok := opts["funcs"]; ok {
		for name, fn := range m.(template.FuncMap) {
			tpl.funcMap[name] = fn
		}
	}
}

// parseOverride will append overriden templates to be integrating in the
// template list to render
func (tpl *BuiltInTemplate) parseOverride(content []byte) {

	re := regexp.MustCompile(`\{\{/\*\s*override\s*\"?(.*?)\"?\s*\*/\}\}`)
	matches := re.FindAllSubmatch(content, -1)

	for _, m := range matches {
		// find bottom templates
		tplfile := filepath.Join(tpl.tpldir, string(m[1]))
		c, _ := ioutil.ReadFile(tplfile)
		tpl.parseOverride(c)

		tpl.files = append(tpl.files, tplfile)
	}
}
<|endoftext|>


<commit_before>// Copyright © 2015 Victor Antonovich <victor@antonovich.me>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"bytes"
	"io/ioutil"
	"path/filepath"
	"text/template"

	"fmt"
	"k8s.io/kubernetes/pkg/api"
)

const (
	DEFAULT_NAMESPACE = api.NamespaceDefault
	DEFAULT_SELECTOR  = ""
)

type Template struct {
	// Template descriptor from configuration
	desc *TemplateDescriptor

	// Template name (base file name)
	name string

	// Template last output (in case of successfully rendered template)
	lastOutput string
}

func newTemplate(d *TemplateDescriptor) *Template {
	// Get last template output, if present
	o, err := ioutil.ReadFile(d.Output)
	if err != nil {
		o = nil
	}
	// Create template
	return &Template{
		desc:       d,
		name:       filepath.Base(d.Path),
		lastOutput: string(o),
	}
}

func (t *Template) Process(c *Client, dryRun bool) (bool, error) {
	if r, err := t.Render(c); err == nil {
		if changed := !(r == t.lastOutput); changed {
			// Template output changed
			if !dryRun {
				// TODO file mode from config
				// TODO atomic write
				if err := ioutil.WriteFile(t.desc.Output, []byte(r), 0644); err != nil {
					return false, err
				}
			}
			t.lastOutput = r
			return true, nil
		}
		// Template output not changed
		return false, nil
	} else {
		// Can't render template
		return false, err
	}
}

func (t *Template) Render(c *Client) (string, error) {
	// Read template data
	data, err := ioutil.ReadFile(t.desc.Path)
	if err != nil {
		return "", err
	}
	s := string(data)
	// Create template from read data
	template, err := template.New(t.name).Funcs(funcMap(c)).Parse(s)
	if err != nil {
		return "", err
	}
	// Render template to buffer
	buf := new(bytes.Buffer)
	if err := template.Execute(buf, nil); err != nil {
		return "", err
	}

	return buf.String(), nil
}

func funcMap(c *Client) template.FuncMap {
	return template.FuncMap{
		"pods":     pods(c),
		"services": services(c),
	}
}

// {{pods "selector" "namespace"}}
func pods(c *Client) func(...string) ([]api.Pod, error) {
	return func(s ...string) ([]api.Pod, error) {
		namespace, selector := DEFAULT_NAMESPACE, DEFAULT_SELECTOR
		switch len(s) {
		case 0:
			break
		case 1:
			selector = s[0]
		case 2:
			selector = s[0]
			namespace = s[1]
		default:
			return nil, fmt.Errorf("expected max 2 arguments, got %d", len(s))
		}
		pods, err := c.Pods(namespace, selector)
		if err != nil {
			return nil, err
		}
		return pods, nil
	}
}

// {{services "selector" "namespace"}}
func services(c *Client) func(...string) ([]api.Service, error) {
	return func(s ...string) ([]api.Service, error) {
		namespace, selector := DEFAULT_NAMESPACE, DEFAULT_SELECTOR
		switch len(s) {
		case 0:
			break
		case 1:
			selector = s[0]
		case 2:
			selector = s[0]
			namespace = s[1]
		default:
			return nil, fmt.Errorf("expected max 2 arguments, got %d", len(s))
		}
		services, err := c.Services(namespace, selector)
		if err != nil {
			return nil, err
		}
		return services, nil
	}
}
<commit_msg>Added add/sub template functions<commit_after>// Copyright © 2015 Victor Antonovich <victor@antonovich.me>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"bytes"
	"io/ioutil"
	"path/filepath"
	"text/template"

	"fmt"
	"k8s.io/kubernetes/pkg/api"
)

const (
	DEFAULT_NAMESPACE = api.NamespaceDefault
	DEFAULT_SELECTOR  = ""
)

type Template struct {
	// Template descriptor from configuration
	desc *TemplateDescriptor

	// Template name (base file name)
	name string

	// Template last output (in case of successfully rendered template)
	lastOutput string
}

func newTemplate(d *TemplateDescriptor) *Template {
	// Get last template output, if present
	o, err := ioutil.ReadFile(d.Output)
	if err != nil {
		o = nil
	}
	// Create template
	return &Template{
		desc:       d,
		name:       filepath.Base(d.Path),
		lastOutput: string(o),
	}
}

func (t *Template) Process(c *Client, dryRun bool) (bool, error) {
	if r, err := t.Render(c); err == nil {
		if changed := !(r == t.lastOutput); changed {
			// Template output changed
			if !dryRun {
				// TODO file mode from config
				// TODO atomic write
				if err := ioutil.WriteFile(t.desc.Output, []byte(r), 0644); err != nil {
					return false, err
				}
			}
			t.lastOutput = r
			return true, nil
		}
		// Template output not changed
		return false, nil
	} else {
		// Can't render template
		return false, err
	}
}

func (t *Template) Render(c *Client) (string, error) {
	// Read template data
	data, err := ioutil.ReadFile(t.desc.Path)
	if err != nil {
		return "", err
	}
	s := string(data)
	// Create template from read data
	template, err := template.New(t.name).Funcs(funcMap(c)).Parse(s)
	if err != nil {
		return "", err
	}
	// Render template to buffer
	buf := new(bytes.Buffer)
	if err := template.Execute(buf, nil); err != nil {
		return "", err
	}

	return buf.String(), nil
}

func funcMap(c *Client) template.FuncMap {
	return template.FuncMap{
		// Kubernetes objects
		"pods":     pods(c),
		"services": services(c),
		// Utils
		"add": add,
		"sub": sub,
	}
}

// {{pods "selector" "namespace"}}
func pods(c *Client) func(...string) ([]api.Pod, error) {
	return func(s ...string) ([]api.Pod, error) {
		namespace, selector := DEFAULT_NAMESPACE, DEFAULT_SELECTOR
		switch len(s) {
		case 0:
			break
		case 1:
			selector = s[0]
		case 2:
			selector = s[0]
			namespace = s[1]
		default:
			return nil, fmt.Errorf("expected max 2 arguments, got %d", len(s))
		}
		pods, err := c.Pods(namespace, selector)
		if err != nil {
			return nil, err
		}
		return pods, nil
	}
}

// {{services "selector" "namespace"}}
func services(c *Client) func(...string) ([]api.Service, error) {
	return func(s ...string) ([]api.Service, error) {
		namespace, selector := DEFAULT_NAMESPACE, DEFAULT_SELECTOR
		switch len(s) {
		case 0:
			break
		case 1:
			selector = s[0]
		case 2:
			selector = s[0]
			namespace = s[1]
		default:
			return nil, fmt.Errorf("expected max 2 arguments, got %d", len(s))
		}
		services, err := c.Services(namespace, selector)
		if err != nil {
			return nil, err
		}
		return services, nil
	}
}

// {{add a b}}
func add(a, b int) int {
	return a + b
}

// {{sub a b}}
func sub(a, b int) int {
	return a - b
}
<|endoftext|>


<commit_before>// Copyright 2016, Cossack Labs Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package postgresql

import (
	"bytes"
	"encoding/binary"
	. "github.com/cossacklabs/acra/utils"
	"io"
	"log"
	"strconv"

	"fmt"
	"github.com/cossacklabs/acra/decryptor/base"
	"github.com/cossacklabs/acra/keystore"
	"github.com/cossacklabs/acra/zone"
	"github.com/cossacklabs/themis/gothemis/cell"
	"github.com/cossacklabs/themis/gothemis/keys"
	"github.com/cossacklabs/themis/gothemis/message"
)

var ESCAPE_TAG_BEGIN = EncodeToOctal(base.TAG_BEGIN)

var ESCAPE_ZONE_TAG_LENGTH = zone.ZONE_TAG_LENGTH
var ESCAPE_ZONE_ID_BLOCK_LENGTH = zone.ZONE_ID_BLOCK_LENGTH

func encodeToOctal(from, to []byte) {
	to = to[:0]
	for _, c := range from {
		if IsPrintableEscapeChar(c) {
			if c == SLASH_CHAR {
				to = append(to, []byte{SLASH_CHAR, SLASH_CHAR}...)
			} else {
				to = append(to, c)
			}
		} else {
			to = append(to, SLASH_CHAR)
			octal := strconv.FormatInt(int64(c), 8)
			switch len(octal) {
			case 3:
				to = append(to, []byte(octal)...)
			case 2:
				to = append(to, '0', octal[0], octal[1])

			case 1:
				to = append(to, '0', '0', octal[0])
			}
		}
	}
}

func EncodeToOctal(from []byte) []byte {
	// count output size
	output_length := 0
	for _, c := range from {
		if IsPrintableEscapeChar(c) {
			if c == SLASH_CHAR {
				output_length += 2
			} else {
				output_length++
			}
		} else {
			output_length += 4
		}
	}
	buffer := make([]byte, output_length)
	encodeToOctal(from, buffer)
	return buffer
}

type PgEscapeDecryptor struct {
	current_index    uint8
	output_size      int
	is_with_zone     bool
	poison_key       []byte
	callback_storage *base.PoisonCallbackStorage
	// max size can be 4 characters for octal representation per byte
	oct_key_block_buffer     [base.KEY_BLOCK_LENGTH * 4]byte
	decoded_key_block_buffer []byte
	//uint64
	length_buf [8]byte
	// 4 oct symbols (\000) ber byte
	oct_length_buf [8 * 4]byte
	oct_char_buf   [3]byte
	key_store      keystore.KeyStore
	zone_matcher   *zone.ZoneIdMatcher
}

func NewPgEscapeDecryptor() *PgEscapeDecryptor {
	return &PgEscapeDecryptor{
		current_index:            0,
		is_with_zone:             false,
		output_size:              0,
		decoded_key_block_buffer: make([]byte, base.KEY_BLOCK_LENGTH),
	}
}

func (decryptor *PgEscapeDecryptor) SetWithZone(b bool) {
	decryptor.is_with_zone = b
}

func (decryptor *PgEscapeDecryptor) SetPoisonKey(key []byte) {
	decryptor.poison_key = key
}

func (decryptor *PgEscapeDecryptor) GetPoisonKey() []byte {
	return decryptor.poison_key
}

func (decryptor *PgEscapeDecryptor) MatchBeginTag(char byte) bool {
	if char == ESCAPE_TAG_BEGIN[decryptor.current_index] {
		decryptor.current_index++
		decryptor.output_size++
		return true
	} else {
		return false
	}

}
func (decryptor *PgEscapeDecryptor) IsMatched() bool {
	return int(decryptor.current_index) == len(ESCAPE_TAG_BEGIN)
}
func (decryptor *PgEscapeDecryptor) Reset() {
	decryptor.current_index = 0
	decryptor.output_size = 0
}
func (decryptor *PgEscapeDecryptor) GetMatched() []byte {
	return ESCAPE_TAG_BEGIN[:decryptor.current_index]
}

func (decryptor *PgEscapeDecryptor) readOctalData(data, oct_data []byte, reader io.Reader) (int, int, error) {
	data_index := 0
	oct_data_index := 0
	var char_buf [1]byte
	for {
		n, err := reader.Read(char_buf[:])
		if err != nil {
			return data_index, oct_data_index, err
		}
		if n != 1 {
			log.Println("Debug: readOctalData read 0 bytes")
			return data_index, oct_data_index, base.ErrFakeAcraStruct
		}
		oct_data[oct_data_index] = char_buf[0]
		oct_data_index++
		if !IsPrintableEscapeChar(char_buf[0]) {
			return data_index, oct_data_index, base.ErrFakeAcraStruct
		}

		// if slash than next char must be slash too
		if char_buf[0] == SLASH_CHAR {
			// read next char
			_, err := reader.Read(char_buf[:])
			if err != nil {
				return data_index, oct_data_index, err
			}
			oct_data[oct_data_index] = char_buf[0]
			oct_data_index++
			if char_buf[0] == SLASH_CHAR {
				// just write slash char
				data[data_index] = char_buf[0]
				data_index++
			} else {
				decryptor.oct_char_buf[0] = char_buf[0]
				// read next 3 oct bytes
				n, err := io.ReadFull(reader, decryptor.oct_char_buf[1:])
				if err != nil {
					return data_index, oct_data_index, err
				}
				if n != len(decryptor.oct_char_buf)-1 {
					if n != 0 {
						copy(oct_data[oct_data_index:oct_data_index+n], decryptor.oct_char_buf[1:1+n])
						oct_data_index += n
					}
					log.Printf("Warning: expected 2 octal symbols, but read %v\n", n)
					return data_index, oct_data_index, base.ErrFakeAcraStruct
				}
				// parse 3 octal symbols
				num, err := strconv.ParseInt(string(decryptor.oct_char_buf[:]), 8, 9)
				if err != nil {
					return data_index, oct_data_index, base.ErrFakeAcraStruct
				}
				data[data_index] = byte(num)
				data_index++

				copy(oct_data[oct_data_index:oct_data_index+len(decryptor.oct_char_buf)-1], decryptor.oct_char_buf[1:])
				oct_data_index += 2
			}
		} else {
			// just write to data
			data[data_index] = char_buf[0]
			data_index++
		}
		if data_index == cap(data) {
			return data_index, oct_data_index, nil
		}
	}
}
func (decryptor *PgEscapeDecryptor) ReadSymmetricKey(private_key *keys.PrivateKey, reader io.Reader) ([]byte, []byte, error) {
	data_length, oct_data_length, err := decryptor.readOctalData(decryptor.decoded_key_block_buffer, decryptor.oct_key_block_buffer[:], reader)
	if err != nil {
		return nil, decryptor.oct_key_block_buffer[:oct_data_length], err
	}
	if len(decryptor.decoded_key_block_buffer) != base.KEY_BLOCK_LENGTH || data_length != base.KEY_BLOCK_LENGTH {
		return nil, decryptor.oct_key_block_buffer[:oct_data_length], base.ErrFakeAcraStruct
	}
	smessage := message.New(private_key, &keys.PublicKey{Value: decryptor.decoded_key_block_buffer[:base.PUBLIC_KEY_LENGTH]})
	symmetric_key, err := smessage.Unwrap(decryptor.decoded_key_block_buffer[base.PUBLIC_KEY_LENGTH:])
	if err != nil {
		log.Printf("Warning: %v\n", ErrorMessage("can't unwrap symmetric key", err))
		return nil, decryptor.oct_key_block_buffer[:oct_data_length], base.ErrFakeAcraStruct
	}
	decryptor.output_size += oct_data_length
	return symmetric_key, decryptor.oct_key_block_buffer[:oct_data_length], nil
}

func (decryptor *PgEscapeDecryptor) readDataLength(reader io.Reader) (uint64, []byte, error) {
	var length uint64

	len_count, oct_len_count, err := decryptor.readOctalData(decryptor.length_buf[:], decryptor.oct_length_buf[:], reader)
	if err != nil {
		log.Printf("Warning: %v\n", ErrorMessage("can't read data length", err))
		return 0, decryptor.oct_length_buf[:oct_len_count], err
	}
	if len_count != len(decryptor.length_buf) {
		log.Printf("Warning: incorrect length count, %v!=%v\n", len_count, len(decryptor.length_buf))
		return 0, decryptor.oct_length_buf[:oct_len_count], base.ErrFakeAcraStruct
	}
	decryptor.output_size += oct_len_count
	binary.Read(bytes.NewBuffer(decryptor.length_buf[:]), binary.LittleEndian, &length)
	return length, decryptor.oct_length_buf[:oct_len_count], nil
}
func (decryptor *PgEscapeDecryptor) readScellData(length uint64, reader io.Reader) ([]byte, []byte, error) {
	hex_buf := make([]byte, int(length)*4)
	buf := make([]byte, int(length))
	n, oct_n, err := decryptor.readOctalData(buf, hex_buf, reader)
	if err != nil {
		log.Printf("Warning: %v\n", ErrorMessage(fmt.Sprintf("can't read scell data with passed length=%v", length), err))
		return nil, hex_buf[:oct_n], err
	}
	if n != int(length) {
		log.Printf("Warning: read incorrect length, %v!=%v\n", n, length)
		return nil, hex_buf[:oct_n], base.ErrFakeAcraStruct
	}
	decryptor.output_size += oct_n
	return buf, hex_buf[:oct_n], nil
}

func (decryptor *PgEscapeDecryptor) getFullDataLength() int {
	return decryptor.output_size
}

func (decryptor *PgEscapeDecryptor) ReadData(symmetric_key, zone_id []byte, reader io.Reader) ([]byte, error) {
	length, hex_length_buf, err := decryptor.readDataLength(reader)
	if err != nil {
		return hex_length_buf, err
	}
	data, oct_data, err := decryptor.readScellData(length, reader)
	if err != nil {
		return append(hex_length_buf, oct_data...), err
	}

	scell := cell.New(symmetric_key, cell.CELL_MODE_SEAL)
	decrypted, err := scell.Unprotect(data, nil, zone_id)
	// fill zero symmetric_key
	FillSlice(byte(0), symmetric_key[:])
	if err != nil {
		return append(hex_length_buf, oct_data...), base.ErrFakeAcraStruct
	}
	return EncodeToOctal(decrypted), nil
}

func (decryptor *PgEscapeDecryptor) SetKeyStore(store keystore.KeyStore) {
	decryptor.key_store = store
}

func (decryptor *PgEscapeDecryptor) GetPrivateKey() (*keys.PrivateKey, error) {
	return decryptor.key_store.GetZonePrivateKey(decryptor.GetMatchedZoneId())
}

func (decryptor *PgEscapeDecryptor) SetZoneMatcher(zone_matcher *zone.ZoneIdMatcher) {
	decryptor.zone_matcher = zone_matcher
}

func (decryptor *PgEscapeDecryptor) MatchZone(c byte) bool {
	return decryptor.zone_matcher.Match(c)
}

func (decryptor *PgEscapeDecryptor) IsWithZone() bool {
	return decryptor.is_with_zone
}

func (decryptor *PgEscapeDecryptor) IsMatchedZone() bool {
	return decryptor.zone_matcher.IsMatched()
}

func (decryptor *PgEscapeDecryptor) ResetZoneMatch() {
	decryptor.zone_matcher.Reset()
}

func (decryptor *PgEscapeDecryptor) GetMatchedZoneId() []byte {
	if decryptor.IsWithZone() {
		return decryptor.zone_matcher.GetZoneId()
	} else {
		return nil
	}
}

func (decryptor *PgEscapeDecryptor) SetPoisonCallbackStorage(storage *base.PoisonCallbackStorage) {
	decryptor.callback_storage = storage
}

func (decryptor *PgEscapeDecryptor) GetPoisonCallbackStorage() *base.PoisonCallbackStorage {
	return decryptor.callback_storage
}

func (decryptor *PgEscapeDecryptor) GetTagBeginLength() int {
	return len(ESCAPE_TAG_BEGIN)
}
<commit_msg>clean pg_escape_decryptor from old code<commit_after>// Copyright 2016, Cossack Labs Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package postgresql

import (
	"bytes"
	"encoding/binary"
	. "github.com/cossacklabs/acra/utils"
	"io"
	"log"
	"strconv"

	"fmt"
	"github.com/cossacklabs/acra/decryptor/base"
	"github.com/cossacklabs/acra/keystore"
	"github.com/cossacklabs/acra/zone"
	"github.com/cossacklabs/themis/gothemis/cell"
	"github.com/cossacklabs/themis/gothemis/keys"
	"github.com/cossacklabs/themis/gothemis/message"
)

var ESCAPE_TAG_BEGIN = EncodeToOctal(base.TAG_BEGIN)

var ESCAPE_ZONE_TAG_LENGTH = zone.ZONE_TAG_LENGTH
var ESCAPE_ZONE_ID_BLOCK_LENGTH = zone.ZONE_ID_BLOCK_LENGTH

func encodeToOctal(from, to []byte) {
	to = to[:0]
	for _, c := range from {
		if IsPrintableEscapeChar(c) {
			if c == SLASH_CHAR {
				to = append(to, []byte{SLASH_CHAR, SLASH_CHAR}...)
			} else {
				to = append(to, c)
			}
		} else {
			to = append(to, SLASH_CHAR)
			octal := strconv.FormatInt(int64(c), 8)
			switch len(octal) {
			case 3:
				to = append(to, []byte(octal)...)
			case 2:
				to = append(to, '0', octal[0], octal[1])

			case 1:
				to = append(to, '0', '0', octal[0])
			}
		}
	}
}

func EncodeToOctal(from []byte) []byte {
	// count output size
	output_length := 0
	for _, c := range from {
		if IsPrintableEscapeChar(c) {
			if c == SLASH_CHAR {
				output_length += 2
			} else {
				output_length++
			}
		} else {
			output_length += 4
		}
	}
	buffer := make([]byte, output_length)
	encodeToOctal(from, buffer)
	return buffer
}

type PgEscapeDecryptor struct {
	current_index    uint8
	output_size      int
	is_with_zone     bool
	poison_key       []byte
	callback_storage *base.PoisonCallbackStorage
	// max size can be 4 characters for octal representation per byte
	oct_key_block_buffer     [base.KEY_BLOCK_LENGTH * 4]byte
	decoded_key_block_buffer []byte
	//uint64
	length_buf [8]byte
	// 4 oct symbols (\000) ber byte
	oct_length_buf [8 * 4]byte
	oct_char_buf   [3]byte
	key_store      keystore.KeyStore
	zone_matcher   *zone.ZoneIdMatcher
}

func NewPgEscapeDecryptor() *PgEscapeDecryptor {
	return &PgEscapeDecryptor{
		current_index:            0,
		is_with_zone:             false,
		output_size:              0,
		decoded_key_block_buffer: make([]byte, base.KEY_BLOCK_LENGTH),
	}
}

func (decryptor *PgEscapeDecryptor) MatchBeginTag(char byte) bool {
	if char == ESCAPE_TAG_BEGIN[decryptor.current_index] {
		decryptor.current_index++
		decryptor.output_size++
		return true
	} else {
		return false
	}

}
func (decryptor *PgEscapeDecryptor) IsMatched() bool {
	return int(decryptor.current_index) == len(ESCAPE_TAG_BEGIN)
}
func (decryptor *PgEscapeDecryptor) Reset() {
	decryptor.current_index = 0
	decryptor.output_size = 0
}
func (decryptor *PgEscapeDecryptor) GetMatched() []byte {
	return ESCAPE_TAG_BEGIN[:decryptor.current_index]
}

func (decryptor *PgEscapeDecryptor) readOctalData(data, oct_data []byte, reader io.Reader) (int, int, error) {
	data_index := 0
	oct_data_index := 0
	var char_buf [1]byte
	for {
		n, err := reader.Read(char_buf[:])
		if err != nil {
			return data_index, oct_data_index, err
		}
		if n != 1 {
			log.Println("Debug: readOctalData read 0 bytes")
			return data_index, oct_data_index, base.ErrFakeAcraStruct
		}
		oct_data[oct_data_index] = char_buf[0]
		oct_data_index++
		if !IsPrintableEscapeChar(char_buf[0]) {
			return data_index, oct_data_index, base.ErrFakeAcraStruct
		}

		// if slash than next char must be slash too
		if char_buf[0] == SLASH_CHAR {
			// read next char
			_, err := reader.Read(char_buf[:])
			if err != nil {
				return data_index, oct_data_index, err
			}
			oct_data[oct_data_index] = char_buf[0]
			oct_data_index++
			if char_buf[0] == SLASH_CHAR {
				// just write slash char
				data[data_index] = char_buf[0]
				data_index++
			} else {
				decryptor.oct_char_buf[0] = char_buf[0]
				// read next 3 oct bytes
				n, err := io.ReadFull(reader, decryptor.oct_char_buf[1:])
				if err != nil {
					return data_index, oct_data_index, err
				}
				if n != len(decryptor.oct_char_buf)-1 {
					if n != 0 {
						copy(oct_data[oct_data_index:oct_data_index+n], decryptor.oct_char_buf[1:1+n])
						oct_data_index += n
					}
					log.Printf("Warning: expected 2 octal symbols, but read %v\n", n)
					return data_index, oct_data_index, base.ErrFakeAcraStruct
				}
				// parse 3 octal symbols
				num, err := strconv.ParseInt(string(decryptor.oct_char_buf[:]), 8, 9)
				if err != nil {
					return data_index, oct_data_index, base.ErrFakeAcraStruct
				}
				data[data_index] = byte(num)
				data_index++

				copy(oct_data[oct_data_index:oct_data_index+len(decryptor.oct_char_buf)-1], decryptor.oct_char_buf[1:])
				oct_data_index += 2
			}
		} else {
			// just write to data
			data[data_index] = char_buf[0]
			data_index++
		}
		if data_index == cap(data) {
			return data_index, oct_data_index, nil
		}
	}
}
func (decryptor *PgEscapeDecryptor) ReadSymmetricKey(private_key *keys.PrivateKey, reader io.Reader) ([]byte, []byte, error) {
	data_length, oct_data_length, err := decryptor.readOctalData(decryptor.decoded_key_block_buffer, decryptor.oct_key_block_buffer[:], reader)
	if err != nil {
		return nil, decryptor.oct_key_block_buffer[:oct_data_length], err
	}
	if len(decryptor.decoded_key_block_buffer) != base.KEY_BLOCK_LENGTH || data_length != base.KEY_BLOCK_LENGTH {
		return nil, decryptor.oct_key_block_buffer[:oct_data_length], base.ErrFakeAcraStruct
	}
	smessage := message.New(private_key, &keys.PublicKey{Value: decryptor.decoded_key_block_buffer[:base.PUBLIC_KEY_LENGTH]})
	symmetric_key, err := smessage.Unwrap(decryptor.decoded_key_block_buffer[base.PUBLIC_KEY_LENGTH:])
	if err != nil {
		log.Printf("Warning: %v\n", ErrorMessage("can't unwrap symmetric key", err))
		return nil, decryptor.oct_key_block_buffer[:oct_data_length], base.ErrFakeAcraStruct
	}
	decryptor.output_size += oct_data_length
	return symmetric_key, decryptor.oct_key_block_buffer[:oct_data_length], nil
}

func (decryptor *PgEscapeDecryptor) readDataLength(reader io.Reader) (uint64, []byte, error) {
	var length uint64

	len_count, oct_len_count, err := decryptor.readOctalData(decryptor.length_buf[:], decryptor.oct_length_buf[:], reader)
	if err != nil {
		log.Printf("Warning: %v\n", ErrorMessage("can't read data length", err))
		return 0, decryptor.oct_length_buf[:oct_len_count], err
	}
	if len_count != len(decryptor.length_buf) {
		log.Printf("Warning: incorrect length count, %v!=%v\n", len_count, len(decryptor.length_buf))
		return 0, decryptor.oct_length_buf[:oct_len_count], base.ErrFakeAcraStruct
	}
	decryptor.output_size += oct_len_count
	binary.Read(bytes.NewBuffer(decryptor.length_buf[:]), binary.LittleEndian, &length)
	return length, decryptor.oct_length_buf[:oct_len_count], nil
}
func (decryptor *PgEscapeDecryptor) readScellData(length uint64, reader io.Reader) ([]byte, []byte, error) {
	hex_buf := make([]byte, int(length)*4)
	buf := make([]byte, int(length))
	n, oct_n, err := decryptor.readOctalData(buf, hex_buf, reader)
	if err != nil {
		log.Printf("Warning: %v\n", ErrorMessage(fmt.Sprintf("can't read scell data with passed length=%v", length), err))
		return nil, hex_buf[:oct_n], err
	}
	if n != int(length) {
		log.Printf("Warning: read incorrect length, %v!=%v\n", n, length)
		return nil, hex_buf[:oct_n], base.ErrFakeAcraStruct
	}
	decryptor.output_size += oct_n
	return buf, hex_buf[:oct_n], nil
}

func (decryptor *PgEscapeDecryptor) getFullDataLength() int {
	return decryptor.output_size
}

func (decryptor *PgEscapeDecryptor) ReadData(symmetric_key, zone_id []byte, reader io.Reader) ([]byte, error) {
	length, hex_length_buf, err := decryptor.readDataLength(reader)
	if err != nil {
		return hex_length_buf, err
	}
	data, oct_data, err := decryptor.readScellData(length, reader)
	if err != nil {
		return append(hex_length_buf, oct_data...), err
	}

	scell := cell.New(symmetric_key, cell.CELL_MODE_SEAL)
	decrypted, err := scell.Unprotect(data, nil, zone_id)
	// fill zero symmetric_key
	FillSlice(byte(0), symmetric_key[:])
	if err != nil {
		return append(hex_length_buf, oct_data...), base.ErrFakeAcraStruct
	}
	return EncodeToOctal(decrypted), nil
}

func (decryptor *PgEscapeDecryptor) GetTagBeginLength() int {
	return len(ESCAPE_TAG_BEGIN)
}
<|endoftext|>


<commit_before>package dal

import (
	"bytes"
	"encoding/xml"
	"fmt"
	log "github.com/Sirupsen/logrus"
	"github.com/libvirt/libvirt-go"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"text/template"
	"vmango/models"
)

type LibvirtMachinerep struct {
	conn  *libvirt.Connect
	vmtpl *template.Template
}

type diskSourceXMLConfig struct {
	File string `xml:"file,attr"`
}

type diskTargetXMLConfig struct {
	Device string `xml:"dev,attr"`
	Bus    string `xml:"bus,attr"`
}

type diskDriverXMLConfig struct {
	Name  string `xml:"name,attr"`
	Type  string `xml:"type,attr"`
	Cache string `xml:"cache,attr"`
}

type diskXMLConfig struct {
	Driver diskDriverXMLConfig `xml:"driver"`
	Target diskTargetXMLConfig `xml:"target"`
	Source diskSourceXMLConfig `xml:"source"`
}

type domainXMLConfig struct {
	XMLName xml.Name        `xml:"domain"`
	Name    string          `xml:"name"`
	Disks   []diskXMLConfig `xml:"devices>disk"`
}

func NewLibvirtMachinerep(conn *libvirt.Connect, tpl *template.Template) (*LibvirtMachinerep, error) {
	return &LibvirtMachinerep{conn: conn, vmtpl: tpl}, nil
}

func (store *LibvirtMachinerep) fillVm(vm *models.VirtualMachine, domain *libvirt.Domain) error {
	name, err := domain.GetName()
	if err != nil {
		return err
	}
	uuid, err := domain.GetUUID()
	if err != nil {
		return err
	}
	info, err := domain.GetInfo()
	if err != nil {
		return err
	}

	xmlString, err := domain.GetXMLDesc(0)
	if err != nil {
		return err
	}

	domainConfig := domainXMLConfig{}
	if err := xml.Unmarshal([]byte(xmlString), &domainConfig); err != nil {
		return fmt.Errorf("failed to parse domain xml:", err)
	}

	log.WithField("name", name).WithField("domain", domainConfig).Debug("domain xml fetched")

	switch info.State {
	default:
		vm.State = models.STATE_UNKNOWN
	case libvirt.DOMAIN_RUNNING:
		vm.State = models.STATE_RUNNING
	case libvirt.DOMAIN_SHUTDOWN:
		vm.State = models.STATE_STOPPED
	case libvirt.DOMAIN_SHUTOFF:
		vm.State = models.STATE_STOPPED

	}

	if len(domainConfig.Disks) > 0 {
		volume, err := store.conn.LookupStorageVolByPath(domainConfig.Disks[0].Source.File)
		if err != nil {
			return err
		}
		volumeInfo, err := volume.GetInfo()
		if err != nil {
			return err
		}
		vm.Disk = &models.VirtualMachineDisk{}
		vm.Disk.Driver = domainConfig.Disks[0].Driver.Name
		vm.Disk.Size = volumeInfo.Capacity
	} else {
		vm.Disk = nil
	}

	vm.Name = name
	vm.Uuid = fmt.Sprintf("%x", uuid)
	vm.Memory = int(info.Memory)
	vm.Cpus = int(info.NrVirtCpu)
	return nil
}

func (store *LibvirtMachinerep) List(machines *models.VirtualMachineList) error {
	domains, err := store.conn.ListAllDomains(0)
	if err != nil {
		return err
	}
	for _, domain := range domains {
		vm := &models.VirtualMachine{}
		if err := store.fillVm(vm, &domain); err != nil {
			return err
		}
		machines.Add(vm)
	}
	return nil
}

func (store *LibvirtMachinerep) Get(machine *models.VirtualMachine) (bool, error) {
	if machine.Name == "" {
		return false, nil
	}

	domain, err := store.conn.LookupDomainByName(machine.Name)
	if err != nil {
		virErr := err.(libvirt.Error)
		if virErr.Code == libvirt.ERR_NO_DOMAIN {
			return false, nil
		}
		return false, virErr
	}
	store.fillVm(machine, domain)
	return true, nil
}

func (store *LibvirtMachinerep) createConfigDrive(machine *models.VirtualMachine, pool *libvirt.StoragePool) (*libvirt.StorageVol, error) {
	tmpdir, err := ioutil.TempDir("", "")
	if err != nil {
		return nil, err
	}
	defer os.RemoveAll(tmpdir)
	metadataRoot := filepath.Join(tmpdir, "openstack", "latest")
	if err := os.MkdirAll(metadataRoot, 0755); err != nil {
		return nil, err
	}
	md, err := os.Create(filepath.Join(metadataRoot, "meta_data.json"))
	if err != nil {
		return nil, err
	}
	md.WriteString(fmt.Sprintf(`{
    "availability_zone": "none",
    "files": [
    ],
    "hostname": "%s",
    "launch_index": 0,
    "name": "%s",
    "meta": {
        "role": "webservers",
        "essential": "false"
    },
    "public_keys": {
        "mykey": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDAvKEhzpqnZ7ipUZkx43In/YoNuvG/HUqR0oCLk/Mil0R533TCDP9ZOiJOrWPhvQc3EOy6mJi5h9KBfxoGt0EbLkkL5Bq5Bb+NvbsxMXmNpgFkE6Yul+yJzRvzQJsvUk8B0vptDfQE2z3+LHkcN/WjMIVUhBC/hB+7d7THC2/TJ+o0CgCXXSkCJ3FqsjiZWEb77pLGnQUV5pp3n4tpR7Aoe9c1KZplXNt8hnWGUJN/gtLLmO6ouORnbRRE9yuPoLJz/r7GMmQQM9VOPyDBelpob4X7fiz0c5L+BCtvWjrZo7vVCFRcpVpBbNUiw5seK3qLUhaOVwL8GOfHTtsFpA7h kubuzzzz+book@gmail.com\n"
    },
    "uuid": "0cae2cdb-e041-4f26-835b-f9602df0edf3"}
    `, machine.Name, machine.Name))
	if err := md.Close(); err != nil {
		return nil, err
	}
	cmd := exec.Command(
		"mkisofs", "-R", "-V", "config-2", "-o",
		filepath.Join(tmpdir, "drive.iso"), tmpdir,
	)
	if err := cmd.Run(); err != nil {
		return nil, err
	}
	volumeXML := fmt.Sprintf(`
	<volume>
	  <target>
	  	<format type="raw" />
	  </target>
	  <name>%s_config.iso</name>
	  <capacity unit="b">1</capacity>
	</volume>`, machine.Name)
	volume, err := pool.StorageVolCreateXML(volumeXML, 0)
	if err != nil {
		return nil, err
	}
	content, err := os.Open(filepath.Join(tmpdir, "drive.iso"))
	if err != nil {
		return nil, err
	}
	contentSize, err := content.Seek(0, os.SEEK_END)
	if err != nil {
		return nil, err
	}
	_, err = content.Seek(0, os.SEEK_SET)
	if err != nil {
		return nil, err
	}

	stream, err := store.conn.NewStream(0)
	if err != nil {
		return nil, err
	}
	if err := volume.Upload(stream, 0, uint64(contentSize), 0); err != nil {
		return nil, err
	}
	stream.SendAll(func(stream *libvirt.Stream, n int) ([]byte, error) {
		buf := make([]byte, n)
		_, err := content.Read(buf)
		return buf, err
	})
	// if err := stream.Finish(); err != nil {
	// 	return nil, err
	// }
	return volume, nil
}

func (store *LibvirtMachinerep) Create(machine *models.VirtualMachine, image *models.Image, plan *models.Plan) error {
	storagePool, err := store.conn.LookupStoragePoolByName("default")
	if err != nil {
		return fmt.Errorf("failed to lookup vm storage pool: %s", err)
	}

	imagePool, err := store.conn.LookupStoragePoolByName(image.PoolName)
	if err != nil {
		return fmt.Errorf("failed to lookup image storage pool: %s", err)
	}

	volumeXML := fmt.Sprintf(`
	<volume>
	  <target>
	  	<format type="%s" />
	  </target>
	  <name>%s_disk.%s</name>
	  <capacity unit="G">%d</capacity>
	  <allocation unit="G">%d</allocation>
	</volume>
	`, image.TypeString(), machine.Name, image.TypeString(), plan.DiskSizeGigabytes(), plan.DiskSizeGigabytes())
	imageVolume, err := imagePool.LookupStorageVolByName(image.FullName)
	if err != nil {
		return fmt.Errorf("failed to lookup image volume: %s", err)
	}

	configDriveVolume, err := store.createConfigDrive(machine, storagePool)
	if err != nil {
		return fmt.Errorf("failed to create config drive: %s", err)
	}
	log.WithField("configdrive", configDriveVolume).Debug("config drive created successfully")
	configDrivePath, err := configDriveVolume.GetPath()
	if err != nil {
		return err
	}

	rootVolume, err := storagePool.StorageVolCreateXMLFrom(volumeXML, imageVolume, 0)
	if err != nil {
		configDriveVolume.Delete(0)
		return fmt.Errorf("failed to clone image: %s", err)
	}
	rootVolumePath, err := rootVolume.GetPath()
	if err != nil {
		return fmt.Errorf("failed to get machine volume path: %s", err)
	}
	var machineXml bytes.Buffer
	vmtplContext := struct {
		Machine     *models.VirtualMachine
		Image       *models.Image
		Plan        *models.Plan
		VolumePath  string
		ConfigDrive string
	}{machine, image, plan, rootVolumePath, configDrivePath}
	if err := store.vmtpl.Execute(&machineXml, vmtplContext); err != nil {
		configDriveVolume.Delete(0)
		return err
	}
	log.WithField("xml", machineXml.String()).Debug("defining domain from xml")
	domain, err := store.conn.DomainDefineXML(machineXml.String())
	if err != nil {
		return err
	}
	store.fillVm(machine, domain)
	return nil
}

func (store *LibvirtMachinerep) Start(machine *models.VirtualMachine) error {
	domain, err := store.conn.LookupDomainByName(machine.Name)
	if err != nil {
		return err
	}
	return domain.Create()
}
<commit_msg>Resize machine root volume during creation<commit_after>package dal

import (
	"bytes"
	"encoding/xml"
	"fmt"
	log "github.com/Sirupsen/logrus"
	"github.com/libvirt/libvirt-go"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"text/template"
	"vmango/models"
)

type LibvirtMachinerep struct {
	conn  *libvirt.Connect
	vmtpl *template.Template
}

type diskSourceXMLConfig struct {
	File string `xml:"file,attr"`
}

type diskTargetXMLConfig struct {
	Device string `xml:"dev,attr"`
	Bus    string `xml:"bus,attr"`
}

type diskDriverXMLConfig struct {
	Name  string `xml:"name,attr"`
	Type  string `xml:"type,attr"`
	Cache string `xml:"cache,attr"`
}

type diskXMLConfig struct {
	Driver diskDriverXMLConfig `xml:"driver"`
	Target diskTargetXMLConfig `xml:"target"`
	Source diskSourceXMLConfig `xml:"source"`
}

type domainXMLConfig struct {
	XMLName xml.Name        `xml:"domain"`
	Name    string          `xml:"name"`
	Disks   []diskXMLConfig `xml:"devices>disk"`
}

func NewLibvirtMachinerep(conn *libvirt.Connect, tpl *template.Template) (*LibvirtMachinerep, error) {
	return &LibvirtMachinerep{conn: conn, vmtpl: tpl}, nil
}

func (store *LibvirtMachinerep) fillVm(vm *models.VirtualMachine, domain *libvirt.Domain) error {
	name, err := domain.GetName()
	if err != nil {
		return err
	}
	uuid, err := domain.GetUUID()
	if err != nil {
		return err
	}
	info, err := domain.GetInfo()
	if err != nil {
		return err
	}

	xmlString, err := domain.GetXMLDesc(0)
	if err != nil {
		return err
	}

	domainConfig := domainXMLConfig{}
	if err := xml.Unmarshal([]byte(xmlString), &domainConfig); err != nil {
		return fmt.Errorf("failed to parse domain xml:", err)
	}

	log.WithField("name", name).WithField("domain", domainConfig).Debug("domain xml fetched")

	switch info.State {
	default:
		vm.State = models.STATE_UNKNOWN
	case libvirt.DOMAIN_RUNNING:
		vm.State = models.STATE_RUNNING
	case libvirt.DOMAIN_SHUTDOWN:
		vm.State = models.STATE_STOPPED
	case libvirt.DOMAIN_SHUTOFF:
		vm.State = models.STATE_STOPPED

	}

	if len(domainConfig.Disks) > 0 {
		volume, err := store.conn.LookupStorageVolByPath(domainConfig.Disks[0].Source.File)
		if err != nil {
			return err
		}
		volumeInfo, err := volume.GetInfo()
		if err != nil {
			return err
		}
		vm.Disk = &models.VirtualMachineDisk{}
		vm.Disk.Driver = domainConfig.Disks[0].Driver.Name
		vm.Disk.Size = volumeInfo.Capacity
	} else {
		vm.Disk = nil
	}

	vm.Name = name
	vm.Uuid = fmt.Sprintf("%x", uuid)
	vm.Memory = int(info.Memory)
	vm.Cpus = int(info.NrVirtCpu)
	return nil
}

func (store *LibvirtMachinerep) List(machines *models.VirtualMachineList) error {
	domains, err := store.conn.ListAllDomains(0)
	if err != nil {
		return err
	}
	for _, domain := range domains {
		vm := &models.VirtualMachine{}
		if err := store.fillVm(vm, &domain); err != nil {
			return err
		}
		machines.Add(vm)
	}
	return nil
}

func (store *LibvirtMachinerep) Get(machine *models.VirtualMachine) (bool, error) {
	if machine.Name == "" {
		return false, nil
	}

	domain, err := store.conn.LookupDomainByName(machine.Name)
	if err != nil {
		virErr := err.(libvirt.Error)
		if virErr.Code == libvirt.ERR_NO_DOMAIN {
			return false, nil
		}
		return false, virErr
	}
	store.fillVm(machine, domain)
	return true, nil
}

func (store *LibvirtMachinerep) createConfigDrive(machine *models.VirtualMachine, pool *libvirt.StoragePool) (*libvirt.StorageVol, error) {
	tmpdir, err := ioutil.TempDir("", "")
	if err != nil {
		return nil, err
	}
	defer os.RemoveAll(tmpdir)
	metadataRoot := filepath.Join(tmpdir, "openstack", "latest")
	if err := os.MkdirAll(metadataRoot, 0755); err != nil {
		return nil, err
	}
	md, err := os.Create(filepath.Join(metadataRoot, "meta_data.json"))
	if err != nil {
		return nil, err
	}
	md.WriteString(fmt.Sprintf(`{
    "availability_zone": "none",
    "files": [
    ],
    "hostname": "%s",
    "launch_index": 0,
    "name": "%s",
    "meta": {
        "role": "webservers",
        "essential": "false"
    },
    "public_keys": {
        "mykey": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDAvKEhzpqnZ7ipUZkx43In/YoNuvG/HUqR0oCLk/Mil0R533TCDP9ZOiJOrWPhvQc3EOy6mJi5h9KBfxoGt0EbLkkL5Bq5Bb+NvbsxMXmNpgFkE6Yul+yJzRvzQJsvUk8B0vptDfQE2z3+LHkcN/WjMIVUhBC/hB+7d7THC2/TJ+o0CgCXXSkCJ3FqsjiZWEb77pLGnQUV5pp3n4tpR7Aoe9c1KZplXNt8hnWGUJN/gtLLmO6ouORnbRRE9yuPoLJz/r7GMmQQM9VOPyDBelpob4X7fiz0c5L+BCtvWjrZo7vVCFRcpVpBbNUiw5seK3qLUhaOVwL8GOfHTtsFpA7h kubuzzzz+book@gmail.com\n"
    },
    "uuid": "0cae2cdb-e041-4f26-835b-f9602df0edf3"}
    `, machine.Name, machine.Name))
	if err := md.Close(); err != nil {
		return nil, err
	}
	cmd := exec.Command(
		"mkisofs", "-R", "-V", "config-2", "-o",
		filepath.Join(tmpdir, "drive.iso"), tmpdir,
	)
	if err := cmd.Run(); err != nil {
		return nil, err
	}
	volumeXML := fmt.Sprintf(`
	<volume>
	  <target>
	  	<format type="raw" />
	  </target>
	  <name>%s_config.iso</name>
	  <capacity unit="b">1</capacity>
	</volume>`, machine.Name)
	volume, err := pool.StorageVolCreateXML(volumeXML, 0)
	if err != nil {
		return nil, err
	}
	content, err := os.Open(filepath.Join(tmpdir, "drive.iso"))
	if err != nil {
		return nil, err
	}
	contentSize, err := content.Seek(0, os.SEEK_END)
	if err != nil {
		return nil, err
	}
	_, err = content.Seek(0, os.SEEK_SET)
	if err != nil {
		return nil, err
	}

	stream, err := store.conn.NewStream(0)
	if err != nil {
		return nil, err
	}
	if err := volume.Upload(stream, 0, uint64(contentSize), 0); err != nil {
		return nil, err
	}
	stream.SendAll(func(stream *libvirt.Stream, n int) ([]byte, error) {
		buf := make([]byte, n)
		_, err := content.Read(buf)
		return buf, err
	})
	// if err := stream.Finish(); err != nil {
	// 	return nil, err
	// }
	return volume, nil
}

func (store *LibvirtMachinerep) Create(machine *models.VirtualMachine, image *models.Image, plan *models.Plan) error {
	storagePool, err := store.conn.LookupStoragePoolByName("default")
	if err != nil {
		return fmt.Errorf("failed to lookup vm storage pool: %s", err)
	}

	imagePool, err := store.conn.LookupStoragePoolByName(image.PoolName)
	if err != nil {
		return fmt.Errorf("failed to lookup image storage pool: %s", err)
	}

	volumeXML := fmt.Sprintf(`
	<volume>
	  <target>
	  	<format type="%s" />
	  </target>
	  <name>%s_disk.%s</name>
	  <capacity unit="G">%d</capacity>
	  <allocation unit="G">%d</allocation>
	</volume>
	`, image.TypeString(), machine.Name, image.TypeString(), plan.DiskSizeGigabytes(), plan.DiskSizeGigabytes())
	imageVolume, err := imagePool.LookupStorageVolByName(image.FullName)
	if err != nil {
		return fmt.Errorf("failed to lookup image volume: %s", err)
	}

	configDriveVolume, err := store.createConfigDrive(machine, storagePool)
	if err != nil {
		return fmt.Errorf("failed to create config drive: %s", err)
	}
	log.WithField("configdrive", configDriveVolume).Debug("config drive created successfully")
	configDrivePath, err := configDriveVolume.GetPath()
	if err != nil {
		return err
	}

	rootVolume, err := storagePool.StorageVolCreateXMLFrom(volumeXML, imageVolume, 0)
	if err != nil {
		configDriveVolume.Delete(0)
		return fmt.Errorf("failed to clone image: %s", err)
	}
	if err := rootVolume.Resize(uint64(plan.DiskSize), 0); err != nil {
		configDriveVolume.Delete(0)
		return fmt.Errorf("failed to resize root volume: %s", err)
	}
	rootVolumePath, err := rootVolume.GetPath()
	if err != nil {
		return fmt.Errorf("failed to get machine volume path: %s", err)
	}
	var machineXml bytes.Buffer
	vmtplContext := struct {
		Machine     *models.VirtualMachine
		Image       *models.Image
		Plan        *models.Plan
		VolumePath  string
		ConfigDrive string
	}{machine, image, plan, rootVolumePath, configDrivePath}
	if err := store.vmtpl.Execute(&machineXml, vmtplContext); err != nil {
		configDriveVolume.Delete(0)
		return err
	}
	log.WithField("xml", machineXml.String()).Debug("defining domain from xml")
	domain, err := store.conn.DomainDefineXML(machineXml.String())
	if err != nil {
		return err
	}
	store.fillVm(machine, domain)
	return nil
}

func (store *LibvirtMachinerep) Start(machine *models.VirtualMachine) error {
	domain, err := store.conn.LookupDomainByName(machine.Name)
	if err != nil {
		return err
	}
	return domain.Create()
}
<|endoftext|>


<commit_before>package swarm

import (
	"net"
	"time"
	"xd/lib/bittorrent"
	"xd/lib/bittorrent/extensions"
	"xd/lib/common"
	"xd/lib/log"
	"xd/lib/network"
	"xd/lib/storage"
	"xd/lib/tracker"
)

// a bittorrent swarm tracking many torrents
type Swarm struct {
	closing  bool
	net      network.Network
	Torrents Holder
	id       common.PeerID
	trackers map[string]tracker.Announcer
}

func (sw *Swarm) Running() bool {
	return !sw.closing
}

// wait until we get a network context
func (sw *Swarm) WaitForNetwork() {
	for sw.net == nil {
		time.Sleep(time.Second)
	}
}

func (sw *Swarm) startTorrent(t *Torrent) {
	sw.WaitForNetwork()
	// give peerid
	t.id = sw.id
	// add open trackers
	for name := range sw.trackers {
		t.Trackers[name] = sw.trackers[name]
	}

	info := t.MetaInfo()
	for _, u := range info.GetAllAnnounceURLS() {
		tr := tracker.FromURL(u)
		if tr != nil {
			name := tr.Name()
			_, ok := t.Trackers[name]
			if !ok {
				t.Trackers[name] = tr
			}
		}
	}

	// start annoucing
	go t.StartAnnouncing()
	// handle messages
	go t.Run()
}

// got inbound connection
func (sw *Swarm) inboundConn(c net.Conn) {
	h := new(bittorrent.Handshake)
	log.Debug("read bittorrent handshake")
	err := h.Recv(c)
	if err != nil {
		log.Warn("read bittorrent handshake failed, closing connection")
		// read error
		c.Close()
		return
	}
	t := sw.Torrents.GetTorrent(h.Infohash)
	if t == nil {
		log.Warnf("we don't have torrent with infohash %s, closing connection", h.Infohash.Hex())
		// no such torrent
		c.Close()
		return
	}
	var opts *extensions.ExtendedOptions
	if h.Reserved.Has(bittorrent.Extension) {
		opts = extensions.New()
	}
	// reply to handshake
	copy(h.PeerID[:], sw.id[:])
	err = h.Send(c)

	if err != nil {
		log.Warnf("didn't send bittorrent handshake reply: %s, closing connection", err)
		// write error
		c.Close()
		return
	}
	// make peer conn
	p := makePeerConn(c, t, h.PeerID, opts)

	go p.runWriter()
	go p.runReader()
	t.onNewPeer(p)
}

// add a torrent to this swarm
func (sw *Swarm) AddTorrent(t storage.Torrent, fresh bool) (err error) {
	if fresh {
		t.VerifyAll(true)
	}
	sw.Torrents.addTorrent(t)
	tr := sw.Torrents.GetTorrent(t.Infohash())
	go sw.startTorrent(tr)
	return
}

// run with network context
func (sw *Swarm) Run(n network.Network) (err error) {
	// resolve open trackers

	// give network to torrents
	sw.Torrents.ForEachTorrent(func(t *Torrent) {
		t.ObtainedNetwork(n)
	})
	// give network to swarm
	sw.net = n
	log.Debug("gave network context to torrents")
	// accept inbound connections
	for err == nil {
		var c net.Conn
		c, err = n.Accept()
		if err == nil {
			log.Debugf("got inbound bittorrent connection from %s", c.RemoteAddr())
			go sw.inboundConn(c)
		}
	}
	if sw.Running() {
		// suspend torrent's network on abbrupt break
		sw.Torrents.ForEachTorrent(func(t *Torrent) {
			t.LostNetwork()
		})
	}
	sw.net = nil
	return
}

// create a new swarm using a storage backend for storing downloads and torrent metadata
func NewSwarm(storage storage.Storage) *Swarm {
	sw := &Swarm{
		Torrents: Holder{
			st:       storage,
			torrents: make(map[string]*Torrent),
		},
		trackers: map[string]tracker.Announcer{},
	}
	sw.id = common.GeneratePeerID()
	log.Infof("generated peer id %s", sw.id.String())
	return sw
}

// AddOpenTracker adds an opentracker by url to be used by this swarm
func (sw *Swarm) AddOpenTracker(url string) {
	tr := tracker.FromURL(url)
	if tr != nil {
		name := tr.Name()
		_, ok := sw.trackers[name]
		if !ok {
			sw.trackers[name] = tr
		}
	}

}

// implements io.Closer
func (sw *Swarm) Close() (err error) {
	if !sw.closing {
		sw.closing = true
		err = sw.Torrents.Close()
	}
	return
}
<commit_msg>try fix<commit_after>package swarm

import (
	"net"
	"time"
	"xd/lib/bittorrent"
	"xd/lib/bittorrent/extensions"
	"xd/lib/common"
	"xd/lib/log"
	"xd/lib/network"
	"xd/lib/storage"
	"xd/lib/tracker"
)

// a bittorrent swarm tracking many torrents
type Swarm struct {
	closing  bool
	net      network.Network
	Torrents Holder
	id       common.PeerID
	trackers map[string]tracker.Announcer
}

func (sw *Swarm) Running() bool {
	return !sw.closing
}

// wait until we get a network context
func (sw *Swarm) WaitForNetwork() {
	for sw.net == nil {
		time.Sleep(time.Second)
	}
}

func (sw *Swarm) startTorrent(t *Torrent) {
	sw.WaitForNetwork()
	// give peerid
	t.id = sw.id
	// add open trackers
	for name := range sw.trackers {
		t.Trackers[name] = sw.trackers[name]
	}

	info := t.MetaInfo()
	for _, u := range info.GetAllAnnounceURLS() {
		tr := tracker.FromURL(u)
		if tr != nil {
			name := tr.Name()
			_, ok := t.Trackers[name]
			if !ok {
				t.Trackers[name] = tr
			}
		}
	}

	// start annoucing
	go t.StartAnnouncing()
	// handle messages
	go t.Run()
}

// got inbound connection
func (sw *Swarm) inboundConn(c net.Conn) {
	h := new(bittorrent.Handshake)
	log.Debug("read bittorrent handshake")
	err := h.Recv(c)
	if err != nil {
		log.Warn("read bittorrent handshake failed, closing connection")
		// read error
		c.Close()
		return
	}
	t := sw.Torrents.GetTorrent(h.Infohash)
	if t == nil {
		log.Warnf("we don't have torrent with infohash %s, closing connection", h.Infohash.Hex())
		// no such torrent
		c.Close()
		return
	}
	var opts *extensions.ExtendedOptions
	if h.Reserved.Has(bittorrent.Extension) {
		opts = extensions.New()
	}
	// reply to handshake
	copy(h.PeerID[:], sw.id[:])
	err = h.Send(c)

	if err != nil {
		log.Warnf("didn't send bittorrent handshake reply: %s, closing connection", err)
		// write error
		c.Close()
		return
	}
	// make peer conn
	p := makePeerConn(c, t, h.PeerID, opts)

	go p.runWriter()
	go p.runReader()
	t.onNewPeer(p)
}

// add a torrent to this swarm
func (sw *Swarm) AddTorrent(t storage.Torrent, fresh bool) (err error) {
	if fresh {
		t.VerifyAll(true)
	}
	sw.Torrents.addTorrent(t)
	tr := sw.Torrents.GetTorrent(t.Infohash())
	go sw.startTorrent(tr)
	return
}

// run with network context
func (sw *Swarm) Run(n network.Network) (err error) {
	// give network to swarm
	sw.net = n
	// give network to torrents
	sw.Torrents.ForEachTorrent(func(t *Torrent) {
		t.ObtainedNetwork(n)
	})
	log.Debug("gave network context to torrents")
	// accept inbound connections
	for err == nil {
		var c net.Conn
		c, err = n.Accept()
		if err == nil {
			log.Debugf("got inbound bittorrent connection from %s", c.RemoteAddr())
			go sw.inboundConn(c)
		}
	}
	if sw.Running() {
		// suspend torrent's network on abbrupt break
		sw.Torrents.ForEachTorrent(func(t *Torrent) {
			t.LostNetwork()
		})
	}
	sw.net = nil
	return
}

// create a new swarm using a storage backend for storing downloads and torrent metadata
func NewSwarm(storage storage.Storage) *Swarm {
	sw := &Swarm{
		Torrents: Holder{
			st:       storage,
			torrents: make(map[string]*Torrent),
		},
		trackers: map[string]tracker.Announcer{},
	}
	sw.id = common.GeneratePeerID()
	log.Infof("generated peer id %s", sw.id.String())
	return sw
}

// AddOpenTracker adds an opentracker by url to be used by this swarm
func (sw *Swarm) AddOpenTracker(url string) {
	tr := tracker.FromURL(url)
	if tr != nil {
		name := tr.Name()
		_, ok := sw.trackers[name]
		if !ok {
			sw.trackers[name] = tr
		}
	}

}

// implements io.Closer
func (sw *Swarm) Close() (err error) {
	if !sw.closing {
		sw.closing = true
		err = sw.Torrents.Close()
	}
	return
}
<|endoftext|>


<commit_before>package tiger

import (
	"fmt"
	"io"
	"testing"
	"unsafe"
)

type Test struct {
	out string
	in  string
}

var golden = []Test{
	{"3293ac630c13f0245f92bbb1766e16167a4e58492dde73f3", ""},
	{"77befbef2e7ef8ab2ec8f93bf587a7fc613e247f5f247809", "a"},
	{"2aab1484e8c158f2bfb8c5ff41b57a525129131c957b5f93", "abc"},
	{"d981f8cb78201a950dcf3048751e441c517fca1aa55a29f6", "message digest"},
	{"1714a472eee57d30040412bfcc55032a0b11602ff37beee9", "abcdefghijklmnopqrstuvwxyz"},
	{"0f7bf9a19b9c58f2b7610df7e84f0ac3a71c631e7b53f78e", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"},
	{"8dcea680a17583ee502ba38a3c368651890ffbccdc49a8cc", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"},
	{"1c14795529fd9f207a958f84c52f11e887fa0cabdfd91bfd", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"},
}

func TestGolden(t *testing.T) {
	for i := 0; i < len(golden); i++ {
		g := golden[i]
		c := New()
		buf := make([]byte, len(g.in)+4)
		for j := 0; j < 3+4; j++ {
			if j < 2 {
				io.WriteString(c, g.in)
			} else if j == 2 {
				io.WriteString(c, g.in[0:len(g.in)/2])
				c.Sum(nil)
				io.WriteString(c, g.in[len(g.in)/2:])
			} else if j > 2 {
				// test unaligned write
				buf = buf[1:]
				copy(buf, g.in)
				c.Write(buf[:len(g.in)])
			}
			s := fmt.Sprintf("%x", c.Sum(nil))
			if s != g.out {
				t.Fatalf("tiger[%d](%s) = %s want %s", j, g.in, s, g.out)
			}
			c.Reset()
		}
	}
}

func ExampleNew() {
	h := New()
	io.WriteString(h, "It's the eye of the tiger, it's the thrill of the fight")
	io.WriteString(h, "Rising up to the challenge of our rival!")
	fmt.Printf("%x", h.Sum(nil))
	// Output: a7bbad36cc17918e399ae8ee893e4595e4d24e1639fe822c
}

var bench = New()
var buf = make([]byte, 8192+1)
var sum = make([]byte, bench.Size())

func benchmarkSize(b *testing.B, size int, unaligned bool) {
	b.SetBytes(int64(size))
	buf := buf
	if unaligned {
		if uintptr(unsafe.Pointer(&buf[0]))&(unsafe.Alignof(uint32(0))-1) == 0 {
			buf = buf[1:]
		}
	}
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		bench.Reset()
		bench.Write(buf[:size])
		bench.Sum(sum[:0])
	}
}

func BenchmarkHash8Bytes(b *testing.B) {
	benchmarkSize(b, 8, false)
}

func BenchmarkHash1K(b *testing.B) {
	benchmarkSize(b, 1024, false)
}

func BenchmarkHash8K(b *testing.B) {
	benchmarkSize(b, 8192, false)
}

func BenchmarkHash8BytesUnaligned(b *testing.B) {
	benchmarkSize(b, 8, true)
}

func BenchmarkHash1KUnaligned(b *testing.B) {
	benchmarkSize(b, 1024, true)
}

func BenchmarkHash8KUnaligned(b *testing.B) {
	benchmarkSize(b, 8192, true)
}
<commit_msg>Example for tiger v2<commit_after>package tiger

import (
	"fmt"
	"io"
	"testing"
	"unsafe"
)

type Test struct {
	out string
	in  string
}

var golden = []Test{
	{"3293ac630c13f0245f92bbb1766e16167a4e58492dde73f3", ""},
	{"77befbef2e7ef8ab2ec8f93bf587a7fc613e247f5f247809", "a"},
	{"2aab1484e8c158f2bfb8c5ff41b57a525129131c957b5f93", "abc"},
	{"d981f8cb78201a950dcf3048751e441c517fca1aa55a29f6", "message digest"},
	{"1714a472eee57d30040412bfcc55032a0b11602ff37beee9", "abcdefghijklmnopqrstuvwxyz"},
	{"0f7bf9a19b9c58f2b7610df7e84f0ac3a71c631e7b53f78e", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"},
	{"8dcea680a17583ee502ba38a3c368651890ffbccdc49a8cc", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"},
	{"1c14795529fd9f207a958f84c52f11e887fa0cabdfd91bfd", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"},
}

func TestGolden(t *testing.T) {
	for i := 0; i < len(golden); i++ {
		g := golden[i]
		c := New()
		buf := make([]byte, len(g.in)+4)
		for j := 0; j < 3+4; j++ {
			if j < 2 {
				io.WriteString(c, g.in)
			} else if j == 2 {
				io.WriteString(c, g.in[0:len(g.in)/2])
				c.Sum(nil)
				io.WriteString(c, g.in[len(g.in)/2:])
			} else if j > 2 {
				// test unaligned write
				buf = buf[1:]
				copy(buf, g.in)
				c.Write(buf[:len(g.in)])
			}
			s := fmt.Sprintf("%x", c.Sum(nil))
			if s != g.out {
				t.Fatalf("tiger[%d](%s) = %s want %s", j, g.in, s, g.out)
			}
			c.Reset()
		}
	}
}

func ExampleNew() {
	h := New()
	io.WriteString(h, "It's the eye of the tiger, it's the thrill of the fight")
	io.WriteString(h, "Rising up to the challenge of our rival!")
	fmt.Printf("%x", h.Sum(nil))
	// Output: a7bbad36cc17918e399ae8ee893e4595e4d24e1639fe822c
}

func ExampleNew2() {
	h := New2()
	io.WriteString(h, "It's the eye of the tiger, it's the thrill of the fight")
	io.WriteString(h, "Rising up to the challenge of our rival!")
	fmt.Printf("%x", h.Sum(nil))
	// Output: c86695c2a639506682de2c12c2d23b61a12db78ea1ee1001
}

var bench = New()
var buf = make([]byte, 8192+1)
var sum = make([]byte, bench.Size())

func benchmarkSize(b *testing.B, size int, unaligned bool) {
	b.SetBytes(int64(size))
	buf := buf
	if unaligned {
		if uintptr(unsafe.Pointer(&buf[0]))&(unsafe.Alignof(uint32(0))-1) == 0 {
			buf = buf[1:]
		}
	}
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		bench.Reset()
		bench.Write(buf[:size])
		bench.Sum(sum[:0])
	}
}

func BenchmarkHash8Bytes(b *testing.B) {
	benchmarkSize(b, 8, false)
}

func BenchmarkHash1K(b *testing.B) {
	benchmarkSize(b, 1024, false)
}

func BenchmarkHash8K(b *testing.B) {
	benchmarkSize(b, 8192, false)
}

func BenchmarkHash8BytesUnaligned(b *testing.B) {
	benchmarkSize(b, 8, true)
}

func BenchmarkHash1KUnaligned(b *testing.B) {
	benchmarkSize(b, 1024, true)
}

func BenchmarkHash8KUnaligned(b *testing.B) {
	benchmarkSize(b, 8192, true)
}
<|endoftext|>


<commit_before>package humanlog

import (
	"time"
)

var formats = []string{
	"2006-01-02 15:04:05.999999999 -0700 MST",
	"2006-01-02 15:04:05",
	"2020-11-06T15:41:52.960-0500",
	time.RFC3339,
	time.RFC3339Nano,
	time.RFC822,
	time.RFC822Z,
	time.RFC850,
	time.RFC1123,
	time.RFC1123Z,
	time.UnixDate,
	time.RubyDate,
	time.ANSIC,
	time.Kitchen,
	time.Stamp,
	time.StampMilli,
	time.StampMicro,
	time.StampNano,
}

func parseTimeFloat64(value float64) time.Time {
	v := int64(value)
	switch {
	case v > 1e18:
	case v > 1e15:
		v *= 1e3
	case v > 1e12:
		v *= 1e6
	default:
		return time.Unix(v, 0)
	}

	return time.Unix(v/1e9, v%1e9)
}

// tries to parse time using a couple of formats before giving up
func tryParseTime(value interface{}) (time.Time, bool) {
	var t time.Time
	var err error
	switch value.(type) {
	case string:
		for _, layout := range formats {
			t, err = time.Parse(layout, value.(string))
			if err == nil {
				return t, true
			}
		}
	case float32:
		return parseTimeFloat64(float64(value.(float32))), true
	case float64:
		return parseTimeFloat64(value.(float64)), true
	case int:
		return parseTimeFloat64(float64(value.(int))), true
	case int32:
		return parseTimeFloat64(float64(value.(int32))), true
	case int64:
		return parseTimeFloat64(float64(value.(int64))), true
	}
	return t, false
}
<commit_msg>Fix format string<commit_after>package humanlog

import (
	"time"
)

var formats = []string{
	"2006-01-02 15:04:05.999999999 -0700 MST",
	"2006-01-02 15:04:05",
	"2006-01-02T15:04:05-0700",
	time.RFC3339,
	time.RFC3339Nano,
	time.RFC822,
	time.RFC822Z,
	time.RFC850,
	time.RFC1123,
	time.RFC1123Z,
	time.UnixDate,
	time.RubyDate,
	time.ANSIC,
	time.Kitchen,
	time.Stamp,
	time.StampMilli,
	time.StampMicro,
	time.StampNano,
}

func parseTimeFloat64(value float64) time.Time {
	v := int64(value)
	switch {
	case v > 1e18:
	case v > 1e15:
		v *= 1e3
	case v > 1e12:
		v *= 1e6
	default:
		return time.Unix(v, 0)
	}

	return time.Unix(v/1e9, v%1e9)
}

// tries to parse time using a couple of formats before giving up
func tryParseTime(value interface{}) (time.Time, bool) {
	var t time.Time
	var err error
	switch value.(type) {
	case string:
		for _, layout := range formats {
			t, err = time.Parse(layout, value.(string))
			if err == nil {
				return t, true
			}
		}
	case float32:
		return parseTimeFloat64(float64(value.(float32))), true
	case float64:
		return parseTimeFloat64(value.(float64)), true
	case int:
		return parseTimeFloat64(float64(value.(int))), true
	case int32:
		return parseTimeFloat64(float64(value.(int32))), true
	case int64:
		return parseTimeFloat64(float64(value.(int64))), true
	}
	return t, false
}
<|endoftext|>


<commit_before>package openjpeg

// #cgo pkg-config: libopenjp2
// #include <openjpeg.h>
import "C"

import (
	"errors"
	"fmt"
	"image"
	"reflect"
	"runtime"
	"unsafe"

	"github.com/nfnt/resize"
)

// Container for our simple JP2 operations
type JP2Image struct {
	filename     string
	stream       *C.opj_stream_t
	codec        *C.opj_codec_t
	image        *C.opj_image_t
	decodeWidth  int
	decodeHeight int
	srcWidth     int
	srcHeight    int
	decodeArea   image.Rectangle
	srcRect      image.Rectangle
	tileWidth    int
	tileHeight   int
}

func NewJP2Image(filename string) (*JP2Image, error) {
	i := &JP2Image{filename: filename}
	runtime.SetFinalizer(i, finalizer)

	if err := i.readDimensions(); err != nil {
		return nil, err
	}

	if err := i.initializeStream(); err != nil {
		return nil, err
	}

	return i, nil
}

// SetResizeWH sets the image to scale to the given width and height.  If one
// dimension is 0, the decoded image will preserve the aspect ratio while
// scaling to the non-zero dimension.
func (i *JP2Image) SetResizeWH(width, height int) {
	i.decodeWidth = width
	i.decodeHeight = height
}

func (i *JP2Image) SetCrop(r image.Rectangle) {
	i.decodeArea = r
}

// DecodeImage returns an image.Image that holds the decoded image data,
// resized and cropped if resizing or cropping was requested.  Both cropping
// and resizing happen here due to the nature of openjpeg, so SetScale,
// SetResizeWH, and SetCrop must be called before this function.
func (i *JP2Image) DecodeImage() (image.Image, error) {
	defer i.CleanupResources()

	// We need the codec to be ready for all operations below
	if err := i.initializeCodec(); err != nil {
		goLog(3, "Error initializing codec - aborting")
		return nil, err
	}

	if i.decodeArea == image.ZR {
		i.decodeArea = image.Rect(0, 0, i.srcWidth, i.srcHeight)
	}

	if i.decodeWidth == 0 && i.decodeHeight == 0 {
		i.decodeWidth = i.decodeArea.Dx()
		i.decodeHeight = i.decodeArea.Dy()
	}

	// Get progression level if we're resizing to specific dimensions (it's zero
	// if there isn't any scaling of the output)
	if i.decodeWidth != i.decodeArea.Dx() || i.decodeHeight != i.decodeArea.Dy() {
		level := desiredProgressionLevel(i.decodeArea, i.decodeWidth, i.decodeHeight)
		if err := i.SetDynamicProgressionLevel(level); err != nil {
			goLog(3, "Unable to set dynamic progression level - aborting")
			return nil, err
		}
	}

	if err := i.ReadHeader(); err != nil {
		goLog(3, "Error reading header before decode - aborting")
		return nil, err
	}

	goLog(6, fmt.Sprintf("num comps: %d", i.image.numcomps))
	goLog(6, fmt.Sprintf("x0: %d, x1: %d, y0: %d, y1: %d", i.image.x0, i.image.x1, i.image.y0, i.image.y1))

	// Setting decode area has to happen *after* reading the header / image data
	if i.decodeArea != i.srcRect {
		r := i.decodeArea
		if C.opj_set_decode_area(i.codec, i.image, C.OPJ_INT32(r.Min.X), C.OPJ_INT32(r.Min.Y), C.OPJ_INT32(r.Max.X), C.OPJ_INT32(r.Max.Y)) == C.OPJ_FALSE {
			return nil, errors.New("failed to set the decoded area")
		}
	}

	// Decode the JP2 into the image stream
	if C.opj_decode(i.codec, i.stream, i.image) == C.OPJ_FALSE {
		return nil, errors.New("failed to decode image")
	}
	if C.opj_end_decompress(i.codec, i.stream) == C.OPJ_FALSE {
		return nil, errors.New("failed to close decompression")
	}

	var comps []C.opj_image_comp_t
	compsSlice := (*reflect.SliceHeader)((unsafe.Pointer(&comps)))
	compsSlice.Cap = int(i.image.numcomps)
	compsSlice.Len = int(i.image.numcomps)
	compsSlice.Data = uintptr(unsafe.Pointer(i.image.comps))

	width := int(comps[0].w)
	height := int(comps[0].h)
	bounds := image.Rect(0, 0, width, height)
	var img image.Image

	// We assume grayscale if we don't have at least 3 components, because it's
	// probably the safest default
	if len(comps) < 3 {
		img = &image.Gray{Pix: JP2ComponentData(comps[0]), Stride: width, Rect: bounds}
	} else {
		// If we have 3+ components, we only care about the first three - I have no
		// idea what else we might have other than alpha, and as a tile server, we
		// don't care about the *source* image's alpha.  It's worth noting that
		// this will almost certainly blow up on any JP2 that isn't using RGB.

		area := width * height
		bytes := area << 2
		realData := make([]uint8, bytes)

		red := JP2ComponentData(comps[0])
		green := JP2ComponentData(comps[1])
		blue := JP2ComponentData(comps[2])

		offset := 0
		for i := 0; i < area; i++ {
			realData[offset] = red[i]
			offset++
			realData[offset] = green[i]
			offset++
			realData[offset] = blue[i]
			offset++
			realData[offset] = 255
			offset++
		}

		img = &image.RGBA{Pix: realData, Stride: width << 2, Rect: bounds}
	}

	if i.decodeWidth != i.decodeArea.Dx() || i.decodeHeight != i.decodeArea.Dy() {
		img = resize.Resize(uint(i.decodeWidth), uint(i.decodeHeight), img, resize.Bilinear)
	}

	return img, nil
}

func (i *JP2Image) ReadHeader() error {
	if i.image != nil {
		return nil
	}

	if err := i.initializeCodec(); err != nil {
		return err
	}

	if err := i.initializeStream(); err != nil {
		return err
	}

	if C.opj_read_header(i.stream, i.codec, &i.image) == C.OPJ_FALSE {
		return errors.New("failed to read the header")
	}

	return nil
}

// getDimensions reads the JP2 headers and pulls dimensions into srcWidth and
// srcHeight.  The image resource is cleaned up afterward, as this operation
// has to be usable independently of decoding.  This shouldn't be called after
// width and height are stored.
func (i *JP2Image) readDimensions() error {
	defer i.CleanupResources()
	if err := i.ReadHeader(); err != nil {
		return err
	}

	i.srcRect = image.Rect(int(i.image.x0), int(i.image.y0), int(i.image.x1), int(i.image.y1))
	i.srcWidth = i.srcRect.Dx()
	i.srcHeight = i.srcRect.Dy()

	cstrInfo := C.opj_get_cstr_info(i.codec)
	i.tileWidth = int(cstrInfo.tdx)
	i.tileHeight = int(cstrInfo.tdy)

	return nil
}

// GetWidth returns the image width
func (i *JP2Image) GetWidth() int {
	return i.srcWidth
}

// GetHeight returns the image height
func (i *JP2Image) GetHeight() int {
	return i.srcHeight
}

// GetTileWidth returns the tile width
func (i *JP2Image) GetTileWidth() int {
	return i.tileWidth
}

// GetTileHeight returns the tile height
func (i *JP2Image) GetTileHeight() int {
	return i.tileHeight
}

// Attempts to set the progression level to the given value, then re-read the
// header.  If reading the header fails, attempts to set the level to one level
// below the initial level.  If reading the header fails at level 0, an error
// is returned.
func (i *JP2Image) SetDynamicProgressionLevel(level int) error {
	onErr := func(err error) error {
		if level > 0 {
			goLog(6, fmt.Sprintf("Unable to set progression level to %d; trying again (%s)", level, err))
			i.CleanupResources()
			return i.SetDynamicProgressionLevel(level - 1)
		}

		return err
	}

	goLog(6, fmt.Sprintf("Setting progression level to %d", level))

	if err := i.initializeCodec(); err != nil {
		return onErr(err)
	}

	if C.opj_set_decoded_resolution_factor(i.codec, C.OPJ_UINT32(level)) == C.OPJ_FALSE {
		return onErr(errors.New("Error trying to set decoded resolution factor"))
	}

	if err := i.ReadHeader(); err != nil {
		return onErr(err)
	}

	return nil
}

// JP2ComponentData returns a slice of Image-usable uint8s from the JP2 raw
// data in the given component struct
func JP2ComponentData(comp C.struct_opj_image_comp) []uint8 {
	var data []int32
	dataSlice := (*reflect.SliceHeader)((unsafe.Pointer(&data)))
	size := int(comp.w) * int(comp.h)
	dataSlice.Cap = size
	dataSlice.Len = size
	dataSlice.Data = uintptr(unsafe.Pointer(comp.data))

	realData := make([]uint8, len(data))
	for index, point := range data {
		realData[index] = uint8(point)
	}

	return realData
}
<commit_msg>Use jp2info for getting image and tile dimensions<commit_after>package openjpeg

// #cgo pkg-config: libopenjp2
// #include <openjpeg.h>
import "C"

import (
	"errors"
	"fmt"
	"image"
	"jp2info"
	"reflect"
	"runtime"
	"unsafe"

	"github.com/nfnt/resize"
)

// Container for our simple JP2 operations
type JP2Image struct {
	filename     string
	stream       *C.opj_stream_t
	codec        *C.opj_codec_t
	image        *C.opj_image_t
	info         *jp2info.Info
	decodeWidth  int
	decodeHeight int
	decodeArea   image.Rectangle
	srcRect      image.Rectangle
}

func NewJP2Image(filename string) (*JP2Image, error) {
	i := &JP2Image{filename: filename}
	runtime.SetFinalizer(i, finalizer)

	if err := i.readInfo(); err != nil {
		return nil, err
	}

	if err := i.initializeStream(); err != nil {
		return nil, err
	}

	return i, nil
}

func (i *JP2Image) readInfo() error {
	var err error
	i.info, err = jp2info.NewScanner().Scan(i.filename)
	return err
}

// SetResizeWH sets the image to scale to the given width and height.  If one
// dimension is 0, the decoded image will preserve the aspect ratio while
// scaling to the non-zero dimension.
func (i *JP2Image) SetResizeWH(width, height int) {
	i.decodeWidth = width
	i.decodeHeight = height
}

func (i *JP2Image) SetCrop(r image.Rectangle) {
	i.decodeArea = r
}

// DecodeImage returns an image.Image that holds the decoded image data,
// resized and cropped if resizing or cropping was requested.  Both cropping
// and resizing happen here due to the nature of openjpeg, so SetScale,
// SetResizeWH, and SetCrop must be called before this function.
func (i *JP2Image) DecodeImage() (image.Image, error) {
	defer i.CleanupResources()

	// We need the codec to be ready for all operations below
	if err := i.initializeCodec(); err != nil {
		goLog(3, "Error initializing codec - aborting")
		return nil, err
	}

	if i.decodeArea == image.ZR {
		i.decodeArea = image.Rect(0, 0, int(i.info.Width), int(i.info.Height))
	}

	if i.decodeWidth == 0 && i.decodeHeight == 0 {
		i.decodeWidth = i.decodeArea.Dx()
		i.decodeHeight = i.decodeArea.Dy()
	}

	// Get progression level if we're resizing to specific dimensions (it's zero
	// if there isn't any scaling of the output)
	if i.decodeWidth != i.decodeArea.Dx() || i.decodeHeight != i.decodeArea.Dy() {
		level := desiredProgressionLevel(i.decodeArea, i.decodeWidth, i.decodeHeight)
		if err := i.SetDynamicProgressionLevel(level); err != nil {
			goLog(3, "Unable to set dynamic progression level - aborting")
			return nil, err
		}
	}

	if err := i.ReadHeader(); err != nil {
		goLog(3, "Error reading header before decode - aborting")
		return nil, err
	}

	goLog(6, fmt.Sprintf("num comps: %d", i.image.numcomps))
	goLog(6, fmt.Sprintf("x0: %d, x1: %d, y0: %d, y1: %d", i.image.x0, i.image.x1, i.image.y0, i.image.y1))

	// Setting decode area has to happen *after* reading the header / image data
	if i.decodeArea != i.srcRect {
		r := i.decodeArea
		if C.opj_set_decode_area(i.codec, i.image, C.OPJ_INT32(r.Min.X), C.OPJ_INT32(r.Min.Y), C.OPJ_INT32(r.Max.X), C.OPJ_INT32(r.Max.Y)) == C.OPJ_FALSE {
			return nil, errors.New("failed to set the decoded area")
		}
	}

	// Decode the JP2 into the image stream
	if C.opj_decode(i.codec, i.stream, i.image) == C.OPJ_FALSE {
		return nil, errors.New("failed to decode image")
	}
	if C.opj_end_decompress(i.codec, i.stream) == C.OPJ_FALSE {
		return nil, errors.New("failed to close decompression")
	}

	var comps []C.opj_image_comp_t
	compsSlice := (*reflect.SliceHeader)((unsafe.Pointer(&comps)))
	compsSlice.Cap = int(i.image.numcomps)
	compsSlice.Len = int(i.image.numcomps)
	compsSlice.Data = uintptr(unsafe.Pointer(i.image.comps))

	width := int(comps[0].w)
	height := int(comps[0].h)
	bounds := image.Rect(0, 0, width, height)
	var img image.Image

	// We assume grayscale if we don't have at least 3 components, because it's
	// probably the safest default
	if len(comps) < 3 {
		img = &image.Gray{Pix: JP2ComponentData(comps[0]), Stride: width, Rect: bounds}
	} else {
		// If we have 3+ components, we only care about the first three - I have no
		// idea what else we might have other than alpha, and as a tile server, we
		// don't care about the *source* image's alpha.  It's worth noting that
		// this will almost certainly blow up on any JP2 that isn't using RGB.

		area := width * height
		bytes := area << 2
		realData := make([]uint8, bytes)

		red := JP2ComponentData(comps[0])
		green := JP2ComponentData(comps[1])
		blue := JP2ComponentData(comps[2])

		offset := 0
		for i := 0; i < area; i++ {
			realData[offset] = red[i]
			offset++
			realData[offset] = green[i]
			offset++
			realData[offset] = blue[i]
			offset++
			realData[offset] = 255
			offset++
		}

		img = &image.RGBA{Pix: realData, Stride: width << 2, Rect: bounds}
	}

	if i.decodeWidth != i.decodeArea.Dx() || i.decodeHeight != i.decodeArea.Dy() {
		img = resize.Resize(uint(i.decodeWidth), uint(i.decodeHeight), img, resize.Bilinear)
	}

	return img, nil
}

func (i *JP2Image) ReadHeader() error {
	if i.image != nil {
		return nil
	}

	if err := i.initializeCodec(); err != nil {
		return err
	}

	if err := i.initializeStream(); err != nil {
		return err
	}

	if C.opj_read_header(i.stream, i.codec, &i.image) == C.OPJ_FALSE {
		return errors.New("failed to read the header")
	}

	return nil
}

// GetWidth returns the image width
func (i *JP2Image) GetWidth() int {
	return int(i.info.Width)
}

// GetHeight returns the image height
func (i *JP2Image) GetHeight() int {
	return int(i.info.Height)
}

// GetTileWidth returns the tile width
func (i *JP2Image) GetTileWidth() int {
	return int(i.info.TileWidth())
}

// GetTileHeight returns the tile height
func (i *JP2Image) GetTileHeight() int {
	return int(i.info.TileHeight())
}

// Attempts to set the progression level to the given value, then re-read the
// header.  If reading the header fails, attempts to set the level to one level
// below the initial level.  If reading the header fails at level 0, an error
// is returned.
func (i *JP2Image) SetDynamicProgressionLevel(level int) error {
	onErr := func(err error) error {
		if level > 0 {
			goLog(6, fmt.Sprintf("Unable to set progression level to %d; trying again (%s)", level, err))
			i.CleanupResources()
			return i.SetDynamicProgressionLevel(level - 1)
		}

		return err
	}

	goLog(6, fmt.Sprintf("Setting progression level to %d", level))

	if err := i.initializeCodec(); err != nil {
		return onErr(err)
	}

	if C.opj_set_decoded_resolution_factor(i.codec, C.OPJ_UINT32(level)) == C.OPJ_FALSE {
		return onErr(errors.New("Error trying to set decoded resolution factor"))
	}

	if err := i.ReadHeader(); err != nil {
		return onErr(err)
	}

	return nil
}

// JP2ComponentData returns a slice of Image-usable uint8s from the JP2 raw
// data in the given component struct
func JP2ComponentData(comp C.struct_opj_image_comp) []uint8 {
	var data []int32
	dataSlice := (*reflect.SliceHeader)((unsafe.Pointer(&data)))
	size := int(comp.w) * int(comp.h)
	dataSlice.Cap = size
	dataSlice.Len = size
	dataSlice.Data = uintptr(unsafe.Pointer(comp.data))

	realData := make([]uint8, len(data))
	for index, point := range data {
		realData[index] = uint8(point)
	}

	return realData
}
<|endoftext|>


<commit_before>// Copyright 2009 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.

// This package defines constants representing the lexical
// tokens of the Go programming language and basic operations
// on tokens (printing, predicates).
//
package token

import "strconv"

// Token is the set of lexical tokens of the Go programming language.
type Token int

// The list of tokens.
const (
	// Special tokens
	ILLEGAL Token = iota
	EOF
	COMMENT

	literal_beg
	// Identifiers and basic type literals
	// (these tokens stand for classes of literals)
	IDENT  // main
	INT    // 12345
	FLOAT  // 123.45
	IMAG   // 123.45i
	CHAR   // 'a'
	STRING // "abc"
	literal_end

	operator_beg
	// Operators and delimiters
	ADD // +
	SUB // -
	MUL // *
	QUO // /
	REM // %

	AND     // &
	OR      // |
	XOR     // ^
	SHL     // <<
	SHR     // >>
	AND_NOT // &^

	ADD_ASSIGN // +=
	SUB_ASSIGN // -=
	MUL_ASSIGN // *=
	QUO_ASSIGN // /=
	REM_ASSIGN // %=

	AND_ASSIGN     // &=
	OR_ASSIGN      // |=
	XOR_ASSIGN     // ^=
	SHL_ASSIGN     // <<=
	SHR_ASSIGN     // >>=
	AND_NOT_ASSIGN // &^=

	LAND  // &&
	LOR   // ||
	ARROW // <-
	INC   // ++
	DEC   // --

	EQL    // ==
	LSS    // <
	GTR    // >
	ASSIGN // =
	NOT    // !

	NEQ      // !=
	LEQ      // <=
	GEQ      // >=
	DEFINE   // :=
	ELLIPSIS // ...

	LPAREN // (
	LBRACK // [
	LBRACE // {
	COMMA  // ,
	PERIOD // .

	RPAREN    // )
	RBRACK    // ]
	RBRACE    // }
	SEMICOLON // ;
	COLON     // :
	operator_end

	keyword_beg
	// Keywords
	BREAK
	CASE
	CHAN
	CONST
	CONTINUE

	DEFAULT
	DEFER
	ELSE
	FALLTHROUGH
	FOR

	FUNC
	GO
	GOTO
	IF
	IMPORT

	INTERFACE
	MAP
	PACKAGE
	RANGE
	RETURN

	SELECT
	STRUCT
	SWITCH
	TYPE
	VAR
	keyword_end
)

// At the moment we have no array literal syntax that lets us describe
// the index for each element - use a map for now to make sure they are
// in sync.
var tokens = map[Token]string{
	ILLEGAL: "ILLEGAL",

	EOF:     "EOF",
	COMMENT: "COMMENT",

	IDENT:  "IDENT",
	INT:    "INT",
	FLOAT:  "FLOAT",
	IMAG:   "IMAG",
	CHAR:   "CHAR",
	STRING: "STRING",

	ADD: "+",
	SUB: "-",
	MUL: "*",
	QUO: "/",
	REM: "%",

	AND:     "&",
	OR:      "|",
	XOR:     "^",
	SHL:     "<<",
	SHR:     ">>",
	AND_NOT: "&^",

	ADD_ASSIGN: "+=",
	SUB_ASSIGN: "-=",
	MUL_ASSIGN: "*=",
	QUO_ASSIGN: "/=",
	REM_ASSIGN: "%=",

	AND_ASSIGN:     "&=",
	OR_ASSIGN:      "|=",
	XOR_ASSIGN:     "^=",
	SHL_ASSIGN:     "<<=",
	SHR_ASSIGN:     ">>=",
	AND_NOT_ASSIGN: "&^=",

	LAND:  "&&",
	LOR:   "||",
	ARROW: "<-",
	INC:   "++",
	DEC:   "--",

	EQL:    "==",
	LSS:    "<",
	GTR:    ">",
	ASSIGN: "=",
	NOT:    "!",

	NEQ:      "!=",
	LEQ:      "<=",
	GEQ:      ">=",
	DEFINE:   ":=",
	ELLIPSIS: "...",

	LPAREN: "(",
	LBRACK: "[",
	LBRACE: "{",
	COMMA:  ",",
	PERIOD: ".",

	RPAREN:    ")",
	RBRACK:    "]",
	RBRACE:    "}",
	SEMICOLON: ";",
	COLON:     ":",

	BREAK:    "break",
	CASE:     "case",
	CHAN:     "chan",
	CONST:    "const",
	CONTINUE: "continue",

	DEFAULT:     "default",
	DEFER:       "defer",
	ELSE:        "else",
	FALLTHROUGH: "fallthrough",
	FOR:         "for",

	FUNC:   "func",
	GO:     "go",
	GOTO:   "goto",
	IF:     "if",
	IMPORT: "import",

	INTERFACE: "interface",
	MAP:       "map",
	PACKAGE:   "package",
	RANGE:     "range",
	RETURN:    "return",

	SELECT: "select",
	STRUCT: "struct",
	SWITCH: "switch",
	TYPE:   "type",
	VAR:    "var",
}

// String returns the string corresponding to the token tok.
// For operators, delimiters, and keywords the string is the actual
// token character sequence (e.g., for the token ADD, the string is
// "+"). For all other tokens the string corresponds to the token
// constant name (e.g. for the token IDENT, the string is "IDENT").
//
func (tok Token) String() string {
	if str, exists := tokens[tok]; exists {
		return str
	}
	return "token(" + strconv.Itoa(int(tok)) + ")"
}

// A set of constants for precedence-based expression parsing.
// Non-operators have lowest precedence, followed by operators
// starting with precedence 1 up to unary operators. The highest
// precedence corresponds serves as "catch-all" precedence for
// selector, indexing, and other operator and delimiter tokens.
//
const (
	LowestPrec  = 0 // non-operators
	UnaryPrec   = 6
	HighestPrec = 7
)

// Precedence returns the operator precedence of the binary
// operator op. If op is not a binary operator, the result
// is LowestPrecedence.
//
func (op Token) Precedence() int {
	switch op {
	case LOR:
		return 1
	case LAND:
		return 2
	case EQL, NEQ, LSS, LEQ, GTR, GEQ:
		return 3
	case ADD, SUB, OR, XOR:
		return 4
	case MUL, QUO, REM, SHL, SHR, AND, AND_NOT:
		return 5
	}
	return LowestPrec
}

var keywords map[string]Token

func init() {
	keywords = make(map[string]Token)
	for i := keyword_beg + 1; i < keyword_end; i++ {
		keywords[tokens[i]] = i
	}
}

// Lookup maps an identifier to its keyword token or IDENT (if not a keyword).
//
func Lookup(ident []byte) Token {
	// TODO Maps with []byte key are illegal because []byte does not
	//      support == . Should find a more efficient solution eventually.
	if tok, is_keyword := keywords[string(ident)]; is_keyword {
		return tok
	}
	return IDENT
}

// Predicates

// IsLiteral returns true for tokens corresponding to identifiers
// and basic type literals; returns false otherwise.
//
func (tok Token) IsLiteral() bool { return literal_beg < tok && tok < literal_end }

// IsOperator returns true for tokens corresponding to operators and
// delimiters; returns false otherwise.
//
func (tok Token) IsOperator() bool { return operator_beg < tok && tok < operator_end }

// IsKeyword returns true for tokens corresponding to keywords;
// returns false otherwise.
//
func (tok Token) IsKeyword() bool { return keyword_beg < tok && tok < keyword_end }
<commit_msg>go/token: use array instead of map for token->string table<commit_after>// Copyright 2009 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.

// This package defines constants representing the lexical
// tokens of the Go programming language and basic operations
// on tokens (printing, predicates).
//
package token

import "strconv"

// Token is the set of lexical tokens of the Go programming language.
type Token int

// The list of tokens.
const (
	// Special tokens
	ILLEGAL Token = iota
	EOF
	COMMENT

	literal_beg
	// Identifiers and basic type literals
	// (these tokens stand for classes of literals)
	IDENT  // main
	INT    // 12345
	FLOAT  // 123.45
	IMAG   // 123.45i
	CHAR   // 'a'
	STRING // "abc"
	literal_end

	operator_beg
	// Operators and delimiters
	ADD // +
	SUB // -
	MUL // *
	QUO // /
	REM // %

	AND     // &
	OR      // |
	XOR     // ^
	SHL     // <<
	SHR     // >>
	AND_NOT // &^

	ADD_ASSIGN // +=
	SUB_ASSIGN // -=
	MUL_ASSIGN // *=
	QUO_ASSIGN // /=
	REM_ASSIGN // %=

	AND_ASSIGN     // &=
	OR_ASSIGN      // |=
	XOR_ASSIGN     // ^=
	SHL_ASSIGN     // <<=
	SHR_ASSIGN     // >>=
	AND_NOT_ASSIGN // &^=

	LAND  // &&
	LOR   // ||
	ARROW // <-
	INC   // ++
	DEC   // --

	EQL    // ==
	LSS    // <
	GTR    // >
	ASSIGN // =
	NOT    // !

	NEQ      // !=
	LEQ      // <=
	GEQ      // >=
	DEFINE   // :=
	ELLIPSIS // ...

	LPAREN // (
	LBRACK // [
	LBRACE // {
	COMMA  // ,
	PERIOD // .

	RPAREN    // )
	RBRACK    // ]
	RBRACE    // }
	SEMICOLON // ;
	COLON     // :
	operator_end

	keyword_beg
	// Keywords
	BREAK
	CASE
	CHAN
	CONST
	CONTINUE

	DEFAULT
	DEFER
	ELSE
	FALLTHROUGH
	FOR

	FUNC
	GO
	GOTO
	IF
	IMPORT

	INTERFACE
	MAP
	PACKAGE
	RANGE
	RETURN

	SELECT
	STRUCT
	SWITCH
	TYPE
	VAR
	keyword_end
)

var tokens = [...]string{
	ILLEGAL: "ILLEGAL",

	EOF:     "EOF",
	COMMENT: "COMMENT",

	IDENT:  "IDENT",
	INT:    "INT",
	FLOAT:  "FLOAT",
	IMAG:   "IMAG",
	CHAR:   "CHAR",
	STRING: "STRING",

	ADD: "+",
	SUB: "-",
	MUL: "*",
	QUO: "/",
	REM: "%",

	AND:     "&",
	OR:      "|",
	XOR:     "^",
	SHL:     "<<",
	SHR:     ">>",
	AND_NOT: "&^",

	ADD_ASSIGN: "+=",
	SUB_ASSIGN: "-=",
	MUL_ASSIGN: "*=",
	QUO_ASSIGN: "/=",
	REM_ASSIGN: "%=",

	AND_ASSIGN:     "&=",
	OR_ASSIGN:      "|=",
	XOR_ASSIGN:     "^=",
	SHL_ASSIGN:     "<<=",
	SHR_ASSIGN:     ">>=",
	AND_NOT_ASSIGN: "&^=",

	LAND:  "&&",
	LOR:   "||",
	ARROW: "<-",
	INC:   "++",
	DEC:   "--",

	EQL:    "==",
	LSS:    "<",
	GTR:    ">",
	ASSIGN: "=",
	NOT:    "!",

	NEQ:      "!=",
	LEQ:      "<=",
	GEQ:      ">=",
	DEFINE:   ":=",
	ELLIPSIS: "...",

	LPAREN: "(",
	LBRACK: "[",
	LBRACE: "{",
	COMMA:  ",",
	PERIOD: ".",

	RPAREN:    ")",
	RBRACK:    "]",
	RBRACE:    "}",
	SEMICOLON: ";",
	COLON:     ":",

	BREAK:    "break",
	CASE:     "case",
	CHAN:     "chan",
	CONST:    "const",
	CONTINUE: "continue",

	DEFAULT:     "default",
	DEFER:       "defer",
	ELSE:        "else",
	FALLTHROUGH: "fallthrough",
	FOR:         "for",

	FUNC:   "func",
	GO:     "go",
	GOTO:   "goto",
	IF:     "if",
	IMPORT: "import",

	INTERFACE: "interface",
	MAP:       "map",
	PACKAGE:   "package",
	RANGE:     "range",
	RETURN:    "return",

	SELECT: "select",
	STRUCT: "struct",
	SWITCH: "switch",
	TYPE:   "type",
	VAR:    "var",
}

// String returns the string corresponding to the token tok.
// For operators, delimiters, and keywords the string is the actual
// token character sequence (e.g., for the token ADD, the string is
// "+"). For all other tokens the string corresponds to the token
// constant name (e.g. for the token IDENT, the string is "IDENT").
//
func (tok Token) String() string {
	s := ""
	if 0 <= tok && tok < Token(len(tokens)) {
		s = tokens[tok]
	}
	if s == "" {
		s = "token(" + strconv.Itoa(int(tok)) + ")"
	}
	return s
}

// A set of constants for precedence-based expression parsing.
// Non-operators have lowest precedence, followed by operators
// starting with precedence 1 up to unary operators. The highest
// precedence corresponds serves as "catch-all" precedence for
// selector, indexing, and other operator and delimiter tokens.
//
const (
	LowestPrec  = 0 // non-operators
	UnaryPrec   = 6
	HighestPrec = 7
)

// Precedence returns the operator precedence of the binary
// operator op. If op is not a binary operator, the result
// is LowestPrecedence.
//
func (op Token) Precedence() int {
	switch op {
	case LOR:
		return 1
	case LAND:
		return 2
	case EQL, NEQ, LSS, LEQ, GTR, GEQ:
		return 3
	case ADD, SUB, OR, XOR:
		return 4
	case MUL, QUO, REM, SHL, SHR, AND, AND_NOT:
		return 5
	}
	return LowestPrec
}

var keywords map[string]Token

func init() {
	keywords = make(map[string]Token)
	for i := keyword_beg + 1; i < keyword_end; i++ {
		keywords[tokens[i]] = i
	}
}

// Lookup maps an identifier to its keyword token or IDENT (if not a keyword).
//
func Lookup(ident []byte) Token {
	// TODO Maps with []byte key are illegal because []byte does not
	//      support == . Should find a more efficient solution eventually.
	if tok, is_keyword := keywords[string(ident)]; is_keyword {
		return tok
	}
	return IDENT
}

// Predicates

// IsLiteral returns true for tokens corresponding to identifiers
// and basic type literals; returns false otherwise.
//
func (tok Token) IsLiteral() bool { return literal_beg < tok && tok < literal_end }

// IsOperator returns true for tokens corresponding to operators and
// delimiters; returns false otherwise.
//
func (tok Token) IsOperator() bool { return operator_beg < tok && tok < operator_end }

// IsKeyword returns true for tokens corresponding to keywords;
// returns false otherwise.
//
func (tok Token) IsKeyword() bool { return keyword_beg < tok && tok < keyword_end }
<|endoftext|>