<commit_before>package goejdb

// #cgo LDFLAGS: -ltcejdb
// #include <tcejdb/ejdb.h>
import "C"

import "unsafe"

// Query search mode flags in ejdbqryexecute()
const (
	// Query only count(*)
	jbqrycount   = C.JBQRYCOUNT
	// Fetch first record only
	jbqryfindone = C.JBQRYFINDONE
)

// An EJDB query
type EjQuery struct {
	ptr  *[0]byte
	ejdb *Ejdb
}

// Create query object.
// Sucessfully created queries must be destroyed with Query.Del().
//
// EJDB queries inspired by MongoDB (mongodb.org) and follows same philosophy.
//
//  - Supported queries:
//      - Simple matching of String OR Number OR Array value:
//          -   {'fpath' : 'val', ...}
//      - $not Negate operation.
//          -   {'fpath' : {'$not' : val}} //Field not equal to val
//          -   {'fpath' : {'$not' : {'$begin' : prefix}}} //Field not begins with val
//      - $begin String starts with prefix
//          -   {'fpath' : {'$begin' : prefix}}
//      - $gt, $gte (>, >=) and $lt, $lte for number types:
//          -   {'fpath' : {'$gt' : number}, ...}
//      - $bt Between for number types:
//          -   {'fpath' : {'$bt' : [num1, num2]}}
//      - $in String OR Number OR Array val matches to value in specified array:
//          -   {'fpath' : {'$in' : [val1, val2, val3]}}
//      - $nin - Not IN
//      - $strand String tokens OR String array val matches all tokens in specified array:
//          -   {'fpath' : {'$strand' : [val1, val2, val3]}}
//      - $stror String tokens OR String array val matches any token in specified array:
//          -   {'fpath' : {'$stror' : [val1, val2, val3]}}
//      - $exists Field existence matching:
//          -   {'fpath' : {'$exists' : true|false}}
//      - $icase Case insensitive string matching:
//          -    {'fpath' : {'$icase' : 'val1'}} //icase matching
//          Ignore case matching with '$in' operation:
//          -    {'name' : {'$icase' : {'$in' : ['théâtre - театр', 'hello world']}}}
//          For case insensitive matching you can create special index of type: `JBIDXISTR`
//      - $elemMatch The $elemMatch operator matches more than one component within an array element.
//          -    { array: { $elemMatch: { value1 : 1, value2 : { $gt: 1 } } } }
//          Restriction: only one $elemMatch allowed in context of one array field.
//
//  - Queries can be used to update records:
//
//      $set Field set operation.
//          - {.., '$set' : {'field1' : val1, 'fieldN' : valN}}
//      $upsert Atomic upsert. If matching records are found it will be '$set' operation,
//              otherwise new record will be inserted
//              with fields specified by argment object.
//          - {.., '$upsert' : {'field1' : val1, 'fieldN' : valN}}
//      $inc Increment operation. Only number types are supported.
//          - {.., '$inc' : {'field1' : number, ...,  'field1' : number}
//      $dropall In-place record removal operation.
//          - {.., '$dropall' : true}
//      $addToSet Atomically adds value to the array only if its not in the array already.
//                If containing array is missing it will be created.
//          - {.., '$addToSet' : {'fpath' : val1, 'fpathN' : valN, ...}}
//      $addToSetAll Batch version if $addToSet
//          - {.., '$addToSetAll' : {'fpath' : [array of values to add], ...}}
//      $pull  Atomically removes all occurrences of value from field, if field is an array.
//          - {.., '$pull' : {'fpath' : val1, 'fpathN' : valN, ...}}
//      $pullAll Batch version of $pull
//          - {.., '$pullAll' : {'fpath' : [array of values to remove], ...}}
//
// - Collection joins supported in the following form:
//
//      {..., $do : {fpath : {$join : 'collectionname'}} }
//      Where 'fpath' value points to object's OIDs from 'collectionname'. Its value
//      can be OID, string representation of OID or array of this pointers.
//
//  NOTE: Negate operations: $not and $nin not using indexes
//  so they can be slow in comparison to other matching operations.
//
//  NOTE: Only one index can be used in search query operation.
func (ejdb *Ejdb) CreateQuery(query string, queries ...string) (*EjQuery, *EjdbError) {
	query_bson := bson_from_json(query)
	defer C.bson_destroy(query_bson)

	orqueries_count := len(queries)
	orqueries := C.malloc(C.size_t(unsafe.Sizeof(C.bson{})) * C.size_t(orqueries_count))
	defer C.free(orqueries)
	ptr_orqueries := (*[maxslice]C.bson)(orqueries)
	for i, q := range queries {
		bson := bson_from_json(q)
		(*ptr_orqueries)[i] = *bson
		defer C.bson_destroy(bson)
	}

	q := C.ejdbcreatequery(ejdb.ptr, query_bson, (*C.bson)(orqueries), C.int(len(queries)), nil)
	if q == nil {
		return nil, ejdb.check_error()
	} else {
		return &EjQuery{ptr: q, ejdb: ejdb}, nil
	}
}

//  Set query hints. `hints` is a JSON string
//      - $max Maximum number in the result set
//      - $skip Number of skipped results in the result set
//      - $orderby Sorting order of query fields.
//      - $fields Set subset of fetched fields
//          If a field presented in $orderby clause it will be forced to include in resulting records.
//          Example:
//          hints:    {
//                      "$orderby" : { //ORDER BY field1 ASC, field2 DESC
//                          "field1" : 1,
//                          "field2" : -1
//                      },
//                      "$fields" : { //SELECT ONLY {_id, field1, field2}
//                          "field1" : 1,
//                          "field2" : 1
//                      }
//                    }
func (q *EjQuery) SetHints(hints string) *EjdbError {
	bsdata := bson_from_json(hints).data
	ret := C.ejdbqueryhints(q.ejdb.ptr, q.ptr, unsafe.Pointer(bsdata))
	if ret == nil {
		return q.ejdb.check_error()
	} else {
		return nil
	}
}

// Execute the query and return all results as a slice of BSON objects
func (q *EjQuery) Execute(coll *EjColl) ([][]byte, *EjdbError) {
	// execute query
	var count C.uint32_t
	res := C.ejdbqryexecute(coll.ptr, q.ptr, &count, 0, nil)
	defer C.ejdbqresultdispose(res)
	err := coll.ejdb.check_error()

	// return results
	ret := make([][]byte, 0)
	for i := 0; i < int(count); i++ {
		var size C.int
		bson_blob := C.ejdbqresultbsondata(res, C.int(i), &size)
		el := make([]byte, int(size))
		copy(el, (*[maxslice]byte)(bson_blob)[:int(size)])
		ret = append(ret, el)
	}

	return ret, err
}

// Execute the query and return only the first result as a BSON object
func (q *EjQuery) ExecuteOne(coll *EjColl) (*[]byte, *EjdbError) {
	// execute query
	var count C.uint32_t
	res := C.ejdbqryexecute(coll.ptr, q.ptr, &count, jbqryfindone, nil)
	defer C.ejdbqresultdispose(res)
	err := coll.ejdb.check_error()

	// return results
	if count == 0 {
		return nil, err
	} else {
		var size C.int
		bson_blob := C.ejdbqresultbsondata(res, 0, &size)
		ret := make([]byte, int(size))
		copy(ret, ((*[maxslice]byte)(bson_blob))[:int(size)])
		return &ret, err
	}
}

// Execute the query and only return the number of results it returned, not the results themselves
func (q *EjQuery) Count(coll *EjColl) (int, *EjdbError) {
	var count C.uint32_t
	C.ejdbqryexecute(coll.ptr, q.ptr, &count, jbqrycount, nil)
	err := coll.ejdb.check_error()
	return int(count), err
}

// Delete the query. This must be called in order to not leak memory.
func (q *EjQuery) Del() {
	C.ejdbquerydel(q.ptr)
}
<commit_msg>Implement AddOr method and simplify Query creation code<commit_after>package goejdb

// #cgo LDFLAGS: -ltcejdb
// #include <tcejdb/ejdb.h>
import "C"

import "unsafe"

// Query search mode flags in ejdbqryexecute()
const (
	// Query only count(*)
	jbqrycount   = C.JBQRYCOUNT
	// Fetch first record only
	jbqryfindone = C.JBQRYFINDONE
)

// An EJDB query
type EjQuery struct {
	ptr  *[0]byte
	ejdb *Ejdb
}

// Create query object.
// Sucessfully created queries must be destroyed with Query.Del().
//
// EJDB queries inspired by MongoDB (mongodb.org) and follows same philosophy.
//
//  - Supported queries:
//      - Simple matching of String OR Number OR Array value:
//          -   {'fpath' : 'val', ...}
//      - $not Negate operation.
//          -   {'fpath' : {'$not' : val}} //Field not equal to val
//          -   {'fpath' : {'$not' : {'$begin' : prefix}}} //Field not begins with val
//      - $begin String starts with prefix
//          -   {'fpath' : {'$begin' : prefix}}
//      - $gt, $gte (>, >=) and $lt, $lte for number types:
//          -   {'fpath' : {'$gt' : number}, ...}
//      - $bt Between for number types:
//          -   {'fpath' : {'$bt' : [num1, num2]}}
//      - $in String OR Number OR Array val matches to value in specified array:
//          -   {'fpath' : {'$in' : [val1, val2, val3]}}
//      - $nin - Not IN
//      - $strand String tokens OR String array val matches all tokens in specified array:
//          -   {'fpath' : {'$strand' : [val1, val2, val3]}}
//      - $stror String tokens OR String array val matches any token in specified array:
//          -   {'fpath' : {'$stror' : [val1, val2, val3]}}
//      - $exists Field existence matching:
//          -   {'fpath' : {'$exists' : true|false}}
//      - $icase Case insensitive string matching:
//          -    {'fpath' : {'$icase' : 'val1'}} //icase matching
//          Ignore case matching with '$in' operation:
//          -    {'name' : {'$icase' : {'$in' : ['théâtre - театр', 'hello world']}}}
//          For case insensitive matching you can create special index of type: `JBIDXISTR`
//      - $elemMatch The $elemMatch operator matches more than one component within an array element.
//          -    { array: { $elemMatch: { value1 : 1, value2 : { $gt: 1 } } } }
//          Restriction: only one $elemMatch allowed in context of one array field.
//
//  - Queries can be used to update records:
//
//      $set Field set operation.
//          - {.., '$set' : {'field1' : val1, 'fieldN' : valN}}
//      $upsert Atomic upsert. If matching records are found it will be '$set' operation,
//              otherwise new record will be inserted
//              with fields specified by argment object.
//          - {.., '$upsert' : {'field1' : val1, 'fieldN' : valN}}
//      $inc Increment operation. Only number types are supported.
//          - {.., '$inc' : {'field1' : number, ...,  'field1' : number}
//      $dropall In-place record removal operation.
//          - {.., '$dropall' : true}
//      $addToSet Atomically adds value to the array only if its not in the array already.
//                If containing array is missing it will be created.
//          - {.., '$addToSet' : {'fpath' : val1, 'fpathN' : valN, ...}}
//      $addToSetAll Batch version if $addToSet
//          - {.., '$addToSetAll' : {'fpath' : [array of values to add], ...}}
//      $pull  Atomically removes all occurrences of value from field, if field is an array.
//          - {.., '$pull' : {'fpath' : val1, 'fpathN' : valN, ...}}
//      $pullAll Batch version of $pull
//          - {.., '$pullAll' : {'fpath' : [array of values to remove], ...}}
//
// - Collection joins supported in the following form:
//
//      {..., $do : {fpath : {$join : 'collectionname'}} }
//      Where 'fpath' value points to object's OIDs from 'collectionname'. Its value
//      can be OID, string representation of OID or array of this pointers.
//
//  NOTE: Negate operations: $not and $nin not using indexes
//  so they can be slow in comparison to other matching operations.
//
//  NOTE: Only one index can be used in search query operation.
func (ejdb *Ejdb) CreateQuery(query string, queries ...string) (*EjQuery, *EjdbError) {
	query_bson := bson_from_json(query)
	defer C.bson_destroy(query_bson)

	ptr := C.ejdbcreatequery(ejdb.ptr, query_bson, nil, 0, nil)
	if ptr == nil {
		return nil, ejdb.check_error()
	}

	q := &EjQuery{ptr, ejdb}

	for _, orquery := range queries {
		err := q.AddOr(orquery)
		if err != nil {
			q.Del()
			return nil, ejdb.check_error()
		}
	}

	return q, nil
}

// Add OR restriction to query object. Expects orquery to be a JSON string.
func (q *EjQuery) AddOr(orquery string) (*EjdbError) {
	bson := bson_from_json(orquery)
	defer C.bson_destroy(bson)
	ret := C.ejdbqueryaddor(q.ejdb.ptr, q.ptr, unsafe.Pointer(bson.data))
	if ret == nil {
		return q.ejdb.check_error()
	} else {
		return nil
	}
}

//  Set query hints. `hints` is a JSON string
//      - $max Maximum number in the result set
//      - $skip Number of skipped results in the result set
//      - $orderby Sorting order of query fields.
//      - $fields Set subset of fetched fields
//          If a field presented in $orderby clause it will be forced to include in resulting records.
//          Example:
//          hints:    {
//                      "$orderby" : { //ORDER BY field1 ASC, field2 DESC
//                          "field1" : 1,
//                          "field2" : -1
//                      },
//                      "$fields" : { //SELECT ONLY {_id, field1, field2}
//                          "field1" : 1,
//                          "field2" : 1
//                      }
//                    }
func (q *EjQuery) SetHints(hints string) *EjdbError {
	bsdata := bson_from_json(hints).data
	ret := C.ejdbqueryhints(q.ejdb.ptr, q.ptr, unsafe.Pointer(bsdata))
	if ret == nil {
		return q.ejdb.check_error()
	} else {
		return nil
	}
}

// Execute the query and return all results as a slice of BSON objects
func (q *EjQuery) Execute(coll *EjColl) ([][]byte, *EjdbError) {
	// execute query
	var count C.uint32_t
	res := C.ejdbqryexecute(coll.ptr, q.ptr, &count, 0, nil)
	defer C.ejdbqresultdispose(res)
	err := coll.ejdb.check_error()

	// return results
	ret := make([][]byte, 0)
	for i := 0; i < int(count); i++ {
		var size C.int
		bson_blob := C.ejdbqresultbsondata(res, C.int(i), &size)
		el := make([]byte, int(size))
		copy(el, (*[maxslice]byte)(bson_blob)[:int(size)])
		ret = append(ret, el)
	}

	return ret, err
}

// Execute the query and return only the first result as a BSON object
func (q *EjQuery) ExecuteOne(coll *EjColl) (*[]byte, *EjdbError) {
	// execute query
	var count C.uint32_t
	res := C.ejdbqryexecute(coll.ptr, q.ptr, &count, jbqryfindone, nil)
	defer C.ejdbqresultdispose(res)
	err := coll.ejdb.check_error()

	// return results
	if count == 0 {
		return nil, err
	} else {
		var size C.int
		bson_blob := C.ejdbqresultbsondata(res, 0, &size)
		ret := make([]byte, int(size))
		copy(ret, ((*[maxslice]byte)(bson_blob))[:int(size)])
		return &ret, err
	}
}

// Execute the query and only return the number of results it returned, not the results themselves
func (q *EjQuery) Count(coll *EjColl) (int, *EjdbError) {
	var count C.uint32_t
	C.ejdbqryexecute(coll.ptr, q.ptr, &count, jbqrycount, nil)
	err := coll.ejdb.check_error()
	return int(count), err
}

// Delete the query. This must be called in order to not leak memory.
func (q *EjQuery) Del() {
	C.ejdbquerydel(q.ptr)
}
<|endoftext|>


<commit_before>package soap

import (
	"encoding/xml"
	"errors"
	"reflect"
	"strconv"
	"strings"
	"time"
)

// Element represents one XML/SOAP data element as Go struct. You can use it
// to build your own SOAP request/reply and use encoding/xml to
// marshal/unmarshal into/from XML document.
// See http://www.w3.org/2001/XMLSchema
type Element struct {
	XMLName xml.Name

	Type string `xml:"type,attr,omitempty"`
	Nil  bool   `xml:"nil,attr,omitempty"`

	Text     string     `xml:",chardata"`
	Children []*Element `xml:",any"`
}

// MakeElement takes some data structure in a and its name and produces Element
// (or Element tree) for it.
func MakeElement(name string, a interface{}) *Element {
	e := new(Element)
	e.XMLName.Local = name

	if a == nil {
		e.Nil = true
		return e
	}

	v := reflect.ValueOf(a)
	if v.Kind() == reflect.Ptr {
		if v.IsNil() {
			e.Nil = true
			return e
		}
		v = v.Elem()
	}

	if t, ok := v.Interface().(time.Time); ok {
		e.Type = "dateTime"
		e.Text = t.Format("2006-01-02T15:04:05.000000000-07:00")
		return e
	}

	switch v.Kind() {
	case reflect.String:
		e.Type = "string"
		e.Text = v.String()

	case reflect.Bool:
		e.Type = "boolean"
		if v.Bool() {
			e.Text = "true"
		} else {
			e.Text = "false"
		}

	case reflect.Int, reflect.Int64:
		e.Type = "long"
		e.Text = strconv.FormatInt(v.Int(), 10)
	case reflect.Int32:
		e.Type = "int"
		e.Text = strconv.FormatInt(v.Int(), 10)
	case reflect.Int16:
		e.Type = "short"
		e.Text = strconv.FormatInt(v.Int(), 10)
	case reflect.Int8:
		e.Type = "byte"
		e.Text = strconv.FormatInt(v.Int(), 10)

	case reflect.Uint, reflect.Uint64:
		e.Type = "unsignedLong"
		e.Text = strconv.FormatUint(v.Uint(), 10)
	case reflect.Uint32:
		e.Type = "unsignedInt"
		e.Text = strconv.FormatUint(v.Uint(), 10)
	case reflect.Uint16:
		e.Type = "unsignedShort"
		e.Text = strconv.FormatUint(v.Uint(), 10)
	case reflect.Uint8:
		e.Type = "unsignedByte"
		e.Text = strconv.FormatUint(v.Uint(), 10)
	case reflect.Float32:

		e.Type = "float"
		e.Text = strconv.FormatFloat(v.Float(), 'e', 7, 32)
	case reflect.Float64:
		e.Type = "double"
		e.Text = strconv.FormatFloat(v.Float(), 'e', 16, 64)

	case reflect.Struct:
		e.Type = "Struct"
		t := v.Type()
		n := t.NumField()
		for i := 0; i < n; i++ {
			ft := t.Field(i)
			if ft.PkgPath != "" {
				continue // unexported field
			}
			name := ft.Tag.Get("xml")
			if name == "" {
				name = ft.Name
			}
			e.Children = append(
				e.Children,
				MakeElement(name, v.Field(i).Interface()),
			)
		}

	case reflect.Slice, reflect.Array:
		panic("soap: slices and arrays not implemented")
	case reflect.Map:
		panic("soap: maps not implemented")
	default:
		panic("soap: unknown kind of type: " + v.Kind().String())
	}
	return e
}

func skipNS(s string) string {
	i := strings.IndexRune(s, ':')
	if i == -1 {
		return s
	}
	return s[i+1:]
}

func (e *Element) badValue() error {
	return errors.New("soap: bad value '" + e.Text + "' for type: " + e.Type)
}

// Value return SOAP element as Go data structure. It can be a simple scalar
// value or more complicated structure that contains maps and slices.
func (e *Element) Value() (interface{}, error) {
	if e.Nil {
		return nil, nil
	}

	switch skipNS(e.Type) {
	case "string":
		return e.Text, nil

	case "boolean":
		switch e.Text {
		case "true":
			return true, nil
		case "false":
			return false, nil
		}
		return nil, e.badValue()

	case "long", "int", "short", "byte":
		v, err := strconv.ParseInt(e.Text, 10, 64)
		if err != nil {
			return nil, e.badValue()
		}
		return v, nil

	case "unsignedLong", "unsignedInt", "unsignedShort", "unsignedByte":
		v, err := strconv.ParseUint(e.Text, 10, 64)
		if err != nil {
			return nil, e.badValue()
		}
		return v, nil

	case "float", "double":
		v, err := strconv.ParseFloat(e.Text, 64)
		if err != nil {
			return nil, e.badValue()
		}
		return v, nil

	case "Struct":
		v := make(map[string]interface{})
		for _, c := range e.Children {
			cv, err := c.Value()
			if err != nil {
				return nil, err
			}
			v[c.XMLName.Local] = cv
		}
		return v, nil

	case "Array":
		var v []interface{}
		for _, c := range e.Children {
			if c.XMLName.Local != "item" {
				return nil, errors.New(
					"soap: bad element '" + c.XMLName.Local + "'in array",
				)
			}
			cv, err := c.Value()
			if err != nil {
				return nil, err
			}
			v = append(v, cv)
		}
		return v, nil

	case "Map":
		v := make(map[interface{}]interface{})
		for _, c := range e.Children {
			if c.XMLName.Local != "item" {
				return nil, errors.New(
					"soap: bad element name '" + c.XMLName.Local + "' in map",
				)
			}
			if len(c.Children) != 2 || c.Children[0] == nil ||
				c.Children[1] == nil {

				return nil, errors.New(
					"soap: bad number of children in map item",
				)
			}

			var (
				key, val interface{}
				err      error
			)

			switch "key" {
			case c.Children[0].XMLName.Local:
				key, err = c.Children[0].Value()
			case c.Children[1].XMLName.Local:
				key, err = c.Children[1].Value()
			default:
				return nil, errors.New("soap: map item without a key")
			}
			if err != nil {
				return nil, err
			}

			switch "value" {
			case c.Children[1].XMLName.Local:
				val, err = c.Children[1].Value()
			case c.Children[0].XMLName.Local:
				val, err = c.Children[0].Value()
			default:
				return nil, errors.New("soap: map item without a value")

			}
			if err != nil {
				return nil, err
			}

			v[key] = val
		}
		return v, nil
	}
	return nil, errors.New("soap: unknown type: " + e.Type)
}
<commit_msg>Some fixes in doc<commit_after>package soap

import (
	"encoding/xml"
	"errors"
	"reflect"
	"strconv"
	"strings"
	"time"
)

// Element represents one XML/SOAP data element as Go struct. You can use it
// to build your own SOAP request/reply and use encoding/xml to
// marshal/unmarshal it into/from XML document.
// See http://www.w3.org/2001/XMLSchema
type Element struct {
	XMLName xml.Name

	Type string `xml:"type,attr,omitempty"`
	Nil  bool   `xml:"nil,attr,omitempty"`

	Text     string     `xml:",chardata"`
	Children []*Element `xml:",any"`
}

// MakeElement takes some data structure in a and its name and produces an
// Element (or some Element tree) for it.
func MakeElement(name string, a interface{}) *Element {
	e := new(Element)
	e.XMLName.Local = name

	if a == nil {
		e.Nil = true
		return e
	}

	v := reflect.ValueOf(a)
	if v.Kind() == reflect.Ptr {
		if v.IsNil() {
			e.Nil = true
			return e
		}
		v = v.Elem()
	}

	if t, ok := v.Interface().(time.Time); ok {
		e.Type = "dateTime"
		e.Text = t.Format("2006-01-02T15:04:05.000000000-07:00")
		return e
	}

	switch v.Kind() {
	case reflect.String:
		e.Type = "string"
		e.Text = v.String()

	case reflect.Bool:
		e.Type = "boolean"
		if v.Bool() {
			e.Text = "true"
		} else {
			e.Text = "false"
		}

	case reflect.Int, reflect.Int64:
		e.Type = "long"
		e.Text = strconv.FormatInt(v.Int(), 10)
	case reflect.Int32:
		e.Type = "int"
		e.Text = strconv.FormatInt(v.Int(), 10)
	case reflect.Int16:
		e.Type = "short"
		e.Text = strconv.FormatInt(v.Int(), 10)
	case reflect.Int8:
		e.Type = "byte"
		e.Text = strconv.FormatInt(v.Int(), 10)

	case reflect.Uint, reflect.Uint64:
		e.Type = "unsignedLong"
		e.Text = strconv.FormatUint(v.Uint(), 10)
	case reflect.Uint32:
		e.Type = "unsignedInt"
		e.Text = strconv.FormatUint(v.Uint(), 10)
	case reflect.Uint16:
		e.Type = "unsignedShort"
		e.Text = strconv.FormatUint(v.Uint(), 10)
	case reflect.Uint8:
		e.Type = "unsignedByte"
		e.Text = strconv.FormatUint(v.Uint(), 10)
	case reflect.Float32:

		e.Type = "float"
		e.Text = strconv.FormatFloat(v.Float(), 'e', 7, 32)
	case reflect.Float64:
		e.Type = "double"
		e.Text = strconv.FormatFloat(v.Float(), 'e', 16, 64)

	case reflect.Struct:
		e.Type = "Struct"
		t := v.Type()
		n := t.NumField()
		for i := 0; i < n; i++ {
			ft := t.Field(i)
			if ft.PkgPath != "" {
				continue // unexported field
			}
			name := ft.Tag.Get("xml")
			if name == "" {
				name = ft.Name
			}
			e.Children = append(
				e.Children,
				MakeElement(name, v.Field(i).Interface()),
			)
		}

	case reflect.Slice, reflect.Array:
		panic("soap: slices and arrays not implemented")
	case reflect.Map:
		panic("soap: maps not implemented")
	default:
		panic("soap: unknown kind of type: " + v.Kind().String())
	}
	return e
}

func skipNS(s string) string {
	i := strings.IndexRune(s, ':')
	if i == -1 {
		return s
	}
	return s[i+1:]
}

func (e *Element) badValue() error {
	return errors.New("soap: bad value '" + e.Text + "' for type: " + e.Type)
}

// Value returns SOAP element as Go data structure. It can be a simple scalar
// value or more complicated structure that contains maps and slices.
func (e *Element) Value() (interface{}, error) {
	if e.Nil {
		return nil, nil
	}

	switch skipNS(e.Type) {
	case "string":
		return e.Text, nil

	case "boolean":
		switch e.Text {
		case "true":
			return true, nil
		case "false":
			return false, nil
		}
		return nil, e.badValue()

	case "long", "int", "short", "byte":
		v, err := strconv.ParseInt(e.Text, 10, 64)
		if err != nil {
			return nil, e.badValue()
		}
		return v, nil

	case "unsignedLong", "unsignedInt", "unsignedShort", "unsignedByte":
		v, err := strconv.ParseUint(e.Text, 10, 64)
		if err != nil {
			return nil, e.badValue()
		}
		return v, nil

	case "float", "double":
		v, err := strconv.ParseFloat(e.Text, 64)
		if err != nil {
			return nil, e.badValue()
		}
		return v, nil

	case "Struct":
		v := make(map[string]interface{})
		for _, c := range e.Children {
			cv, err := c.Value()
			if err != nil {
				return nil, err
			}
			v[c.XMLName.Local] = cv
		}
		return v, nil

	case "Array":
		var v []interface{}
		for _, c := range e.Children {
			if c.XMLName.Local != "item" {
				return nil, errors.New(
					"soap: bad element '" + c.XMLName.Local + "'in array",
				)
			}
			cv, err := c.Value()
			if err != nil {
				return nil, err
			}
			v = append(v, cv)
		}
		return v, nil

	case "Map":
		v := make(map[interface{}]interface{})
		for _, c := range e.Children {
			if c.XMLName.Local != "item" {
				return nil, errors.New(
					"soap: bad element name '" + c.XMLName.Local + "' in map",
				)
			}
			if len(c.Children) != 2 || c.Children[0] == nil ||
				c.Children[1] == nil {

				return nil, errors.New(
					"soap: bad number of children in map item",
				)
			}

			var (
				key, val interface{}
				err      error
			)

			switch "key" {
			case c.Children[0].XMLName.Local:
				key, err = c.Children[0].Value()
			case c.Children[1].XMLName.Local:
				key, err = c.Children[1].Value()
			default:
				return nil, errors.New("soap: map item without a key")
			}
			if err != nil {
				return nil, err
			}

			switch "value" {
			case c.Children[1].XMLName.Local:
				val, err = c.Children[1].Value()
			case c.Children[0].XMLName.Local:
				val, err = c.Children[0].Value()
			default:
				return nil, errors.New("soap: map item without a value")

			}
			if err != nil {
				return nil, err
			}

			v[key] = val
		}
		return v, nil
	}
	return nil, errors.New("soap: unknown type: " + e.Type)
}
<|endoftext|>


<commit_before>package sdp

func (s Session) appendAttributes(attrs Attributes) Session {
	for k, v := range attrs {
		for _, a := range v {
			if len(a) == 0 {
				s = s.AddFlag(k)
			} else {
				s = s.AddAttribute(k, a)
			}
		}
	}
	return s
}

// Append encodes message to Session and returns result.
func (m *Message) Append(s Session) Session {
	// see https://tools.ietf.org/html/rfc4566#section-5
	s = s.AddVersion(m.Version)
	s = s.AddOrigin(m.Origin)
	s = s.AddSessionName(m.Name)
	if len(m.Info) > 0 {
		s = s.AddSessionInfo(m.Info)
	}
	if len(m.URI) > 0 {
		s = s.AddURI(m.URI)
	}
	if len(m.Email) > 0 {
		s = s.AddEmail(m.Email)
	}
	if len(m.Phone) > 0 {
		s = s.AddPhone(m.Phone)
	}
	if !m.Connection.Blank() {
		s = s.AddConnectionData(m.Connection)
	}
	for t, v := range m.Bandwidths {
		s = s.AddBandwidth(t, v)
	}
	// One or more time descriptions ("t=" and "r=" lines)
	for _, t := range m.Timing {
		s = s.AddTiming(t.Start, t.End)
		if len(t.Offsets) > 0 {
			s = s.AddRepeatTimesCompact(t.Repeat, t.Active, t.Offsets...)
		}
	}
	if len(m.TZAdjustments) > 0 {
		s = s.AddTimeZones(m.TZAdjustments...)
	}
	if !m.Encryption.Blank() {
		s = s.AddEncryption(m.Encryption)
	}
	s = s.appendAttributes(m.Attributes)

	for _, mm := range m.Medias {
		s = s.AddMediaDescription(mm.Description)
		if len(mm.Title) > 0 {
			s = s.AddSessionInfo(mm.Title)
		}
		if !mm.Connection.Blank() {
			s = s.AddConnectionData(mm.Connection)
		}
		for t, v := range mm.Bandwidths {
			s = s.AddBandwidth(t, v)
		}
		if !mm.Encryption.Blank() {
			s = s.AddEncryption(mm.Encryption)
		}
		s = s.appendAttributes(mm.Attributes)
	}
	return s
}
<commit_msg>encoder: optimize data copy on iteration<commit_after>package sdp

func (s Session) appendAttributes(attrs Attributes) Session {
	for k, v := range attrs {
		for _, a := range v {
			if len(a) == 0 {
				s = s.AddFlag(k)
			} else {
				s = s.AddAttribute(k, a)
			}
		}
	}
	return s
}

// Append encodes message to Session and returns result.
func (m *Message) Append(s Session) Session {
	// see https://tools.ietf.org/html/rfc4566#section-5
	s = s.AddVersion(m.Version)
	s = s.AddOrigin(m.Origin)
	s = s.AddSessionName(m.Name)
	if len(m.Info) > 0 {
		s = s.AddSessionInfo(m.Info)
	}
	if len(m.URI) > 0 {
		s = s.AddURI(m.URI)
	}
	if len(m.Email) > 0 {
		s = s.AddEmail(m.Email)
	}
	if len(m.Phone) > 0 {
		s = s.AddPhone(m.Phone)
	}
	if !m.Connection.Blank() {
		s = s.AddConnectionData(m.Connection)
	}
	for t, v := range m.Bandwidths {
		s = s.AddBandwidth(t, v)
	}
	// One or more time descriptions ("t=" and "r=" lines)
	for _, t := range m.Timing {
		s = s.AddTiming(t.Start, t.End)
		if len(t.Offsets) > 0 {
			s = s.AddRepeatTimesCompact(t.Repeat, t.Active, t.Offsets...)
		}
	}
	if len(m.TZAdjustments) > 0 {
		s = s.AddTimeZones(m.TZAdjustments...)
	}
	if !m.Encryption.Blank() {
		s = s.AddEncryption(m.Encryption)
	}
	s = s.appendAttributes(m.Attributes)

	for i := range m.Medias {
		s = s.AddMediaDescription(m.Medias[i].Description)
		if len(m.Medias[i].Title) > 0 {
			s = s.AddSessionInfo(m.Medias[i].Title)
		}
		if !m.Medias[i].Connection.Blank() {
			s = s.AddConnectionData(m.Medias[i].Connection)
		}
		for t, v := range m.Medias[i].Bandwidths {
			s = s.AddBandwidth(t, v)
		}
		if !m.Medias[i].Encryption.Blank() {
			s = s.AddEncryption(m.Medias[i].Encryption)
		}
		s = s.appendAttributes(m.Medias[i].Attributes)
	}
	return s
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"golang.org/x/crypto/openpgp"
	"golang.org/x/crypto/openpgp/armor"
	"bytes"
	"net/http"
)

// XXX: For actual encryption in app do not use armor for encoding

func encrypt(message string) (string, error) {
    // Gets public key of recipient
	resp, err := http.Get("https://keybase.io/leijurv/key.asc")
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

    // Reads key into list of keys
	entityList, err := openpgp.ReadArmoredKeyRing(resp.Body)
	if err != nil {
		return "", err
	}

    // New buffer where the result of the encripted msg will be
	buf := new(bytes.Buffer)

    // Create an armored template stream for msg
	w, err := armor.Encode(buf, "PGP MESSAGE", nil)
	if err != nil {
		return "", err
	}

    // Create an encryption stream
	plaintext, err := openpgp.Encrypt(w, entityList, nil, nil, nil)
	if err != nil {
		return "", err
	}

    // Write a byte array saying the message to encryption stream
	_, err = plaintext.Write([]byte(message))
	if err != nil {
		return "", err
	}

    // Close streams, finishing encryption and armor texts
    plaintext.Close()
    w.Close()

	return buf.String(), nil
}

func main() {
    str, err := encrypt("hello world")
    if err != nil {
		panic(err)
	}
    fmt.Println(str)
}
<commit_msg>encrypt multi user<commit_after>package main

import (
	"bytes"
	"fmt"
	"golang.org/x/crypto/openpgp"
	"golang.org/x/crypto/openpgp/armor"
	"net/http"
)

// XXX: For actual encryption in app do not use armor for encoding

func getKeyByKeybaseUsername(username string) (openpgp.EntityList, error) {
	// Gets public key of recipient
	resp, err := http.Get("https://keybase.io/" + username + "/key.asc")
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	// Reads key into list of keys
	entityList, err := openpgp.ReadArmoredKeyRing(resp.Body)
	if err != nil {
		return nil, err
	}
	return entityList, nil
}

func encrypt(message string, users []string) (string, error) {

	var entityList openpgp.EntityList

	for index, username := range users {
		eL, err := getKeyByKeybaseUsername(username)
		if err != nil {
			return "", err
		}
		if index == 0 {
			entityList = eL
		} else {
			entityList = append(entityList, eL[0])
		}
	}

	// New buffer where the result of the encripted msg will be
	buf := new(bytes.Buffer)

	// Create an armored template stream for msg
	w, err := armor.Encode(buf, "PGP MESSAGE", nil)
	if err != nil {
		return "", err
	}

	// Create an encryption stream
	plaintext, err := openpgp.Encrypt(w, entityList, nil, nil, nil)
	if err != nil {
		return "", err
	}

	// Write a byte array saying the message to encryption stream
	_, err = plaintext.Write([]byte(message))
	if err != nil {
		return "", err
	}

	// Close streams, finishing encryption and armor texts
	plaintext.Close()
	w.Close()

	return buf.String(), nil
}

func main() {
	str, err := encrypt("hello world", []string{"slaidan_lt"})
	if err != nil {
		panic(err)
	}
	fmt.Println(str)
}
<|endoftext|>


<commit_before>package env

import (
	"os"
	"strings"
	"sync"
)

const pathListSeparator = string(os.PathListSeparator)

// Env represents an environment.
type Env struct {
	keys map[string]int
	data []string
	lock sync.Mutex
}

// New returns a new environment filled with initial data.
func New(data []string) *Env {
	env := &Env{
		keys: make(map[string]int),
	}

	if len(data) > 0 {
		env.data = make([]string, len(data))
		copy(env.data, data)
	}

	return env.fillkeys()
}

func (env *Env) fillkeys() *Env {
	for i, v := range env.data {
		for j, k := 0, len(v); j < k; j++ {
			if v[j] == '=' {
				key := v[:j]
				if _, ok := env.keys[key]; !ok {
					env.keys[key] = i
				}
				break
			}
		}
	}

	return env
}

// Add adds to the values of the environment variable named by the key.
func (env *Env) Add(key string, values ...string) {
	env.lock.Lock()
	defer env.lock.Unlock()

	value := strings.Join(values, pathListSeparator)

	if i, ok := env.keys[key]; ok {
		env.data[i] += value
	} else {
		env.keys[key] = len(env.data)
		env.data = append(env.data, key+"="+value)
	}
}

// Set sets the value of the environment variable named by the key.
func (env *Env) Set(key string, values ...string) {
	env.lock.Lock()
	defer env.lock.Unlock()

	value := key + "=" + strings.Join(values, pathListSeparator)

	if i, ok := env.keys[key]; ok {
		env.data[i] = value
	} else {
		env.keys[key] = len(env.data)
		env.data = append(env.data, value)
	}
}

// Get retreives the value of the environment variable named by the given key. The return value will be
// an empty string if the key is not present
func (env *Env) Get(key string) (value string) {
	if i, ok := env.keys[key]; ok {
		value = env.data[i]
		return value[strings.Index(value, "=")+1:]
	}
	return value
}

// Data returns a copy of the slice representing the environment.
func (env *Env) Data() []string {
	return env.data
}
<commit_msg>Add env string function<commit_after>package env

import (
	"os"
	"strings"
	"sync"
)

const pathListSeparator = string(os.PathListSeparator)

// Env represents an environment.
type Env struct {
	keys map[string]int
	data []string
	lock sync.Mutex
}

// New returns a new environment filled with initial data.
func New(data []string) *Env {
	env := &Env{
		keys: make(map[string]int),
	}

	if len(data) > 0 {
		env.data = make([]string, len(data))
		copy(env.data, data)
	}

	return env.fillkeys()
}

func (env *Env) fillkeys() *Env {
	for i, v := range env.data {
		for j, k := 0, len(v); j < k; j++ {
			if v[j] == '=' {
				key := v[:j]
				if _, ok := env.keys[key]; !ok {
					env.keys[key] = i
				}
				break
			}
		}
	}

	return env
}

// Add adds to the values of the environment variable named by the key.
func (env *Env) Add(key string, values ...string) {
	env.lock.Lock()
	defer env.lock.Unlock()

	value := strings.Join(values, pathListSeparator)

	if i, ok := env.keys[key]; ok {
		env.data[i] += value
	} else {
		env.keys[key] = len(env.data)
		env.data = append(env.data, key+"="+value)
	}
}

// Set sets the value of the environment variable named by the key.
func (env *Env) Set(key string, values ...string) {
	env.lock.Lock()
	defer env.lock.Unlock()

	value := key + "=" + strings.Join(values, pathListSeparator)

	if i, ok := env.keys[key]; ok {
		env.data[i] = value
	} else {
		env.keys[key] = len(env.data)
		env.data = append(env.data, value)
	}
}

// Get retrieves the value of the environment variable named by the given key. The return value will be
// an empty string if the key is not present
func (env *Env) Get(key string) (value string) {
	if i, ok := env.keys[key]; ok {
		value = env.data[i]
		return value[strings.Index(value, "=")+1:]
	}
	return value
}

// Data returns a copy of the slice representing the environment.
func (env *Env) Data() []string {
	return env.data
}

// String return the string representation of Env data
func (env *Env) String() string {
	return strings.Join(env.Data(), "\n")
}
<|endoftext|>


<commit_before>package erasure

/*
#cgo CFLAGS: -Wall -std=gnu99
#include "types.h"
#include "erasure_code.h"
*/
import "C"

import (
	"log"
)

type Code struct {
	M            int
	K            int
	VectorLength int
	EncodeMatrix []byte
	galoisTables []byte
}

func NewCode(m int, k int, size int) *Code {
	if m <= 0 || k <= 0 || k >= m || k > 127 || m > 127 || size < 0 {
		log.Fatal("Invalid erasure code params")
	}
	if size%k != 0 {
		log.Fatal("Size to encode is not divisable by k and therefore cannot be enocded in vector chunks")
	}

	encodeMatrix := make([]byte, m*k)
	galoisTables := make([]byte, k*(m-k)*32)

	if k > 5 {
		C.gf_gen_cauchy1_matrix((*C.uchar)(&encodeMatrix[0]), C.int(m), C.int(k))
	} else {
		C.gf_gen_rs_matrix((*C.uchar)(&encodeMatrix[0]), C.int(m), C.int(k))
	}

	return &Code{
		M:            m,
		K:            k,
		VectorLength: size / k,
		EncodeMatrix: encodeMatrix,
		galoisTables: galoisTables,
	}
}

// Data buffer to encode must be of the k*vector given in the constructor
// The returned encoded buffer is (m-k)*vector, since the first k*vector of the
// encoded data is just the original data due to the identity matrix
func (c *Code) Encode(data []byte) []byte {
	if len(data) != c.K*c.VectorLength {
		log.Fatal("Data to encode is not the proper size")
	}
	// Since the first k row of the encode matrix is actually the identity matrix
	// we only need to encode the last m-k vectors of the matrix and append
	// them to the original data
	encoded := make([]byte, (c.M-c.K)*(c.VectorLength))
	C.ec_init_tables(C.int(c.K), C.int(c.M-c.K), (*C.uchar)(&c.EncodeMatrix[c.K*c.K]), (*C.uchar)(&c.galoisTables[0]))
	C.ec_encode_data(C.int(c.VectorLength), C.int(c.K), C.int(c.M-c.K), (*C.uchar)(&c.galoisTables[0]), (*C.uchar)(&data[0]), (*C.uchar)(&encoded[0]))

	// return append(data, encoded...)
	return encoded
}

// Data buffer to decode must be of the m*vector given in the constructor
// The source error list must contain m-k values, corresponding to the vectors with errors
// The returned decoded data is k*vector
func (c *Code) Decode(encoded []byte, errList []byte) []byte {
	if len(encoded) != c.M*c.VectorLength {
		log.Fatal("Data to decode is not the proper size")
	}
	if len(errList) > c.M-c.K {
		log.Fatal("Too many errors, cannot decode")
	}
	decodeMatrix := make([]byte, c.M*c.K)
	decodeIndex := make([]byte, c.K)
	srcInErr := make([]byte, c.M)
	nErrs := len(errList)
	nSrcErrs := 0
	for _, err := range errList {
		srcInErr[err] = 1
		if int(err) < c.K {
			nSrcErrs++
		}
	}

	C.gf_gen_decode_matrix((*C.uchar)(&c.EncodeMatrix[0]), (*C.uchar)(&decodeMatrix[0]), (*C.uchar)(&decodeIndex[0]), (*C.uchar)(&errList[0]), (*C.uchar)(&srcInErr[0]), C.int(nErrs), C.int(nSrcErrs), C.int(c.K), C.int(c.M))

	C.ec_init_tables(C.int(c.K), C.int(nErrs), (*C.uchar)(&decodeMatrix[0]), (*C.uchar)(&c.galoisTables[0]))

	recovered := []byte{}
	for i := 0; i < c.K; i++ {
		recovered = append(recovered, encoded[(int(decodeIndex[i])*c.VectorLength):int(decodeIndex[i]+1)*c.VectorLength]...)
	}

	decoded := make([]byte, c.M*c.VectorLength)
	C.ec_encode_data(C.int(c.VectorLength), C.int(c.K), C.int(c.M), (*C.uchar)(&c.galoisTables[0]), (*C.uchar)(&recovered[0]), (*C.uchar)(&decoded[0]))

	copy(recovered, encoded)

	for i, err := range errList {
		if int(err) < c.K {
			copy(recovered[int(err)*c.VectorLength:int(err+1)*c.VectorLength], decoded[i*c.VectorLength:(i+1)*c.VectorLength])
		}
	}

	return recovered
}
<commit_msg>Cache encode galois tables<commit_after>package erasure

/*
#cgo CFLAGS: -Wall -std=gnu99
#include "types.h"
#include "erasure_code.h"
*/
import "C"

import (
	"log"
)

type Code struct {
	M                  int
	K                  int
	VectorLength       int
	EncodeMatrix       []byte
	galoisTables       []byte
	decodeGaloisTables []byte
}

func NewCode(m int, k int, size int) *Code {
	if m <= 0 || k <= 0 || k >= m || k > 127 || m > 127 || size < 0 {
		log.Fatal("Invalid erasure code params")
	}
	if size%k != 0 {
		log.Fatal("Size to encode is not divisable by k and therefore cannot be enocded in vector chunks")
	}

	encodeMatrix := make([]byte, m*k)
	galoisTables := make([]byte, k*(m-k)*32)
	decodeGaloisTables := make([]byte, k*(m-k)*32)

	if k > 5 {
		C.gf_gen_cauchy1_matrix((*C.uchar)(&encodeMatrix[0]), C.int(m), C.int(k))
	} else {
		C.gf_gen_rs_matrix((*C.uchar)(&encodeMatrix[0]), C.int(m), C.int(k))
	}

	C.ec_init_tables(C.int(k), C.int(m-k), (*C.uchar)(&encodeMatrix[k*k]), (*C.uchar)(&galoisTables[0]))
	return &Code{
		M:                  m,
		K:                  k,
		VectorLength:       size / k,
		EncodeMatrix:       encodeMatrix,
		galoisTables:       galoisTables,
		decodeGaloisTables: decodeGaloisTables,
	}
}

// Data buffer to encode must be of the k*vector given in the constructor
// The returned encoded buffer is (m-k)*vector, since the first k*vector of the
// encoded data is just the original data due to the identity matrix
func (c *Code) Encode(data []byte) []byte {
	if len(data) != c.K*c.VectorLength {
		log.Fatal("Data to encode is not the proper size")
	}
	// Since the first k row of the encode matrix is actually the identity matrix
	// we only need to encode the last m-k vectors of the matrix and append
	// them to the original data
	encoded := make([]byte, (c.M-c.K)*(c.VectorLength))
	C.ec_encode_data(C.int(c.VectorLength), C.int(c.K), C.int(c.M-c.K), (*C.uchar)(&c.galoisTables[0]), (*C.uchar)(&data[0]), (*C.uchar)(&encoded[0]))
	// return append(data, encoded...)
	return encoded
}

// Data buffer to decode must be of the m*vector given in the constructor
// The source error list must contain m-k values, corresponding to the vectors with errors
// The returned decoded data is k*vector
func (c *Code) Decode(encoded []byte, errList []byte) []byte {
	if len(encoded) != c.M*c.VectorLength {
		log.Fatal("Data to decode is not the proper size")
	}
	if len(errList) > c.M-c.K {
		log.Fatal("Too many errors, cannot decode")
	}
	decodeMatrix := make([]byte, c.M*c.K)
	decodeIndex := make([]byte, c.K)
	srcInErr := make([]byte, c.M)
	nErrs := len(errList)
	nSrcErrs := 0
	for _, err := range errList {
		srcInErr[err] = 1
		if int(err) < c.K {
			nSrcErrs++
		}
	}

	C.gf_gen_decode_matrix((*C.uchar)(&c.EncodeMatrix[0]), (*C.uchar)(&decodeMatrix[0]), (*C.uchar)(&decodeIndex[0]), (*C.uchar)(&errList[0]), (*C.uchar)(&srcInErr[0]), C.int(nErrs), C.int(nSrcErrs), C.int(c.K), C.int(c.M))

	C.ec_init_tables(C.int(c.K), C.int(nErrs), (*C.uchar)(&decodeMatrix[0]), (*C.uchar)(&c.decodeGaloisTables[0]))

	recovered := []byte{}
	for i := 0; i < c.K; i++ {
		recovered = append(recovered, encoded[(int(decodeIndex[i])*c.VectorLength):int(decodeIndex[i]+1)*c.VectorLength]...)
	}

	decoded := make([]byte, c.M*c.VectorLength)
	C.ec_encode_data(C.int(c.VectorLength), C.int(c.K), C.int(c.M), (*C.uchar)(&c.decodeGaloisTables[0]), (*C.uchar)(&recovered[0]), (*C.uchar)(&decoded[0]))

	copy(recovered, encoded)

	for i, err := range errList {
		if int(err) < c.K {
			copy(recovered[int(err)*c.VectorLength:int(err+1)*c.VectorLength], decoded[i*c.VectorLength:(i+1)*c.VectorLength])
		}
	}

	return recovered
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/hex"
	"errors"
	"fmt"
	"github.com/uavionix/serial"
	"log"
	"unsafe"
)

/*

#cgo LDFLAGS: -ldump978

#include <stdint.h>
#include "../dump978/fec.h"

*/
import "C"

var radioSerialConfig *serial.Config
var radioSerialPort *serial.Port

func initUATRadioSerial() error {
	// Init for FEC routines.
	C.init_fec()
	// Initialize port at 2Mbaud.
	radioSerialConfig = &serial.Config{Name: "/dev/uatradio", Baud: 2000000}
	p, err := serial.OpenPort(radioSerialConfig)
	if err != nil {
		log.Printf("serial port err: %s\n", err.Error())
		return errors.New("serial port failed to initialize")
	}

	radioSerialPort = p

	// Start a goroutine to watch the serial port.
	go radioSerialPortReader()
	return nil
}

/*
	radioSerialPortReader().
	 Loop to read data from the radio serial port.
*/
var radioMagic = []byte{0x0a, 0xb0, 0xcd, 0xe0}

func radioSerialPortReader() {
	tmpBuf := make([]byte, 1024) // Read buffer.
	var buf []byte               // Message buffer.
	if radioSerialPort == nil {
		return
	}
	defer radioSerialPort.Close()
	for {
		n, err := radioSerialPort.Read(tmpBuf)
		if err != nil {
			log.Printf("serial port err, shutting down radio: %s\n", err.Error())
			return
		}
		buf = append(buf, tmpBuf[:n]...)
		bufLen := len(buf)
		var finBuf []byte   // Truncated buffer, with processed messages extracted.
		var numMessages int // Number of messages extracted.
		// Search for a suitable message to extract.
		for i := 0; i < bufLen-6; i++ {
			if (buf[i] == radioMagic[0]) && (buf[i+1] == radioMagic[1]) && (buf[i+2] == radioMagic[2]) && (buf[i+3] == radioMagic[3]) {
				// Found the magic sequence. Get the length.
				msgLen := int(uint16(buf[i+4])+(uint16(buf[i+5])<<8)) + 5 // 5 bytes for RSSI and TS.
				// Check if we've read enough to finish this message.
				if bufLen < i+6+msgLen {
					break // Wait for more of the message to come in.
				}
				// Message is long enough.
				processRadioMessage(buf[i+6 : i+6+msgLen])
				// Remove everything in the buffer before this message.
				finBuf = buf[i+6+msgLen:]
				numMessages++
			}
		}
		if numMessages > 0 {
			buf = finBuf
		}
	}
}

/*
	processRadioMessage().
	 Processes a single message from the radio. De-interleaves (when necessary), checks Reed-Solomon, passes to main process.
*/

func processRadioMessage(msg []byte) {
	log.Printf("processRadioMessage(): %d %s\n", len(msg), hex.EncodeToString(msg))

	// RSSI and message timestamp are prepended to the actual packet.

	// RSSI
	rssiRaw := int8(msg[0])
	//rssiAdjusted := int16(rssiRaw) - 132 // -132 dBm, calculated minimum RSSI.
	//rssiDump978 := int16(1000 * (10 ^ (float64(rssiAdjusted) / 20)))
	rssiDump978 := rssiRaw

	//_ := uint32(msg[1]) + (uint32(msg[2]) << 8) + (uint32(msg[3]) << 16) + (uint32(msg[4]) << 24) // Timestamp. Currently unused.

	msg = msg[5:]

	var toRelay string
	var rs_errors int
	switch len(msg) {
	case 552:
		to := make([]byte, 552)
		i := int(C.correct_uplink_frame((*C.uint8_t)(unsafe.Pointer(&msg[0])), (*C.uint8_t)(unsafe.Pointer(&to[0])), (*C.int)(unsafe.Pointer(&rs_errors))))
		toRelay = fmt.Sprintf("+%s;ss=%d;", hex.EncodeToString(to[:432]), rssiDump978)
		log.Printf("i=%d, rs_errors=%d, msg=%s\n", i, rs_errors, toRelay)
	case 48:
		to := make([]byte, 48)
		copy(to, msg)
		i := int(C.correct_adsb_frame((*C.uint8_t)(unsafe.Pointer(&to[0])), (*C.int)(unsafe.Pointer(&rs_errors))))
		if i == 1 {
			// Short ADS-B frame.
			toRelay = fmt.Sprintf("-%s;ss=%d;", hex.EncodeToString(to[:18]), rssiDump978)
			log.Printf("i=%d, rs_errors=%d, msg=%s\n", i, rs_errors, toRelay)
		} else if i == 2 {
			// Long ADS-B frame.
			toRelay = fmt.Sprintf("-%s;ss=%d;", hex.EncodeToString(to[:34]), rssiDump978)
			log.Printf("i=%d, rs_errors=%d, msg=%s\n", i, rs_errors, toRelay)
		} else {
			log.Printf("i=%d, rs_errors=%d, msg=%s\n", i, rs_errors, hex.EncodeToString(to))
		}
	default:
		log.Printf("processRadioMessage(): unhandled message size %d\n", len(msg))
	}

	if len(toRelay) > 0 && rs_errors != 9999 {
		o, msgtype := parseInput(toRelay)
		if o != nil && msgtype != 0 {
			relayMessage(msgtype, o)
		}
	}
}
<commit_msg>Change to stratux/serial.<commit_after>package main

import (
	"encoding/hex"
	"errors"
	"fmt"
	"github.com/stratux/serial"
	"log"
	"unsafe"
)

/*

#cgo LDFLAGS: -ldump978

#include <stdint.h>
#include "../dump978/fec.h"

*/
import "C"

var radioSerialConfig *serial.Config
var radioSerialPort *serial.Port

func initUATRadioSerial() error {
	// Init for FEC routines.
	C.init_fec()
	// Initialize port at 2Mbaud.
	radioSerialConfig = &serial.Config{Name: "/dev/uatradio", Baud: 2000000}
	p, err := serial.OpenPort(radioSerialConfig)
	if err != nil {
		log.Printf("serial port err: %s\n", err.Error())
		return errors.New("serial port failed to initialize")
	}

	radioSerialPort = p

	// Start a goroutine to watch the serial port.
	go radioSerialPortReader()
	return nil
}

/*
	radioSerialPortReader().
	 Loop to read data from the radio serial port.
*/
var radioMagic = []byte{0x0a, 0xb0, 0xcd, 0xe0}

func radioSerialPortReader() {
	tmpBuf := make([]byte, 1024) // Read buffer.
	var buf []byte               // Message buffer.
	if radioSerialPort == nil {
		return
	}
	defer radioSerialPort.Close()
	for {
		n, err := radioSerialPort.Read(tmpBuf)
		if err != nil {
			log.Printf("serial port err, shutting down radio: %s\n", err.Error())
			return
		}
		buf = append(buf, tmpBuf[:n]...)
		bufLen := len(buf)
		var finBuf []byte   // Truncated buffer, with processed messages extracted.
		var numMessages int // Number of messages extracted.
		// Search for a suitable message to extract.
		for i := 0; i < bufLen-6; i++ {
			if (buf[i] == radioMagic[0]) && (buf[i+1] == radioMagic[1]) && (buf[i+2] == radioMagic[2]) && (buf[i+3] == radioMagic[3]) {
				// Found the magic sequence. Get the length.
				msgLen := int(uint16(buf[i+4])+(uint16(buf[i+5])<<8)) + 5 // 5 bytes for RSSI and TS.
				// Check if we've read enough to finish this message.
				if bufLen < i+6+msgLen {
					break // Wait for more of the message to come in.
				}
				// Message is long enough.
				processRadioMessage(buf[i+6 : i+6+msgLen])
				// Remove everything in the buffer before this message.
				finBuf = buf[i+6+msgLen:]
				numMessages++
			}
		}
		if numMessages > 0 {
			buf = finBuf
		}
	}
}

/*
	processRadioMessage().
	 Processes a single message from the radio. De-interleaves (when necessary), checks Reed-Solomon, passes to main process.
*/

func processRadioMessage(msg []byte) {
	log.Printf("processRadioMessage(): %d %s\n", len(msg), hex.EncodeToString(msg))

	// RSSI and message timestamp are prepended to the actual packet.

	// RSSI
	rssiRaw := int8(msg[0])
	//rssiAdjusted := int16(rssiRaw) - 132 // -132 dBm, calculated minimum RSSI.
	//rssiDump978 := int16(1000 * (10 ^ (float64(rssiAdjusted) / 20)))
	rssiDump978 := rssiRaw

	//_ := uint32(msg[1]) + (uint32(msg[2]) << 8) + (uint32(msg[3]) << 16) + (uint32(msg[4]) << 24) // Timestamp. Currently unused.

	msg = msg[5:]

	var toRelay string
	var rs_errors int
	switch len(msg) {
	case 552:
		to := make([]byte, 552)
		i := int(C.correct_uplink_frame((*C.uint8_t)(unsafe.Pointer(&msg[0])), (*C.uint8_t)(unsafe.Pointer(&to[0])), (*C.int)(unsafe.Pointer(&rs_errors))))
		toRelay = fmt.Sprintf("+%s;ss=%d;", hex.EncodeToString(to[:432]), rssiDump978)
		log.Printf("i=%d, rs_errors=%d, msg=%s\n", i, rs_errors, toRelay)
	case 48:
		to := make([]byte, 48)
		copy(to, msg)
		i := int(C.correct_adsb_frame((*C.uint8_t)(unsafe.Pointer(&to[0])), (*C.int)(unsafe.Pointer(&rs_errors))))
		if i == 1 {
			// Short ADS-B frame.
			toRelay = fmt.Sprintf("-%s;ss=%d;", hex.EncodeToString(to[:18]), rssiDump978)
			log.Printf("i=%d, rs_errors=%d, msg=%s\n", i, rs_errors, toRelay)
		} else if i == 2 {
			// Long ADS-B frame.
			toRelay = fmt.Sprintf("-%s;ss=%d;", hex.EncodeToString(to[:34]), rssiDump978)
			log.Printf("i=%d, rs_errors=%d, msg=%s\n", i, rs_errors, toRelay)
		} else {
			log.Printf("i=%d, rs_errors=%d, msg=%s\n", i, rs_errors, hex.EncodeToString(to))
		}
	default:
		log.Printf("processRadioMessage(): unhandled message size %d\n", len(msg))
	}

	if len(toRelay) > 0 && rs_errors != 9999 {
		o, msgtype := parseInput(toRelay)
		if o != nil && msgtype != 0 {
			relayMessage(msgtype, o)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/tls"
	"crypto/x509"
	"encoding/pem"
	"flag"
	"github.com/KIT-MAMID/mamid/master"
	"github.com/KIT-MAMID/mamid/master/masterapi"
	"github.com/KIT-MAMID/mamid/model"
	"github.com/KIT-MAMID/mamid/msp"
	"github.com/Sirupsen/logrus"
	"github.com/gorilla/mux"
	"io/ioutil"
	"net/http"
	"time"
)

var masterLog = logrus.WithField("module", "master")

type LogLevelFlag struct {
	// flag.Value
	lvl logrus.Level
}

func (f LogLevelFlag) String() string {
	return f.lvl.String()
}
func (f LogLevelFlag) Set(val string) error {
	l, err := logrus.ParseLevel(val)
	if err != nil {
		f.lvl = l
	}
	return err
}

func main() {

	// Command Line Flags
	var (
		logLevel                                                    LogLevelFlag = LogLevelFlag{logrus.DebugLevel}
		dbPath, listenString                                        string
		rootCA, clientCert, clientKey, apiCert, apiKey, apiVerifyCA string
		dbDriver, dbDSN                                             string
		monitorInterval                                             time.Duration
	)

	flag.Var(&logLevel, "log.level", "possible values: debug, info, warning, error, fatal, panic")
	flag.StringVar(&dbPath, "db.path", "", "path to the SQLite file where MAMID data is stored")
	flag.StringVar(&dbDriver, "db.driver", "postgres", "the database driver to use. See https://golang.org/pkg/database/sql/#Open")
	flag.StringVar(&dbDSN, "db.dsn", "", "the data source name to use. for PostgreSQL, checkout https://godoc.org/github.com/lib/pq")
	flag.StringVar(&listenString, "listen", ":8080", "net.Listen() string, e.g. addr:port")
	flag.StringVar(&rootCA, "cacert", "", "The CA certificate to verify slaves against it")
	flag.StringVar(&clientCert, "clientCert", "", "The client certificate for authentication against the slave")
	flag.StringVar(&clientKey, "clientKey", "", "The key for the client certificate for authentication against the slave")
	flag.StringVar(&apiCert, "apiCert", "", "Optional: a certificate for the api/webinterface")
	flag.StringVar(&apiKey, "apiKey", "", "Optional: the for the certificate for the api/webinterface")
	flag.StringVar(&apiVerifyCA, "apiVerifyCA", "", "Optional: a ca, to check client certs from webinterface/api users. Implies authentication.")

	flag.DurationVar(&monitorInterval, "monitor.interval", time.Duration(10*time.Second),
		"Interval in which the monitoring component should poll slaves for status updates. Specify with suffix [ms,s,min,...]")
	flag.Parse()

	if dbDriver != "postgres" {
		masterLog.Fatal("-db.driver: only 'postgres' is supported")
	}
	if dbDSN == "" {
		masterLog.Fatal("-db.dsn cannot be empty")
	}
	if rootCA == "" {
		masterLog.Fatal("No root certificate for the slave server communication passed. Specify with -cacert")
	}
	if clientCert == "" {
		masterLog.Fatal("No client certificate for the slave server communication passed. Specify with -clientCert")
	}
	if clientKey == "" {
		masterLog.Fatal("No key for the client certificate for the slave server communication passed. Specify with -clientKey")
	}
	if check := apiKey + apiCert; check == apiKey || check == apiCert {
		masterLog.Fatal("Either -apiCert specified without -apiKey or vice versa.")
	}
	// Start application
	logrus.SetLevel(logLevel.lvl)
	masterLog.Info("Startup")

	// Setup controllers

	bus := master.NewBus()
	go bus.Run()

	db, err := model.InitializeDB(dbDriver, dbDSN)
	dieOnError(err)

	clusterAllocatorBusWriteChannel := bus.GetNewWriteChannel()
	clusterAllocator := &master.ClusterAllocator{
		BusWriteChannel: &clusterAllocatorBusWriteChannel,
	}
	go clusterAllocator.Run(db)

	mainRouter := mux.NewRouter().StrictSlash(true)

	httpStatic := http.FileServer(http.Dir("./gui/"))
	mainRouter.Handle("/", httpStatic)
	mainRouter.PathPrefix("/static/").Handler(httpStatic)
	mainRouter.PathPrefix("/pages/").Handler(httpStatic)

	masterAPI := &masterapi.MasterAPI{
		DB:               db,
		ClusterAllocator: clusterAllocator,
		Router:           mainRouter.PathPrefix("/api/").Subrouter(),
	}
	masterAPI.Setup()

	certPool := x509.NewCertPool()
	cert, err := loadCertificateFromFile(rootCA)
	dieOnError(err)
	certPool.AddCert(cert)
	clientAuthCert, err := tls.LoadX509KeyPair(clientCert, clientKey)
	dieOnError(err)
	httpTransport := &http.Transport{
		TLSClientConfig: &tls.Config{
			RootCAs:      certPool,
			Certificates: []tls.Certificate{clientAuthCert},
		},
	}
	mspClient := msp.MSPClientImpl{HttpClient: http.Client{Transport: httpTransport}}

	monitor := master.Monitor{
		DB:              db,
		BusWriteChannel: bus.GetNewWriteChannel(),
		MSPClient:       mspClient,
		Interval:        monitorInterval,
	}
	go monitor.Run()

	deployer := master.Deployer{
		DB:             db,
		BusReadChannel: bus.GetNewReadChannel(),
		MSPClient:      mspClient,
	}
	go deployer.Run()

	problemManager := master.ProblemManager{
		DB:             db,
		BusReadChannel: bus.GetNewReadChannel(),
	}
	go problemManager.Run()

	// Listen
	if apiCert != "" {
		err = http.ListenAndServeTLS(listenString, apiCert, apiKey, mainRouter)
	} else {
		err = http.ListenAndServe(listenString, mainRouter)
	}
	dieOnError(err)
}

func dieOnError(err error) {
	if err != nil {
		panic(err)
	}
}

func loadCertificateFromFile(file string) (cert *x509.Certificate, err error) {
	certFile, err := ioutil.ReadFile(file)
	if err != nil {
		return
	}
	block, _ := pem.Decode(certFile)
	cert, err = x509.ParseCertificate(block.Bytes)
	return
}
<commit_msg>ADD: master: client cert auth for the web interface + api<commit_after>package main

import (
	"crypto/tls"
	"crypto/x509"
	"encoding/pem"
	"flag"
	"github.com/KIT-MAMID/mamid/master"
	"github.com/KIT-MAMID/mamid/master/masterapi"
	"github.com/KIT-MAMID/mamid/model"
	"github.com/KIT-MAMID/mamid/msp"
	"github.com/Sirupsen/logrus"
	"github.com/gorilla/mux"
	"io/ioutil"
	"net/http"
	"time"
)

var masterLog = logrus.WithField("module", "master")

type LogLevelFlag struct {
	// flag.Value
	lvl logrus.Level
}

func (f LogLevelFlag) String() string {
	return f.lvl.String()
}
func (f LogLevelFlag) Set(val string) error {
	l, err := logrus.ParseLevel(val)
	if err != nil {
		f.lvl = l
	}
	return err
}

func main() {

	// Command Line Flags
	var (
		logLevel                                                    LogLevelFlag = LogLevelFlag{logrus.DebugLevel}
		dbPath, listenString                                        string
		rootCA, clientCert, clientKey, apiCert, apiKey, apiVerifyCA string
		dbDriver, dbDSN                                             string
		monitorInterval                                             time.Duration
	)

	flag.Var(&logLevel, "log.level", "possible values: debug, info, warning, error, fatal, panic")
	flag.StringVar(&dbPath, "db.path", "", "path to the SQLite file where MAMID data is stored")
	flag.StringVar(&dbDriver, "db.driver", "postgres", "the database driver to use. See https://golang.org/pkg/database/sql/#Open")
	flag.StringVar(&dbDSN, "db.dsn", "", "the data source name to use. for PostgreSQL, checkout https://godoc.org/github.com/lib/pq")
	flag.StringVar(&listenString, "listen", ":8080", "net.Listen() string, e.g. addr:port")
	flag.StringVar(&rootCA, "cacert", "", "The CA certificate to verify slaves against it")
	flag.StringVar(&clientCert, "clientCert", "", "The client certificate for authentication against the slave")
	flag.StringVar(&clientKey, "clientKey", "", "The key for the client certificate for authentication against the slave")
	flag.StringVar(&apiCert, "apiCert", "", "Optional: a certificate for the api/webinterface")
	flag.StringVar(&apiKey, "apiKey", "", "Optional: the for the certificate for the api/webinterface")
	flag.StringVar(&apiVerifyCA, "apiVerifyCA", "", "Optional: a ca, to check client certs from webinterface/api users. Implies authentication.")

	flag.DurationVar(&monitorInterval, "monitor.interval", time.Duration(10*time.Second),
		"Interval in which the monitoring component should poll slaves for status updates. Specify with suffix [ms,s,min,...]")
	flag.Parse()

	if dbDriver != "postgres" {
		masterLog.Fatal("-db.driver: only 'postgres' is supported")
	}
	if dbDSN == "" {
		masterLog.Fatal("-db.dsn cannot be empty")
	}
	if rootCA == "" {
		masterLog.Fatal("No root certificate for the slave server communication passed. Specify with -cacert")
	}
	if clientCert == "" {
		masterLog.Fatal("No client certificate for the slave server communication passed. Specify with -clientCert")
	}
	if clientKey == "" {
		masterLog.Fatal("No key for the client certificate for the slave server communication passed. Specify with -clientKey")
	}
	if check := apiKey + apiCert; check != "" && (check == apiKey || check == apiCert) {
		masterLog.Fatal("Either -apiCert specified without -apiKey or vice versa.")
	}
	// Start application
	logrus.SetLevel(logLevel.lvl)
	masterLog.Info("Startup")

	// Setup controllers

	bus := master.NewBus()
	go bus.Run()

	db, err := model.InitializeDB(dbDriver, dbDSN)
	dieOnError(err)

	clusterAllocatorBusWriteChannel := bus.GetNewWriteChannel()
	clusterAllocator := &master.ClusterAllocator{
		BusWriteChannel: &clusterAllocatorBusWriteChannel,
	}
	go clusterAllocator.Run(db)

	mainRouter := mux.NewRouter().StrictSlash(true)

	httpStatic := http.FileServer(http.Dir("./gui/"))
	mainRouter.Handle("/", httpStatic)
	mainRouter.PathPrefix("/static/").Handler(httpStatic)
	mainRouter.PathPrefix("/pages/").Handler(httpStatic)

	masterAPI := &masterapi.MasterAPI{
		DB:               db,
		ClusterAllocator: clusterAllocator,
		Router:           mainRouter.PathPrefix("/api/").Subrouter(),
	}
	masterAPI.Setup()

	certPool := x509.NewCertPool()
	cert, err := loadCertificateFromFile(rootCA)
	dieOnError(err)
	certPool.AddCert(cert)
	clientAuthCert, err := tls.LoadX509KeyPair(clientCert, clientKey)
	dieOnError(err)
	httpTransport := &http.Transport{
		TLSClientConfig: &tls.Config{
			RootCAs:      certPool,
			Certificates: []tls.Certificate{clientAuthCert},
		},
	}
	mspClient := msp.MSPClientImpl{HttpClient: http.Client{Transport: httpTransport}}

	monitor := master.Monitor{
		DB:              db,
		BusWriteChannel: bus.GetNewWriteChannel(),
		MSPClient:       mspClient,
		Interval:        monitorInterval,
	}
	go monitor.Run()

	deployer := master.Deployer{
		DB:             db,
		BusReadChannel: bus.GetNewReadChannel(),
		MSPClient:      mspClient,
	}
	go deployer.Run()

	problemManager := master.ProblemManager{
		DB:             db,
		BusReadChannel: bus.GetNewReadChannel(),
	}
	go problemManager.Run()

	listenAndServe(listenString, mainRouter, apiCert, apiKey, apiVerifyCA)
}

func dieOnError(err error) {
	if err != nil {
		panic(err)
	}
}

func loadCertificateFromFile(file string) (cert *x509.Certificate, err error) {
	certFile, err := ioutil.ReadFile(file)
	if err != nil {
		return
	}
	block, _ := pem.Decode(certFile)
	cert, err = x509.ParseCertificate(block.Bytes)
	return
}

func listenAndServe(listenString string, mainRouter *mux.Router, apiCert string, apiKey string, apiVerifyCA string) {
	// Listen...
	if apiCert != "" {
		// ...with TLS but WITHOUT client cert auth
		if apiVerifyCA == "" {
			err := http.ListenAndServeTLS(listenString, apiCert, apiKey, mainRouter)
			dieOnError(err)
		} else { // ...with TLS AND client cert auth
			certPool := x509.NewCertPool()
			caCertContent, err := ioutil.ReadFile(apiVerifyCA)
			dieOnError(err)
			certPool.AppendCertsFromPEM(caCertContent)
			tlsConfig := &tls.Config{
				ClientCAs:  certPool,
				ClientAuth: tls.RequireAndVerifyClientCert,
			}
			server := &http.Server{
				TLSConfig: tlsConfig,
				Addr:      listenString,
				Handler:   mainRouter,
			}
			err = server.ListenAndServeTLS(apiCert, apiKey)
			dieOnError(err)
		}
	} else {
		// ...insecure and unauthenticated
		err := http.ListenAndServe(listenString, mainRouter)
		dieOnError(err)
	}
}
<|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.

package gc

import (
	"cmd/compile/internal/base"
	"cmd/compile/internal/ssa"
	"cmd/compile/internal/types"
	"cmd/internal/obj"
	"cmd/internal/src"
	"sync"
)

const (
	BADWIDTH = types.BADWIDTH
)

var (
	// maximum size variable which we will allocate on the stack.
	// This limit is for explicit variable declarations like "var x T" or "x := ...".
	// Note: the flag smallframes can update this value.
	maxStackVarSize = int64(10 * 1024 * 1024)

	// maximum size of implicit variables that we will allocate on the stack.
	//   p := new(T)          allocating T on the stack
	//   p := &T{}            allocating T on the stack
	//   s := make([]T, n)    allocating [n]T on the stack
	//   s := []byte("...")   allocating [n]byte on the stack
	// Note: the flag smallframes can update this value.
	maxImplicitStackVarSize = int64(64 * 1024)

	// smallArrayBytes is the maximum size of an array which is considered small.
	// Small arrays will be initialized directly with a sequence of constant stores.
	// Large arrays will be initialized by copying from a static temp.
	// 256 bytes was chosen to minimize generated code + statictmp size.
	smallArrayBytes = int64(256)
)

// isRuntimePkg reports whether p is package runtime.
func isRuntimePkg(p *types.Pkg) bool {
	if base.Flag.CompilingRuntime && p == localpkg {
		return true
	}
	return p.Path == "runtime"
}

// isReflectPkg reports whether p is package reflect.
func isReflectPkg(p *types.Pkg) bool {
	if p == localpkg {
		return base.Ctxt.Pkgpath == "reflect"
	}
	return p.Path == "reflect"
}

// The Class of a variable/function describes the "storage class"
// of a variable or function. During parsing, storage classes are
// called declaration contexts.
type Class uint8

//go:generate stringer -type=Class
const (
	Pxxx      Class = iota // no class; used during ssa conversion to indicate pseudo-variables
	PEXTERN                // global variables
	PAUTO                  // local variables
	PAUTOHEAP              // local variables or parameters moved to heap
	PPARAM                 // input arguments
	PPARAMOUT              // output results
	PFUNC                  // global functions

	// Careful: Class is stored in three bits in Node.flags.
	_ = uint((1 << 3) - iota) // static assert for iota <= (1 << 3)
)

// Slices in the runtime are represented by three components:
//
// type slice struct {
// 	ptr unsafe.Pointer
// 	len int
// 	cap int
// }
//
// Strings in the runtime are represented by two components:
//
// type string struct {
// 	ptr unsafe.Pointer
// 	len int
// }
//
// These variables are the offsets of fields and sizes of these structs.
var (
	slicePtrOffset int64
	sliceLenOffset int64
	sliceCapOffset int64

	sizeofSlice  int64
	sizeofString int64
)

var pragcgobuf [][]string

var decldepth int32

var localpkg *types.Pkg // package being compiled

var inimport bool // set during import

var itabpkg *types.Pkg // fake pkg for itab entries

var itablinkpkg *types.Pkg // fake package for runtime itab entries

var Runtimepkg *types.Pkg // fake package runtime

var racepkg *types.Pkg // package runtime/race

var msanpkg *types.Pkg // package runtime/msan

var unsafepkg *types.Pkg // package unsafe

var trackpkg *types.Pkg // fake package for field tracking

var mappkg *types.Pkg // fake package for map zero value

var gopkg *types.Pkg // pseudo-package for method symbols on anonymous receiver types

var zerosize int64

var simtype [NTYPE]types.EType

var (
	isInt     [NTYPE]bool
	isFloat   [NTYPE]bool
	isComplex [NTYPE]bool
	issimple  [NTYPE]bool
)

var (
	okforeq    [NTYPE]bool
	okforadd   [NTYPE]bool
	okforand   [NTYPE]bool
	okfornone  [NTYPE]bool
	okforcmp   [NTYPE]bool
	okforbool  [NTYPE]bool
	okforcap   [NTYPE]bool
	okforlen   [NTYPE]bool
	okforarith [NTYPE]bool
	okforconst [NTYPE]bool
)

var (
	okfor [OEND][]bool
	iscmp [OEND]bool
)

var xtop []*Node

var exportlist []*Node

var importlist []*Node // imported functions and methods with inlinable bodies

var (
	funcsymsmu sync.Mutex // protects funcsyms and associated package lookups (see func funcsym)
	funcsyms   []*types.Sym
)

var dclcontext Class // PEXTERN/PAUTO

var Curfn *Node

var Widthptr int

var Widthreg int

var nblank *Node

var typecheckok bool

// Whether we are adding any sort of code instrumentation, such as
// when the race detector is enabled.
var instrumenting bool

// Whether we are tracking lexical scopes for DWARF.
var trackScopes bool

var nodfp *Node

var autogeneratedPos src.XPos

// interface to back end

type Arch struct {
	LinkArch *obj.LinkArch

	REGSP     int
	MAXWIDTH  int64
	SoftFloat bool

	PadFrame func(int64) int64

	// ZeroRange zeroes a range of memory on stack. It is only inserted
	// at function entry, and it is ok to clobber registers.
	ZeroRange func(*Progs, *obj.Prog, int64, int64, *uint32) *obj.Prog

	Ginsnop      func(*Progs) *obj.Prog
	Ginsnopdefer func(*Progs) *obj.Prog // special ginsnop for deferreturn

	// SSAMarkMoves marks any MOVXconst ops that need to avoid clobbering flags.
	SSAMarkMoves func(*SSAGenState, *ssa.Block)

	// SSAGenValue emits Prog(s) for the Value.
	SSAGenValue func(*SSAGenState, *ssa.Value)

	// SSAGenBlock emits end-of-block Progs. SSAGenValue should be called
	// for all values in the block before SSAGenBlock.
	SSAGenBlock func(s *SSAGenState, b, next *ssa.Block)
}

var thearch Arch

var (
	staticuint64s,
	zerobase *Node

	assertE2I,
	assertE2I2,
	assertI2I,
	assertI2I2,
	deferproc,
	deferprocStack,
	Deferreturn,
	Duffcopy,
	Duffzero,
	gcWriteBarrier,
	goschedguarded,
	growslice,
	msanread,
	msanwrite,
	newobject,
	newproc,
	panicdivide,
	panicshift,
	panicdottypeE,
	panicdottypeI,
	panicnildottype,
	panicoverflow,
	raceread,
	racereadrange,
	racewrite,
	racewriterange,
	x86HasPOPCNT,
	x86HasSSE41,
	x86HasFMA,
	armHasVFPv4,
	arm64HasATOMICS,
	typedmemclr,
	typedmemmove,
	Udiv,
	writeBarrier,
	zerobaseSym *obj.LSym

	BoundsCheckFunc [ssa.BoundsKindCount]*obj.LSym
	ExtendCheckFunc [ssa.BoundsKindCount]*obj.LSym

	// Wasm
	WasmMove,
	WasmZero,
	WasmDiv,
	WasmTruncS,
	WasmTruncU,
	SigPanic *obj.LSym
)

// GCWriteBarrierReg maps from registers to gcWriteBarrier implementation LSyms.
var GCWriteBarrierReg map[int16]*obj.LSym
<commit_msg>[dev.regabi] cmd/compile: move okforconst into its own declaration<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.

package gc

import (
	"cmd/compile/internal/base"
	"cmd/compile/internal/ssa"
	"cmd/compile/internal/types"
	"cmd/internal/obj"
	"cmd/internal/src"
	"sync"
)

const (
	BADWIDTH = types.BADWIDTH
)

var (
	// maximum size variable which we will allocate on the stack.
	// This limit is for explicit variable declarations like "var x T" or "x := ...".
	// Note: the flag smallframes can update this value.
	maxStackVarSize = int64(10 * 1024 * 1024)

	// maximum size of implicit variables that we will allocate on the stack.
	//   p := new(T)          allocating T on the stack
	//   p := &T{}            allocating T on the stack
	//   s := make([]T, n)    allocating [n]T on the stack
	//   s := []byte("...")   allocating [n]byte on the stack
	// Note: the flag smallframes can update this value.
	maxImplicitStackVarSize = int64(64 * 1024)

	// smallArrayBytes is the maximum size of an array which is considered small.
	// Small arrays will be initialized directly with a sequence of constant stores.
	// Large arrays will be initialized by copying from a static temp.
	// 256 bytes was chosen to minimize generated code + statictmp size.
	smallArrayBytes = int64(256)
)

// isRuntimePkg reports whether p is package runtime.
func isRuntimePkg(p *types.Pkg) bool {
	if base.Flag.CompilingRuntime && p == localpkg {
		return true
	}
	return p.Path == "runtime"
}

// isReflectPkg reports whether p is package reflect.
func isReflectPkg(p *types.Pkg) bool {
	if p == localpkg {
		return base.Ctxt.Pkgpath == "reflect"
	}
	return p.Path == "reflect"
}

// The Class of a variable/function describes the "storage class"
// of a variable or function. During parsing, storage classes are
// called declaration contexts.
type Class uint8

//go:generate stringer -type=Class
const (
	Pxxx      Class = iota // no class; used during ssa conversion to indicate pseudo-variables
	PEXTERN                // global variables
	PAUTO                  // local variables
	PAUTOHEAP              // local variables or parameters moved to heap
	PPARAM                 // input arguments
	PPARAMOUT              // output results
	PFUNC                  // global functions

	// Careful: Class is stored in three bits in Node.flags.
	_ = uint((1 << 3) - iota) // static assert for iota <= (1 << 3)
)

// Slices in the runtime are represented by three components:
//
// type slice struct {
// 	ptr unsafe.Pointer
// 	len int
// 	cap int
// }
//
// Strings in the runtime are represented by two components:
//
// type string struct {
// 	ptr unsafe.Pointer
// 	len int
// }
//
// These variables are the offsets of fields and sizes of these structs.
var (
	slicePtrOffset int64
	sliceLenOffset int64
	sliceCapOffset int64

	sizeofSlice  int64
	sizeofString int64
)

var pragcgobuf [][]string

var decldepth int32

var localpkg *types.Pkg // package being compiled

var inimport bool // set during import

var itabpkg *types.Pkg // fake pkg for itab entries

var itablinkpkg *types.Pkg // fake package for runtime itab entries

var Runtimepkg *types.Pkg // fake package runtime

var racepkg *types.Pkg // package runtime/race

var msanpkg *types.Pkg // package runtime/msan

var unsafepkg *types.Pkg // package unsafe

var trackpkg *types.Pkg // fake package for field tracking

var mappkg *types.Pkg // fake package for map zero value

var gopkg *types.Pkg // pseudo-package for method symbols on anonymous receiver types

var zerosize int64

var simtype [NTYPE]types.EType

var (
	isInt     [NTYPE]bool
	isFloat   [NTYPE]bool
	isComplex [NTYPE]bool
	issimple  [NTYPE]bool
)

var (
	okforeq    [NTYPE]bool
	okforadd   [NTYPE]bool
	okforand   [NTYPE]bool
	okfornone  [NTYPE]bool
	okforcmp   [NTYPE]bool
	okforbool  [NTYPE]bool
	okforcap   [NTYPE]bool
	okforlen   [NTYPE]bool
	okforarith [NTYPE]bool
)

var okforconst [NTYPE]bool

var (
	okfor [OEND][]bool
	iscmp [OEND]bool
)

var xtop []*Node

var exportlist []*Node

var importlist []*Node // imported functions and methods with inlinable bodies

var (
	funcsymsmu sync.Mutex // protects funcsyms and associated package lookups (see func funcsym)
	funcsyms   []*types.Sym
)

var dclcontext Class // PEXTERN/PAUTO

var Curfn *Node

var Widthptr int

var Widthreg int

var nblank *Node

var typecheckok bool

// Whether we are adding any sort of code instrumentation, such as
// when the race detector is enabled.
var instrumenting bool

// Whether we are tracking lexical scopes for DWARF.
var trackScopes bool

var nodfp *Node

var autogeneratedPos src.XPos

// interface to back end

type Arch struct {
	LinkArch *obj.LinkArch

	REGSP     int
	MAXWIDTH  int64
	SoftFloat bool

	PadFrame func(int64) int64

	// ZeroRange zeroes a range of memory on stack. It is only inserted
	// at function entry, and it is ok to clobber registers.
	ZeroRange func(*Progs, *obj.Prog, int64, int64, *uint32) *obj.Prog

	Ginsnop      func(*Progs) *obj.Prog
	Ginsnopdefer func(*Progs) *obj.Prog // special ginsnop for deferreturn

	// SSAMarkMoves marks any MOVXconst ops that need to avoid clobbering flags.
	SSAMarkMoves func(*SSAGenState, *ssa.Block)

	// SSAGenValue emits Prog(s) for the Value.
	SSAGenValue func(*SSAGenState, *ssa.Value)

	// SSAGenBlock emits end-of-block Progs. SSAGenValue should be called
	// for all values in the block before SSAGenBlock.
	SSAGenBlock func(s *SSAGenState, b, next *ssa.Block)
}

var thearch Arch

var (
	staticuint64s,
	zerobase *Node

	assertE2I,
	assertE2I2,
	assertI2I,
	assertI2I2,
	deferproc,
	deferprocStack,
	Deferreturn,
	Duffcopy,
	Duffzero,
	gcWriteBarrier,
	goschedguarded,
	growslice,
	msanread,
	msanwrite,
	newobject,
	newproc,
	panicdivide,
	panicshift,
	panicdottypeE,
	panicdottypeI,
	panicnildottype,
	panicoverflow,
	raceread,
	racereadrange,
	racewrite,
	racewriterange,
	x86HasPOPCNT,
	x86HasSSE41,
	x86HasFMA,
	armHasVFPv4,
	arm64HasATOMICS,
	typedmemclr,
	typedmemmove,
	Udiv,
	writeBarrier,
	zerobaseSym *obj.LSym

	BoundsCheckFunc [ssa.BoundsKindCount]*obj.LSym
	ExtendCheckFunc [ssa.BoundsKindCount]*obj.LSym

	// Wasm
	WasmMove,
	WasmZero,
	WasmDiv,
	WasmTruncS,
	WasmTruncU,
	SigPanic *obj.LSym
)

// GCWriteBarrierReg maps from registers to gcWriteBarrier implementation LSyms.
var GCWriteBarrierReg map[int16]*obj.LSym
<|endoftext|>


<commit_before>// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package cache

import (
	"bytes"
	"crypto/sha256"
	"fmt"
	"hash"
	"io"
	"os"
	"runtime"
	"sync"
)

var debugHash = false // set when GODEBUG=gocachehash=1

// HashSize is the number of bytes in a hash.
const HashSize = 32

// A Hash provides access to the canonical hash function used to index the cache.
// The current implementation uses salted SHA256, but clients must not assume this.
type Hash struct {
	h    hash.Hash
	name string        // for debugging
	buf  *bytes.Buffer // for verify
}

// hashSalt is a salt string added to the beginning of every hash
// created by NewHash. Using the Go version makes sure that different
// versions of the go command (or even different Git commits during
// work on the development branch) do not address the same cache
// entries, so that a bug in one version does not affect the execution
// of other versions. This salt will result in additional ActionID files
// in the cache, but not additional copies of the large output files,
// which are still addressed by unsalted SHA256.
var hashSalt = []byte(runtime.Version())

// Subkey returns an action ID corresponding to mixing a parent
// action ID with a string description of the subkey.
func Subkey(parent ActionID, desc string) ActionID {
	h := sha256.New()
	h.Write([]byte("subkey:"))
	h.Write(parent[:])
	h.Write([]byte(desc))
	var out ActionID
	h.Sum(out[:0])
	if debugHash {
		fmt.Fprintf(os.Stderr, "HASH subkey %x %q = %x\n", parent, desc, out)
	}
	if verify {
		hashDebug.Lock()
		hashDebug.m[out] = fmt.Sprintf("subkey %x %q", parent, desc)
		hashDebug.Unlock()
	}
	return out
}

// NewHash returns a new Hash.
// The caller is expected to Write data to it and then call Sum.
func NewHash(name string) *Hash {
	h := &Hash{h: sha256.New(), name: name}
	if debugHash {
		fmt.Fprintf(os.Stderr, "HASH[%s]\n", h.name)
	}
	h.Write(hashSalt)
	if verify {
		h.buf = new(bytes.Buffer)
	}
	return h
}

// Write writes data to the running hash.
func (h *Hash) Write(b []byte) (int, error) {
	if debugHash {
		fmt.Fprintf(os.Stderr, "HASH[%s]: %q\n", h.name, b)
	}
	if h.buf != nil {
		h.buf.Write(b)
	}
	return h.h.Write(b)
}

// Sum returns the hash of the data written previously.
func (h *Hash) Sum() [HashSize]byte {
	var out [HashSize]byte
	h.h.Sum(out[:0])
	if debugHash {
		fmt.Fprintf(os.Stderr, "HASH[%s]: %x\n", h.name, out)
	}
	if h.buf != nil {
		hashDebug.Lock()
		if hashDebug.m == nil {
			hashDebug.m = make(map[[HashSize]byte]string)
		}
		hashDebug.m[out] = h.buf.String()
		hashDebug.Unlock()
	}
	return out
}

// In GODEBUG=gocacheverify=1 mode,
// hashDebug holds the input to every computed hash ID,
// so that we can work backward from the ID involved in a
// cache entry mismatch to a description of what should be there.
var hashDebug struct {
	sync.Mutex
	m map[[HashSize]byte]string
}

// reverseHash returns the input used to compute the hash id.
func reverseHash(id [HashSize]byte) string {
	hashDebug.Lock()
	s := hashDebug.m[id]
	hashDebug.Unlock()
	return s
}

var hashFileCache struct {
	sync.Mutex
	m map[string][HashSize]byte
}

// HashFile returns the hash of the named file.
// It caches repeated lookups for a given file,
// and the cache entry for a file can be initialized
// using SetFileHash.
// The hash used by FileHash is not the same as
// the hash used by NewHash.
func FileHash(file string) ([HashSize]byte, error) {
	hashFileCache.Lock()
	out, ok := hashFileCache.m[file]
	hashFileCache.Unlock()

	if ok {
		return out, nil
	}

	h := sha256.New()
	f, err := os.Open(file)
	if err != nil {
		if debugHash {
			fmt.Fprintf(os.Stderr, "HASH %s: %v\n", file, err)
		}
		return [HashSize]byte{}, err
	}
	_, err = io.Copy(h, f)
	f.Close()
	if err != nil {
		if debugHash {
			fmt.Fprintf(os.Stderr, "HASH %s: %v\n", file, err)
		}
		return [HashSize]byte{}, err
	}
	h.Sum(out[:0])
	if debugHash {
		fmt.Fprintf(os.Stderr, "HASH %s: %x\n", file, out)
	}

	SetFileHash(file, out)
	return out, nil
}

// SetFileHash sets the hash returned by FileHash for file.
func SetFileHash(file string, sum [HashSize]byte) {
	hashFileCache.Lock()
	if hashFileCache.m == nil {
		hashFileCache.m = make(map[string][HashSize]byte)
	}
	hashFileCache.m[file] = sum
	hashFileCache.Unlock()
}
<commit_msg>cmd/go/internal/cache: fix wrong/old function name in comment<commit_after>// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package cache

import (
	"bytes"
	"crypto/sha256"
	"fmt"
	"hash"
	"io"
	"os"
	"runtime"
	"sync"
)

var debugHash = false // set when GODEBUG=gocachehash=1

// HashSize is the number of bytes in a hash.
const HashSize = 32

// A Hash provides access to the canonical hash function used to index the cache.
// The current implementation uses salted SHA256, but clients must not assume this.
type Hash struct {
	h    hash.Hash
	name string        // for debugging
	buf  *bytes.Buffer // for verify
}

// hashSalt is a salt string added to the beginning of every hash
// created by NewHash. Using the Go version makes sure that different
// versions of the go command (or even different Git commits during
// work on the development branch) do not address the same cache
// entries, so that a bug in one version does not affect the execution
// of other versions. This salt will result in additional ActionID files
// in the cache, but not additional copies of the large output files,
// which are still addressed by unsalted SHA256.
var hashSalt = []byte(runtime.Version())

// Subkey returns an action ID corresponding to mixing a parent
// action ID with a string description of the subkey.
func Subkey(parent ActionID, desc string) ActionID {
	h := sha256.New()
	h.Write([]byte("subkey:"))
	h.Write(parent[:])
	h.Write([]byte(desc))
	var out ActionID
	h.Sum(out[:0])
	if debugHash {
		fmt.Fprintf(os.Stderr, "HASH subkey %x %q = %x\n", parent, desc, out)
	}
	if verify {
		hashDebug.Lock()
		hashDebug.m[out] = fmt.Sprintf("subkey %x %q", parent, desc)
		hashDebug.Unlock()
	}
	return out
}

// NewHash returns a new Hash.
// The caller is expected to Write data to it and then call Sum.
func NewHash(name string) *Hash {
	h := &Hash{h: sha256.New(), name: name}
	if debugHash {
		fmt.Fprintf(os.Stderr, "HASH[%s]\n", h.name)
	}
	h.Write(hashSalt)
	if verify {
		h.buf = new(bytes.Buffer)
	}
	return h
}

// Write writes data to the running hash.
func (h *Hash) Write(b []byte) (int, error) {
	if debugHash {
		fmt.Fprintf(os.Stderr, "HASH[%s]: %q\n", h.name, b)
	}
	if h.buf != nil {
		h.buf.Write(b)
	}
	return h.h.Write(b)
}

// Sum returns the hash of the data written previously.
func (h *Hash) Sum() [HashSize]byte {
	var out [HashSize]byte
	h.h.Sum(out[:0])
	if debugHash {
		fmt.Fprintf(os.Stderr, "HASH[%s]: %x\n", h.name, out)
	}
	if h.buf != nil {
		hashDebug.Lock()
		if hashDebug.m == nil {
			hashDebug.m = make(map[[HashSize]byte]string)
		}
		hashDebug.m[out] = h.buf.String()
		hashDebug.Unlock()
	}
	return out
}

// In GODEBUG=gocacheverify=1 mode,
// hashDebug holds the input to every computed hash ID,
// so that we can work backward from the ID involved in a
// cache entry mismatch to a description of what should be there.
var hashDebug struct {
	sync.Mutex
	m map[[HashSize]byte]string
}

// reverseHash returns the input used to compute the hash id.
func reverseHash(id [HashSize]byte) string {
	hashDebug.Lock()
	s := hashDebug.m[id]
	hashDebug.Unlock()
	return s
}

var hashFileCache struct {
	sync.Mutex
	m map[string][HashSize]byte
}

// FileHash returns the hash of the named file.
// It caches repeated lookups for a given file,
// and the cache entry for a file can be initialized
// using SetFileHash.
// The hash used by FileHash is not the same as
// the hash used by NewHash.
func FileHash(file string) ([HashSize]byte, error) {
	hashFileCache.Lock()
	out, ok := hashFileCache.m[file]
	hashFileCache.Unlock()

	if ok {
		return out, nil
	}

	h := sha256.New()
	f, err := os.Open(file)
	if err != nil {
		if debugHash {
			fmt.Fprintf(os.Stderr, "HASH %s: %v\n", file, err)
		}
		return [HashSize]byte{}, err
	}
	_, err = io.Copy(h, f)
	f.Close()
	if err != nil {
		if debugHash {
			fmt.Fprintf(os.Stderr, "HASH %s: %v\n", file, err)
		}
		return [HashSize]byte{}, err
	}
	h.Sum(out[:0])
	if debugHash {
		fmt.Fprintf(os.Stderr, "HASH %s: %x\n", file, out)
	}

	SetFileHash(file, out)
	return out, nil
}

// SetFileHash sets the hash returned by FileHash for file.
func SetFileHash(file string, sum [HashSize]byte) {
	hashFileCache.Lock()
	if hashFileCache.m == nil {
		hashFileCache.m = make(map[string][HashSize]byte)
	}
	hashFileCache.m[file] = sum
	hashFileCache.Unlock()
}
<|endoftext|>