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

package proto

/*
 * Routines for decoding protocol buffer data to construct in-memory representations.
 */

import (
	"errors"
	"fmt"
	"io"
)

// errOverflow is returned when an integer is too large to be represented.
var errOverflow = errors.New("proto: integer overflow")

// ErrInternalBadWireType is returned by generated code when an incorrect
// wire type is encountered. It does not get returned to user code.
var ErrInternalBadWireType = errors.New("proto: internal error: bad wiretype for oneof")

// DecodeVarint reads a varint-encoded integer from the slice.
// It returns the integer and the number of bytes consumed, or
// zero if there is not enough.
// This is the format for the
// int32, int64, uint32, uint64, bool, and enum
// protocol buffer types.
func DecodeVarint(buf []byte) (x uint64, n int) {
	for shift := uint(0); shift < 64; shift += 7 {
		if n >= len(buf) {
			return 0, 0
		}
		b := uint64(buf[n])
		n++
		x |= (b & 0x7F) << shift
		if (b & 0x80) == 0 {
			return x, n
		}
	}

	// The number is too large to represent in a 64-bit value.
	return 0, 0
}

func (p *Buffer) decodeVarintSlow() (x uint64, err error) {
	i := p.index
	l := len(p.buf)

	for shift := uint(0); shift < 64; shift += 7 {
		if i >= l {
			err = io.ErrUnexpectedEOF
			return
		}
		b := p.buf[i]
		i++
		x |= (uint64(b) & 0x7F) << shift
		if b < 0x80 {
			p.index = i
			return
		}
	}

	// The number is too large to represent in a 64-bit value.
	err = errOverflow
	return
}

// DecodeVarint reads a varint-encoded integer from the Buffer.
// This is the format for the
// int32, int64, uint32, uint64, bool, and enum
// protocol buffer types.
func (p *Buffer) DecodeVarint() (x uint64, err error) {
	i := p.index
	buf := p.buf

	if i >= len(buf) {
		return 0, io.ErrUnexpectedEOF
	} else if buf[i] < 0x80 {
		p.index++
		return uint64(buf[i]), nil
	} else if len(buf)-i < 10 {
		return p.decodeVarintSlow()
	}

	var b uint64
	// we already checked the first byte
	x = uint64(buf[i]) - 0x80
	i++

	b = uint64(buf[i])
	i++
	x += b << 7
	if b&0x80 == 0 {
		goto done
	}
	x -= 0x80 << 7

	b = uint64(buf[i])
	i++
	x += b << 14
	if b&0x80 == 0 {
		goto done
	}
	x -= 0x80 << 14

	b = uint64(buf[i])
	i++
	x += b << 21
	if b&0x80 == 0 {
		goto done
	}
	x -= 0x80 << 21

	b = uint64(buf[i])
	i++
	x += b << 28
	if b&0x80 == 0 {
		goto done
	}
	x -= 0x80 << 28

	b = uint64(buf[i])
	i++
	x += b << 35
	if b&0x80 == 0 {
		goto done
	}
	x -= 0x80 << 35

	b = uint64(buf[i])
	i++
	x += b << 42
	if b&0x80 == 0 {
		goto done
	}
	x -= 0x80 << 42

	b = uint64(buf[i])
	i++
	x += b << 49
	if b&0x80 == 0 {
		goto done
	}
	x -= 0x80 << 49

	b = uint64(buf[i])
	i++
	x += b << 56
	if b&0x80 == 0 {
		goto done
	}
	x -= 0x80 << 56

	b = uint64(buf[i])
	i++
	x += b << 63
	if b&0x80 == 0 {
		goto done
	}
	// x -= 0x80 << 63 // Always zero.

	return 0, errOverflow

done:
	p.index = i
	return x, nil
}

// DecodeFixed64 reads a 64-bit integer from the Buffer.
// This is the format for the
// fixed64, sfixed64, and double protocol buffer types.
func (p *Buffer) DecodeFixed64() (x uint64, err error) {
	// x, err already 0
	i := p.index + 8
	if i < 0 || i > len(p.buf) {
		err = io.ErrUnexpectedEOF
		return
	}
	p.index = i

	x = uint64(p.buf[i-8])
	x |= uint64(p.buf[i-7]) << 8
	x |= uint64(p.buf[i-6]) << 16
	x |= uint64(p.buf[i-5]) << 24
	x |= uint64(p.buf[i-4]) << 32
	x |= uint64(p.buf[i-3]) << 40
	x |= uint64(p.buf[i-2]) << 48
	x |= uint64(p.buf[i-1]) << 56
	return
}

// DecodeFixed32 reads a 32-bit integer from the Buffer.
// This is the format for the
// fixed32, sfixed32, and float protocol buffer types.
func (p *Buffer) DecodeFixed32() (x uint64, err error) {
	// x, err already 0
	i := p.index + 4
	if i < 0 || i > len(p.buf) {
		err = io.ErrUnexpectedEOF
		return
	}
	p.index = i

	x = uint64(p.buf[i-4])
	x |= uint64(p.buf[i-3]) << 8
	x |= uint64(p.buf[i-2]) << 16
	x |= uint64(p.buf[i-1]) << 24
	return
}

// DecodeZigzag64 reads a zigzag-encoded 64-bit integer
// from the Buffer.
// This is the format used for the sint64 protocol buffer type.
func (p *Buffer) DecodeZigzag64() (x uint64, err error) {
	x, err = p.DecodeVarint()
	if err != nil {
		return
	}
	x = (x >> 1) ^ uint64((int64(x&1)<<63)>>63)
	return
}

// DecodeZigzag32 reads a zigzag-encoded 32-bit integer
// from  the Buffer.
// This is the format used for the sint32 protocol buffer type.
func (p *Buffer) DecodeZigzag32() (x uint64, err error) {
	x, err = p.DecodeVarint()
	if err != nil {
		return
	}
	x = uint64((uint32(x) >> 1) ^ uint32((int32(x&1)<<31)>>31))
	return
}

// DecodeRawBytes reads a count-delimited byte buffer from the Buffer.
// This is the format used for the bytes protocol buffer
// type and for embedded messages.
func (p *Buffer) DecodeRawBytes(alloc bool) (buf []byte, err error) {
	n, err := p.DecodeVarint()
	if err != nil {
		return nil, err
	}

	nb := int(n)
	if nb < 0 {
		return nil, fmt.Errorf("proto: bad byte length %d", nb)
	}
	end := p.index + nb
	if end < p.index || end > len(p.buf) {
		return nil, io.ErrUnexpectedEOF
	}

	if !alloc {
		// todo: check if can get more uses of alloc=false
		buf = p.buf[p.index:end]
		p.index += nb
		return
	}

	buf = make([]byte, nb)
	copy(buf, p.buf[p.index:])
	p.index += nb
	return
}

// DecodeStringBytes reads an encoded string from the Buffer.
// This is the format used for the proto2 string type.
func (p *Buffer) DecodeStringBytes() (s string, err error) {
	buf, err := p.DecodeRawBytes(false)
	if err != nil {
		return
	}
	return string(buf), nil
}

// Unmarshaler is the interface representing objects that can
// unmarshal themselves.  The argument points to data that may be
// overwritten, so implementations should not keep references to the
// buffer.
// Unmarshal implementations should not clear the receiver.
// Any unmarshaled data should be merged into the receiver.
// Callers of Unmarshal that do not want to retain existing data
// should Reset the receiver before calling Unmarshal.
type Unmarshaler interface {
	Unmarshal([]byte) error
}

// newUnmarshaler is the interface representing objects that can
// unmarshal themselves. The semantics are identical to Unmarshaler.
//
// This exists to support protoc-gen-go generated messages.
// The proto package will stop type-asserting to this interface in the future.
//
// DO NOT DEPEND ON THIS.
type newUnmarshaler interface {
	XXX_Unmarshal([]byte) error
}

// Unmarshal parses the protocol buffer representation in buf and places the
// decoded result in pb.  If the struct underlying pb does not match
// the data in buf, the results can be unpredictable.
//
// Unmarshal resets pb before starting to unmarshal, so any
// existing data in pb is always removed. Use UnmarshalMerge
// to preserve and append to existing data.
func Unmarshal(buf []byte, pb Message) error {
	pb.Reset()
	if u, ok := pb.(newUnmarshaler); ok {
		return u.XXX_Unmarshal(buf)
	}
	if u, ok := pb.(Unmarshaler); ok {
		return u.Unmarshal(buf)
	}
	return NewBuffer(buf).Unmarshal(pb)
}

// UnmarshalMerge parses the protocol buffer representation in buf and
// writes the decoded result to pb.  If the struct underlying pb does not match
// the data in buf, the results can be unpredictable.
//
// UnmarshalMerge merges into existing data in pb.
// Most code should use Unmarshal instead.
func UnmarshalMerge(buf []byte, pb Message) error {
	if u, ok := pb.(newUnmarshaler); ok {
		return u.XXX_Unmarshal(buf)
	}
	if u, ok := pb.(Unmarshaler); ok {
		// NOTE: The history of proto have unfortunately been inconsistent
		// whether Unmarshaler should or should not implicitly clear itself.
		// Some implementations do, most do not.
		// Thus, calling this here may or may not do what people want.
		//
		// See https://github.com/golang/protobuf/issues/424
		return u.Unmarshal(buf)
	}
	return NewBuffer(buf).Unmarshal(pb)
}

// DecodeMessage reads a count-delimited message from the Buffer.
func (p *Buffer) DecodeMessage(pb Message) error {
	enc, err := p.DecodeRawBytes(false)
	if err != nil {
		return err
	}
	return NewBuffer(enc).Unmarshal(pb)
}

// DecodeGroup reads a tag-delimited group from the Buffer.
// StartGroup tag is already consumed. This function consumes
// EndGroup tag.
func (p *Buffer) DecodeGroup(pb Message) error {
	b := p.buf[p.index:]
	x, y := findEndGroup(b)
	if x < 0 {
		return io.ErrUnexpectedEOF
	}
	err := Unmarshal(b[:x], pb)
	p.index += y
	return err
}

// Unmarshal parses the protocol buffer representation in the
// Buffer and places the decoded result in pb.  If the struct
// underlying pb does not match the data in the buffer, the results can be
// unpredictable.
//
// Unlike proto.Unmarshal, this does not reset pb before starting to unmarshal.
func (p *Buffer) Unmarshal(pb Message) error {
	// If the object can unmarshal itself, let it.
	if u, ok := pb.(newUnmarshaler); ok {
		err := u.XXX_Unmarshal(p.buf[p.index:])
		p.index = len(p.buf)
		return err
	}
	if u, ok := pb.(Unmarshaler); ok {
		// NOTE: The history of proto have unfortunately been inconsistent
		// whether Unmarshaler should or should not implicitly clear itself.
		// Some implementations do, most do not.
		// Thus, calling this here may or may not do what people want.
		//
		// See https://github.com/golang/protobuf/issues/424
		err := u.Unmarshal(p.buf[p.index:])
		p.index = len(p.buf)
		return err
	}

	// Slow workaround for messages that aren't Unmarshalers.
	// This includes some hand-coded .pb.go files and
	// bootstrap protos.
	// TODO: fix all of those and then add Unmarshal to
	// the Message interface. Then:
	// The cast above and code below can be deleted.
	// The old unmarshaler can be deleted.
	// Clients can call Unmarshal directly (can already do that, actually).
	var info InternalMessageInfo
	err := info.Unmarshal(pb, p.buf[p.index:])
	p.index = len(p.buf)
	return err
}
<commit_msg>proto: remove commented-out code (#704)<commit_after>// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2010 The Go Authors.  All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package proto

/*
 * Routines for decoding protocol buffer data to construct in-memory representations.
 */

import (
	"errors"
	"fmt"
	"io"
)

// errOverflow is returned when an integer is too large to be represented.
var errOverflow = errors.New("proto: integer overflow")

// ErrInternalBadWireType is returned by generated code when an incorrect
// wire type is encountered. It does not get returned to user code.
var ErrInternalBadWireType = errors.New("proto: internal error: bad wiretype for oneof")

// DecodeVarint reads a varint-encoded integer from the slice.
// It returns the integer and the number of bytes consumed, or
// zero if there is not enough.
// This is the format for the
// int32, int64, uint32, uint64, bool, and enum
// protocol buffer types.
func DecodeVarint(buf []byte) (x uint64, n int) {
	for shift := uint(0); shift < 64; shift += 7 {
		if n >= len(buf) {
			return 0, 0
		}
		b := uint64(buf[n])
		n++
		x |= (b & 0x7F) << shift
		if (b & 0x80) == 0 {
			return x, n
		}
	}

	// The number is too large to represent in a 64-bit value.
	return 0, 0
}

func (p *Buffer) decodeVarintSlow() (x uint64, err error) {
	i := p.index
	l := len(p.buf)

	for shift := uint(0); shift < 64; shift += 7 {
		if i >= l {
			err = io.ErrUnexpectedEOF
			return
		}
		b := p.buf[i]
		i++
		x |= (uint64(b) & 0x7F) << shift
		if b < 0x80 {
			p.index = i
			return
		}
	}

	// The number is too large to represent in a 64-bit value.
	err = errOverflow
	return
}

// DecodeVarint reads a varint-encoded integer from the Buffer.
// This is the format for the
// int32, int64, uint32, uint64, bool, and enum
// protocol buffer types.
func (p *Buffer) DecodeVarint() (x uint64, err error) {
	i := p.index
	buf := p.buf

	if i >= len(buf) {
		return 0, io.ErrUnexpectedEOF
	} else if buf[i] < 0x80 {
		p.index++
		return uint64(buf[i]), nil
	} else if len(buf)-i < 10 {
		return p.decodeVarintSlow()
	}

	var b uint64
	// we already checked the first byte
	x = uint64(buf[i]) - 0x80
	i++

	b = uint64(buf[i])
	i++
	x += b << 7
	if b&0x80 == 0 {
		goto done
	}
	x -= 0x80 << 7

	b = uint64(buf[i])
	i++
	x += b << 14
	if b&0x80 == 0 {
		goto done
	}
	x -= 0x80 << 14

	b = uint64(buf[i])
	i++
	x += b << 21
	if b&0x80 == 0 {
		goto done
	}
	x -= 0x80 << 21

	b = uint64(buf[i])
	i++
	x += b << 28
	if b&0x80 == 0 {
		goto done
	}
	x -= 0x80 << 28

	b = uint64(buf[i])
	i++
	x += b << 35
	if b&0x80 == 0 {
		goto done
	}
	x -= 0x80 << 35

	b = uint64(buf[i])
	i++
	x += b << 42
	if b&0x80 == 0 {
		goto done
	}
	x -= 0x80 << 42

	b = uint64(buf[i])
	i++
	x += b << 49
	if b&0x80 == 0 {
		goto done
	}
	x -= 0x80 << 49

	b = uint64(buf[i])
	i++
	x += b << 56
	if b&0x80 == 0 {
		goto done
	}
	x -= 0x80 << 56

	b = uint64(buf[i])
	i++
	x += b << 63
	if b&0x80 == 0 {
		goto done
	}

	return 0, errOverflow

done:
	p.index = i
	return x, nil
}

// DecodeFixed64 reads a 64-bit integer from the Buffer.
// This is the format for the
// fixed64, sfixed64, and double protocol buffer types.
func (p *Buffer) DecodeFixed64() (x uint64, err error) {
	// x, err already 0
	i := p.index + 8
	if i < 0 || i > len(p.buf) {
		err = io.ErrUnexpectedEOF
		return
	}
	p.index = i

	x = uint64(p.buf[i-8])
	x |= uint64(p.buf[i-7]) << 8
	x |= uint64(p.buf[i-6]) << 16
	x |= uint64(p.buf[i-5]) << 24
	x |= uint64(p.buf[i-4]) << 32
	x |= uint64(p.buf[i-3]) << 40
	x |= uint64(p.buf[i-2]) << 48
	x |= uint64(p.buf[i-1]) << 56
	return
}

// DecodeFixed32 reads a 32-bit integer from the Buffer.
// This is the format for the
// fixed32, sfixed32, and float protocol buffer types.
func (p *Buffer) DecodeFixed32() (x uint64, err error) {
	// x, err already 0
	i := p.index + 4
	if i < 0 || i > len(p.buf) {
		err = io.ErrUnexpectedEOF
		return
	}
	p.index = i

	x = uint64(p.buf[i-4])
	x |= uint64(p.buf[i-3]) << 8
	x |= uint64(p.buf[i-2]) << 16
	x |= uint64(p.buf[i-1]) << 24
	return
}

// DecodeZigzag64 reads a zigzag-encoded 64-bit integer
// from the Buffer.
// This is the format used for the sint64 protocol buffer type.
func (p *Buffer) DecodeZigzag64() (x uint64, err error) {
	x, err = p.DecodeVarint()
	if err != nil {
		return
	}
	x = (x >> 1) ^ uint64((int64(x&1)<<63)>>63)
	return
}

// DecodeZigzag32 reads a zigzag-encoded 32-bit integer
// from  the Buffer.
// This is the format used for the sint32 protocol buffer type.
func (p *Buffer) DecodeZigzag32() (x uint64, err error) {
	x, err = p.DecodeVarint()
	if err != nil {
		return
	}
	x = uint64((uint32(x) >> 1) ^ uint32((int32(x&1)<<31)>>31))
	return
}

// DecodeRawBytes reads a count-delimited byte buffer from the Buffer.
// This is the format used for the bytes protocol buffer
// type and for embedded messages.
func (p *Buffer) DecodeRawBytes(alloc bool) (buf []byte, err error) {
	n, err := p.DecodeVarint()
	if err != nil {
		return nil, err
	}

	nb := int(n)
	if nb < 0 {
		return nil, fmt.Errorf("proto: bad byte length %d", nb)
	}
	end := p.index + nb
	if end < p.index || end > len(p.buf) {
		return nil, io.ErrUnexpectedEOF
	}

	if !alloc {
		// todo: check if can get more uses of alloc=false
		buf = p.buf[p.index:end]
		p.index += nb
		return
	}

	buf = make([]byte, nb)
	copy(buf, p.buf[p.index:])
	p.index += nb
	return
}

// DecodeStringBytes reads an encoded string from the Buffer.
// This is the format used for the proto2 string type.
func (p *Buffer) DecodeStringBytes() (s string, err error) {
	buf, err := p.DecodeRawBytes(false)
	if err != nil {
		return
	}
	return string(buf), nil
}

// Unmarshaler is the interface representing objects that can
// unmarshal themselves.  The argument points to data that may be
// overwritten, so implementations should not keep references to the
// buffer.
// Unmarshal implementations should not clear the receiver.
// Any unmarshaled data should be merged into the receiver.
// Callers of Unmarshal that do not want to retain existing data
// should Reset the receiver before calling Unmarshal.
type Unmarshaler interface {
	Unmarshal([]byte) error
}

// newUnmarshaler is the interface representing objects that can
// unmarshal themselves. The semantics are identical to Unmarshaler.
//
// This exists to support protoc-gen-go generated messages.
// The proto package will stop type-asserting to this interface in the future.
//
// DO NOT DEPEND ON THIS.
type newUnmarshaler interface {
	XXX_Unmarshal([]byte) error
}

// Unmarshal parses the protocol buffer representation in buf and places the
// decoded result in pb.  If the struct underlying pb does not match
// the data in buf, the results can be unpredictable.
//
// Unmarshal resets pb before starting to unmarshal, so any
// existing data in pb is always removed. Use UnmarshalMerge
// to preserve and append to existing data.
func Unmarshal(buf []byte, pb Message) error {
	pb.Reset()
	if u, ok := pb.(newUnmarshaler); ok {
		return u.XXX_Unmarshal(buf)
	}
	if u, ok := pb.(Unmarshaler); ok {
		return u.Unmarshal(buf)
	}
	return NewBuffer(buf).Unmarshal(pb)
}

// UnmarshalMerge parses the protocol buffer representation in buf and
// writes the decoded result to pb.  If the struct underlying pb does not match
// the data in buf, the results can be unpredictable.
//
// UnmarshalMerge merges into existing data in pb.
// Most code should use Unmarshal instead.
func UnmarshalMerge(buf []byte, pb Message) error {
	if u, ok := pb.(newUnmarshaler); ok {
		return u.XXX_Unmarshal(buf)
	}
	if u, ok := pb.(Unmarshaler); ok {
		// NOTE: The history of proto have unfortunately been inconsistent
		// whether Unmarshaler should or should not implicitly clear itself.
		// Some implementations do, most do not.
		// Thus, calling this here may or may not do what people want.
		//
		// See https://github.com/golang/protobuf/issues/424
		return u.Unmarshal(buf)
	}
	return NewBuffer(buf).Unmarshal(pb)
}

// DecodeMessage reads a count-delimited message from the Buffer.
func (p *Buffer) DecodeMessage(pb Message) error {
	enc, err := p.DecodeRawBytes(false)
	if err != nil {
		return err
	}
	return NewBuffer(enc).Unmarshal(pb)
}

// DecodeGroup reads a tag-delimited group from the Buffer.
// StartGroup tag is already consumed. This function consumes
// EndGroup tag.
func (p *Buffer) DecodeGroup(pb Message) error {
	b := p.buf[p.index:]
	x, y := findEndGroup(b)
	if x < 0 {
		return io.ErrUnexpectedEOF
	}
	err := Unmarshal(b[:x], pb)
	p.index += y
	return err
}

// Unmarshal parses the protocol buffer representation in the
// Buffer and places the decoded result in pb.  If the struct
// underlying pb does not match the data in the buffer, the results can be
// unpredictable.
//
// Unlike proto.Unmarshal, this does not reset pb before starting to unmarshal.
func (p *Buffer) Unmarshal(pb Message) error {
	// If the object can unmarshal itself, let it.
	if u, ok := pb.(newUnmarshaler); ok {
		err := u.XXX_Unmarshal(p.buf[p.index:])
		p.index = len(p.buf)
		return err
	}
	if u, ok := pb.(Unmarshaler); ok {
		// NOTE: The history of proto have unfortunately been inconsistent
		// whether Unmarshaler should or should not implicitly clear itself.
		// Some implementations do, most do not.
		// Thus, calling this here may or may not do what people want.
		//
		// See https://github.com/golang/protobuf/issues/424
		err := u.Unmarshal(p.buf[p.index:])
		p.index = len(p.buf)
		return err
	}

	// Slow workaround for messages that aren't Unmarshalers.
	// This includes some hand-coded .pb.go files and
	// bootstrap protos.
	// TODO: fix all of those and then add Unmarshal to
	// the Message interface. Then:
	// The cast above and code below can be deleted.
	// The old unmarshaler can be deleted.
	// Clients can call Unmarshal directly (can already do that, actually).
	var info InternalMessageInfo
	err := info.Unmarshal(pb, p.buf[p.index:])
	p.index = len(p.buf)
	return err
}
<|endoftext|>


<commit_before>package api

import (
	"os/exec"
	"time"
	"net/http"
	"path/filepath"
	"github.com/gorilla/mux"
	"github.com/golang/glog"
	"github.com/espebra/filebin/app/config"
	"github.com/espebra/filebin/app/model"
	"github.com/espebra/filebin/app/output"
)

func triggerNewTagHandler(c string, tag string) error {
	glog.Info("Executing trigger-new-tag: " + c)
	cmd := exec.Command(c, tag)
	err := cmdHandler(cmd)
	return err
}

func triggerUploadedFileHandler(c string, tag string, filename string) error {
	glog.Info("Executing trigger-uploaded-file: " + c)
	cmd := exec.Command(c, tag, filename)
	err := cmdHandler(cmd)
	return err
}

func triggerExpiredTagHandler(c string, tag string) error {
	glog.Info("Executing trigger-expired-tag: " + c)
	cmd := exec.Command(c, tag)
	err := cmdHandler(cmd)
	return err
}

func cmdHandler(cmd *exec.Cmd) error {
	err := cmd.Start()
	if err != nil {
		glog.Error("Trigger command failed: ", err)
	}
	return err
}

func Upload(w http.ResponseWriter, r *http.Request, cfg config.Configuration, ctx model.Context) {
	var err error
	f := model.ExtendedFile { }

	// Extract the tag from the request
	if (r.Header.Get("tag") == "") {
		err = f.GenerateTagID()
	} else {
		err = f.SetTagID(r.Header.Get("tag"))
	}
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest);
		glog.Info(err)
		return
	}
	f.SetTagDir(cfg.Filedir)

	// Write the request body to a temporary file
	err = f.WriteTempfile(r.Body, cfg.Tempdir)
	if err != nil {
		glog.Error("Unable to write tempfile: ", err)

		// Clean up by removing the tempfile
		f.ClearTemp()

		http.Error(w, "Internal Server Error", http.StatusInternalServerError);
		return
	}

	// Do not accept files that are 0 bytes
	if f.Bytes == 0 {
		// Clean up by removing the tempfile
		f.ClearTemp()

		http.Error(w, "No content. The file size must be more than " +
			"0 bytes.", http.StatusBadRequest);
		return
	}

	// Calculate and verify the checksum
	err = f.VerifySHA256(r.Header.Get("content-sha256"))
	if err != nil {
		http.Error(w, "Checksum did not match", http.StatusConflict);
		return
	}

	// Create the tag directory if it does not exist
	err = f.EnsureTagDirectoryExists()
	if err != nil {
		glog.Error("Unable to create tag directory: ", f.TagDir)
		http.Error(w, "Internal Server Error", http.StatusInternalServerError);
		return
	}

	f.CalculateExpiration(cfg.Expiration)
	expired, err := f.IsExpired(cfg.Expiration)
	if err != nil {
		http.Error(w,"Internal server error", 500)
		return
	}
	if expired {
		http.Error(w,"This tag has expired.", 410)
		return
	}

	// Extract the filename from the request
	if (r.Header.Get("filename") == "") {
		glog.Info("Using the checksum " + f.Checksum + " as the " +
			"filename")
		f.SetFilename(f.Checksum)
	} else {
		err = f.SetFilename(r.Header.Get("filename"))
		if err != nil {
			glog.Info(err)
			http.Error(w, "Invalid filename specified. It contains illegal characters or is too short.",
				http.StatusBadRequest);
			return
		}
	}

	// Promote file from tempdir to the published tagdir
	f.Publish()

	// Clean up by removing the tempfile
	f.ClearTemp()

	err = f.DetectMIME()
	if err != nil {
		glog.Error("Unable to detect MIME: ", err)
	}

	err = f.Info()
	if err != nil {
		http.Error(w,"Internal Server Error", 500)
		return
	}

	f.GenerateLinks(cfg.Baseurl)
	f.RemoteAddr = r.RemoteAddr
	f.UserAgent = r.Header.Get("User-Agent")
	f.CreatedAt = time.Now().UTC()
	//f.ExpiresAt = time.Now().UTC().Add(24 * 7 * 4 * time.Hour)

	if cfg.TriggerUploadedFile != "" {
		triggerUploadedFileHandler(cfg.TriggerUploadedFile, f.TagID, f.Filename)
	}

	headers := make(map[string]string)
	headers["Content-Type"] = "application/json"

	var status = 201
	output.JSONresponse(w, status, headers, f)
}

func FetchFile(w http.ResponseWriter, r *http.Request, cfg config.Configuration, ctx model.Context) {
	var err error
	params := mux.Vars(r)
	f := model.File {}
	f.SetFilename(params["filename"])
	if err != nil {
		http.Error(w,"Invalid filename specified. It contains illegal characters or is too short.", 400)
		return
	}
	err = f.SetTagID(params["tag"])
	if err != nil {
		http.Error(w,"Invalid tag specified. It contains illegal characters or is too short.", 400)
		return
	}
	f.SetTagDir(cfg.Filedir)

	f.CalculateExpiration(cfg.Expiration)
	expired, err := f.IsExpired(cfg.Expiration)
	if err != nil {
		http.Error(w,"Internal server error", 500)
		return
	}
	if expired {
		http.Error(w,"This tag has expired.", 410)
		return
	}

	path := filepath.Join(f.TagDir, f.Filename)

	w.Header().Set("Cache-Control", "max-age=15")
	http.ServeFile(w, r, path)
}

func DeleteFile(w http.ResponseWriter, r *http.Request, cfg config.Configuration, ctx model.Context) {
	var err error
	params := mux.Vars(r)
	f := model.File {}
	f.SetFilename(params["filename"])
	if err != nil {
		http.Error(w,"Invalid filename specified. It contains illegal characters or is too short.", 400)
		return
	}
	err = f.SetTagID(params["tag"])
	if err != nil {
		http.Error(w,"Invalid tag specified. It contains illegal characters or is too short.", 400)
		return
	}
	f.SetTagDir(cfg.Filedir)

	if f.Exists() == false {
		http.Error(w,"File Not Found", 404)
		return
	}

	f.CalculateExpiration(cfg.Expiration)
	expired, err := f.IsExpired(cfg.Expiration)
	if err != nil {
		http.Error(w,"Internal server error", 500)
		return
	}
	if expired {
		http.Error(w,"This tag has expired.", 410)
		return
	}

	f.GenerateLinks(cfg.Baseurl)
	err = f.DetectMIME()
	if err != nil {
		glog.Error("Unable to detect MIME: ", err)
	}

	err = f.Info()
	if err != nil {
		http.Error(w,"Internal Server Error", 500)
		return
	}

	err = f.Remove()
 	if err != nil {
		glog.Error("Unable to delete file: ", err)
		http.Error(w,"Internal Server Error", 500)
		return
	}

	headers := make(map[string]string)
	headers["Content-Type"] = "application/json"

	var status = 200
	output.JSONresponse(w, status, headers, f)
	return
}

func FetchTag(w http.ResponseWriter, r *http.Request, cfg config.Configuration, ctx model.Context) {
	var err error
	params := mux.Vars(r)
	t := model.ExtendedTag {}
	err = t.SetTagID(params["tag"])
	if err != nil {
		http.Error(w, "Invalid tag", 400)
		return
	}

	t.SetTagDir(cfg.Filedir)
	t.CalculateExpiration(cfg.Expiration)
	if t.Exists() {
		expired, err := t.IsExpired(cfg.Expiration)
		if err != nil {
			http.Error(w,"Internal server error", 500)
			return
		}
		if expired {
			http.Error(w,"This tag has expired.", 410)
			return
		}

		err = t.Info()
		if err != nil {
			http.Error(w, "Internal Server Error", 500)
			return
		}

		err = t.List(cfg.Baseurl)
		if err != nil {
			http.Error(w,"Some error.", 404)
			return
		}
	}

	//t.GenerateLinks(cfg.Baseurl)

	headers := make(map[string]string)
	headers["Cache-Control"] = "max-age=15"

	var status = 200

	if (r.Header.Get("Content-Type") == "application/json") {
		headers["Content-Type"] = "application/json"
		output.JSONresponse(w, status, headers, t)
	} else {
		output.HTMLresponse(w, "viewtag", status, headers, t, ctx)
	}
}

func ViewIndex(w http.ResponseWriter, r *http.Request, cfg config.Configuration, ctx model.Context) {
	t := model.Tag {}
	err := t.GenerateTagID()
	if err != nil {
		http.Error(w, "Internal Server Error", 500)
		return
	}

	headers := make(map[string]string)
	headers["Cache-Control"] = "max-age=0"
	headers["Location"] = "/" + t.TagID
	var status = 302
	output.JSONresponse(w, status, headers, t)
}

func ViewAPI(w http.ResponseWriter, r *http.Request, cfg config.Configuration, ctx model.Context) {
	t := model.Tag {}
	headers := make(map[string]string)
	headers["Cache-Control"] = "max-age=15"
	var status = 200
	output.HTMLresponse(w, "api", status, headers, t, ctx)
}

func ViewDoc(w http.ResponseWriter, r *http.Request, cfg config.Configuration, ctx model.Context) {
	t := model.Tag {}
	headers := make(map[string]string)
	headers["Cache-Control"] = "max-age=15"
	var status = 200
	output.HTMLresponse(w, "doc", status, headers, t, ctx)
}
<commit_msg>Lower max-age for easier development<commit_after>package api

import (
	"os/exec"
	"time"
	"net/http"
	"path/filepath"
	"github.com/gorilla/mux"
	"github.com/golang/glog"
	"github.com/espebra/filebin/app/config"
	"github.com/espebra/filebin/app/model"
	"github.com/espebra/filebin/app/output"
)

func triggerNewTagHandler(c string, tag string) error {
	glog.Info("Executing trigger-new-tag: " + c)
	cmd := exec.Command(c, tag)
	err := cmdHandler(cmd)
	return err
}

func triggerUploadedFileHandler(c string, tag string, filename string) error {
	glog.Info("Executing trigger-uploaded-file: " + c)
	cmd := exec.Command(c, tag, filename)
	err := cmdHandler(cmd)
	return err
}

func triggerExpiredTagHandler(c string, tag string) error {
	glog.Info("Executing trigger-expired-tag: " + c)
	cmd := exec.Command(c, tag)
	err := cmdHandler(cmd)
	return err
}

func cmdHandler(cmd *exec.Cmd) error {
	err := cmd.Start()
	if err != nil {
		glog.Error("Trigger command failed: ", err)
	}
	return err
}

func Upload(w http.ResponseWriter, r *http.Request, cfg config.Configuration, ctx model.Context) {
	var err error
	f := model.ExtendedFile { }

	// Extract the tag from the request
	if (r.Header.Get("tag") == "") {
		err = f.GenerateTagID()
	} else {
		err = f.SetTagID(r.Header.Get("tag"))
	}
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest);
		glog.Info(err)
		return
	}
	f.SetTagDir(cfg.Filedir)

	// Write the request body to a temporary file
	err = f.WriteTempfile(r.Body, cfg.Tempdir)
	if err != nil {
		glog.Error("Unable to write tempfile: ", err)

		// Clean up by removing the tempfile
		f.ClearTemp()

		http.Error(w, "Internal Server Error", http.StatusInternalServerError);
		return
	}

	// Do not accept files that are 0 bytes
	if f.Bytes == 0 {
		// Clean up by removing the tempfile
		f.ClearTemp()

		http.Error(w, "No content. The file size must be more than " +
			"0 bytes.", http.StatusBadRequest);
		return
	}

	// Calculate and verify the checksum
	err = f.VerifySHA256(r.Header.Get("content-sha256"))
	if err != nil {
		http.Error(w, "Checksum did not match", http.StatusConflict);
		return
	}

	// Create the tag directory if it does not exist
	err = f.EnsureTagDirectoryExists()
	if err != nil {
		glog.Error("Unable to create tag directory: ", f.TagDir)
		http.Error(w, "Internal Server Error", http.StatusInternalServerError);
		return
	}

	f.CalculateExpiration(cfg.Expiration)
	expired, err := f.IsExpired(cfg.Expiration)
	if err != nil {
		http.Error(w,"Internal server error", 500)
		return
	}
	if expired {
		http.Error(w,"This tag has expired.", 410)
		return
	}

	// Extract the filename from the request
	if (r.Header.Get("filename") == "") {
		glog.Info("Using the checksum " + f.Checksum + " as the " +
			"filename")
		f.SetFilename(f.Checksum)
	} else {
		err = f.SetFilename(r.Header.Get("filename"))
		if err != nil {
			glog.Info(err)
			http.Error(w, "Invalid filename specified. It contains illegal characters or is too short.",
				http.StatusBadRequest);
			return
		}
	}

	// Promote file from tempdir to the published tagdir
	f.Publish()

	// Clean up by removing the tempfile
	f.ClearTemp()

	err = f.DetectMIME()
	if err != nil {
		glog.Error("Unable to detect MIME: ", err)
	}

	err = f.Info()
	if err != nil {
		http.Error(w,"Internal Server Error", 500)
		return
	}

	f.GenerateLinks(cfg.Baseurl)
	f.RemoteAddr = r.RemoteAddr
	f.UserAgent = r.Header.Get("User-Agent")
	f.CreatedAt = time.Now().UTC()
	//f.ExpiresAt = time.Now().UTC().Add(24 * 7 * 4 * time.Hour)

	if cfg.TriggerUploadedFile != "" {
		triggerUploadedFileHandler(cfg.TriggerUploadedFile, f.TagID, f.Filename)
	}

	headers := make(map[string]string)
	headers["Content-Type"] = "application/json"

	var status = 201
	output.JSONresponse(w, status, headers, f)
}

func FetchFile(w http.ResponseWriter, r *http.Request, cfg config.Configuration, ctx model.Context) {
	var err error
	params := mux.Vars(r)
	f := model.File {}
	f.SetFilename(params["filename"])
	if err != nil {
		http.Error(w,"Invalid filename specified. It contains illegal characters or is too short.", 400)
		return
	}
	err = f.SetTagID(params["tag"])
	if err != nil {
		http.Error(w,"Invalid tag specified. It contains illegal characters or is too short.", 400)
		return
	}
	f.SetTagDir(cfg.Filedir)

	f.CalculateExpiration(cfg.Expiration)
	expired, err := f.IsExpired(cfg.Expiration)
	if err != nil {
		http.Error(w,"Internal server error", 500)
		return
	}
	if expired {
		http.Error(w,"This tag has expired.", 410)
		return
	}

	path := filepath.Join(f.TagDir, f.Filename)

	w.Header().Set("Cache-Control", "max-age=1")
	http.ServeFile(w, r, path)
}

func DeleteFile(w http.ResponseWriter, r *http.Request, cfg config.Configuration, ctx model.Context) {
	var err error
	params := mux.Vars(r)
	f := model.File {}
	f.SetFilename(params["filename"])
	if err != nil {
		http.Error(w,"Invalid filename specified. It contains illegal characters or is too short.", 400)
		return
	}
	err = f.SetTagID(params["tag"])
	if err != nil {
		http.Error(w,"Invalid tag specified. It contains illegal characters or is too short.", 400)
		return
	}
	f.SetTagDir(cfg.Filedir)

	if f.Exists() == false {
		http.Error(w,"File Not Found", 404)
		return
	}

	f.CalculateExpiration(cfg.Expiration)
	expired, err := f.IsExpired(cfg.Expiration)
	if err != nil {
		http.Error(w,"Internal server error", 500)
		return
	}
	if expired {
		http.Error(w,"This tag has expired.", 410)
		return
	}

	f.GenerateLinks(cfg.Baseurl)
	err = f.DetectMIME()
	if err != nil {
		glog.Error("Unable to detect MIME: ", err)
	}

	err = f.Info()
	if err != nil {
		http.Error(w,"Internal Server Error", 500)
		return
	}

	err = f.Remove()
 	if err != nil {
		glog.Error("Unable to delete file: ", err)
		http.Error(w,"Internal Server Error", 500)
		return
	}

	headers := make(map[string]string)
	headers["Content-Type"] = "application/json"

	var status = 200
	output.JSONresponse(w, status, headers, f)
	return
}

func FetchTag(w http.ResponseWriter, r *http.Request, cfg config.Configuration, ctx model.Context) {
	var err error
	params := mux.Vars(r)
	t := model.ExtendedTag {}
	err = t.SetTagID(params["tag"])
	if err != nil {
		http.Error(w, "Invalid tag", 400)
		return
	}

	t.SetTagDir(cfg.Filedir)
	t.CalculateExpiration(cfg.Expiration)
	if t.Exists() {
		expired, err := t.IsExpired(cfg.Expiration)
		if err != nil {
			http.Error(w,"Internal server error", 500)
			return
		}
		if expired {
			http.Error(w,"This tag has expired.", 410)
			return
		}

		err = t.Info()
		if err != nil {
			http.Error(w, "Internal Server Error", 500)
			return
		}

		err = t.List(cfg.Baseurl)
		if err != nil {
			http.Error(w,"Some error.", 404)
			return
		}
	}

	//t.GenerateLinks(cfg.Baseurl)

	headers := make(map[string]string)
	headers["Cache-Control"] = "max-age=1"

	var status = 200

	if (r.Header.Get("Content-Type") == "application/json") {
		headers["Content-Type"] = "application/json"
		output.JSONresponse(w, status, headers, t)
	} else {
		output.HTMLresponse(w, "viewtag", status, headers, t, ctx)
	}
}

func ViewIndex(w http.ResponseWriter, r *http.Request, cfg config.Configuration, ctx model.Context) {
	t := model.Tag {}
	err := t.GenerateTagID()
	if err != nil {
		http.Error(w, "Internal Server Error", 500)
		return
	}

	headers := make(map[string]string)
	headers["Cache-Control"] = "max-age=0"
	headers["Location"] = "/" + t.TagID
	var status = 302
	output.JSONresponse(w, status, headers, t)
}

func ViewAPI(w http.ResponseWriter, r *http.Request, cfg config.Configuration, ctx model.Context) {
	t := model.Tag {}
	headers := make(map[string]string)
	headers["Cache-Control"] = "max-age=1"
	var status = 200
	output.HTMLresponse(w, "api", status, headers, t, ctx)
}

func ViewDoc(w http.ResponseWriter, r *http.Request, cfg config.Configuration, ctx model.Context) {
	t := model.Tag {}
	headers := make(map[string]string)
	headers["Cache-Control"] = "max-age=1"
	var status = 200
	output.HTMLresponse(w, "doc", status, headers, t, ctx)
}
<|endoftext|>


<commit_before>package models

import (
	"github.com/nsqio/go-nsq"
	"time"
)

type GlacierRestoreState struct {
	// NSQMessage is the NSQ message being processed in this restore
	// request. Not serialized because it will change each time we
	// try to process a request.
	NSQMessage *nsq.Message `json:"-"`
	// WorkItem is the Pharos WorkItem we're processing.
	// Not serialized because the Pharos WorkItem record will be
	// more up-to-date and authoritative.
	WorkItem *WorkItem `json:"-"`
	// WorkSummary contains information about whether/when
	// we requested this object(s) be restored from Glacier.
	WorkSummary *WorkSummary
	// Requests are the requests we've made (or need to make)
	// to Glacier to retrieve the objects we need to retrieve.
	Requests []*GlacierRestoreRequest
}

func NewGlacierRestoreState(message *nsq.Message, workItem *WorkItem) *GlacierRestoreState {
	return &GlacierRestoreState{
		NSQMessage:  message,
		WorkItem:    workItem,
		WorkSummary: NewWorkSummary(),
		Requests:    make([]*GlacierRestoreRequest, 0),
	}
}

func (state *GlacierRestoreState) FindRequest(gfIdentifier string) *GlacierRestoreRequest {
	var request *GlacierRestoreRequest
	if state.Requests != nil {
		for _, req := range state.Requests {
			if req.GenericFileIdentifier == gfIdentifier {
				request = req
				break
			}
		}
	}
	return request
}

func (state *GlacierRestoreState) GetReport(genericFiles []*GenericFile) *GlacierRequestReport {
	report := NewGlacierRequestReport()
	requests := make(map[string]*GlacierRestoreRequest, len(state.Requests))
	for _, req := range state.Requests {
		requests[req.GenericFileIdentifier] = req
		if req.RequestAccepted == false {
			report.RequestsNotAccepted = append(report.RequestsNotAccepted, req.GenericFileIdentifier)
		}
		if report.EarliestRequest.IsZero() || req.RequestedAt.Before(report.EarliestRequest) {
			report.EarliestRequest = req.RequestedAt
		}
		if report.LatestRequest.IsZero() || req.RequestedAt.After(report.LatestRequest) {
			report.LatestRequest = req.RequestedAt
		}
		if report.EarliestExpiry.IsZero() || req.EstimatedDeletionFromS3.Before(report.EarliestExpiry) {
			report.EarliestExpiry = req.EstimatedDeletionFromS3
		}
		if report.LatestExpiry.IsZero() || req.EstimatedDeletionFromS3.After(report.LatestExpiry) {
			report.LatestExpiry = req.EstimatedDeletionFromS3
		}
	}
	for _, gf := range genericFiles {
		_, wasRequested := requests[gf.Identifier]
		if wasRequested == false {
			report.FilesNotRequested = append(report.FilesNotRequested, gf.Identifier)
		}
	}
	return report
}

type GlacierRequestReport struct {
	FilesNotRequested   []string
	RequestsNotAccepted []string
	EarliestRequest     time.Time
	LatestRequest       time.Time
	EarliestExpiry      time.Time
	LatestExpiry        time.Time
}

func (report *GlacierRequestReport) AllRequestsInitialized() bool {
	return len(report.FilesNotRequested) == 0 && len(report.RequestsNotAccepted) == 0
}

func NewGlacierRequestReport() *GlacierRequestReport {
	return &GlacierRequestReport{
		FilesNotRequested:   make([]string, 0),
		RequestsNotAccepted: make([]string, 0),
	}
}

type GlacierRestoreRequest struct {
	// GenericFileIdentifier is the identifier of the generic
	// file we want to restore.
	GenericFileIdentifier string
	// GlacierBucket is the bucket that contains the item
	// we want to restore.
	GlacierBucket string
	// GlacierKey is the key we want to restore
	// (usually a UUID, for APTrust).
	GlacierKey string
	// RequestAccepted indicates whether Glacier accepted
	// our request to restore this object.
	RequestAccepted bool
	// RequestedAt is the timestamp of the last request to
	// restore this object.
	RequestedAt time.Time
	// EstimatedDeletionFromS3 describes approximately when
	// this item should be available at the RestorationURL.
	// This time can vary, depending on what level of Glacier
	// retrieval service we're using. Using the standard service
	// level, this should be about four hours after RequestedAt,
	// if the requests succeeded.
	EstimatedDeletionFromS3 time.Time
	// SomeoneElseRequested will be true if apt_glacier_restore
	// thinks someone else requested retrieval of the object.
	// If this is true, EstimatedDeletionFromS3 may not be
	// reliable, because we don't know when the retrieval
	// request occurred, or with what parameters.
	SomeoneElseRequested bool
}
<commit_msg>Added doc comments<commit_after>package models

import (
	"github.com/nsqio/go-nsq"
	"time"
)

// GlacierRestoreState holds information about the state of the Glacier
// restore process. This is serialized to JSON and stored in the
// Pharos WorkItemState table, so any worker picking up this task
// can know what's been done and what work remains. The worker
// apt_glacier_restore_init uses this object to keep track of its work.
//
// Restoring a full APTrust bag from Glacier requires one Glacier
// retrieval initialization request and (later) one S3 GET request
// for each file in the bag. Large bags may contain tens of thousands
// of files, so workers may have to attempt retrieval initialization
// several times before all requests succeed.
type GlacierRestoreState struct {
	// NSQMessage is the NSQ message being processed in this restore
	// request. Not serialized because it will change each time we
	// try to process a request.
	NSQMessage *nsq.Message `json:"-"`
	// WorkItem is the Pharos WorkItem we're processing.
	// Not serialized because the Pharos WorkItem record will be
	// more up-to-date and authoritative.
	WorkItem *WorkItem `json:"-"`
	// WorkSummary contains information about whether/when
	// we requested this object(s) be restored from Glacier.
	WorkSummary *WorkSummary
	// Requests are the requests we've made (or need to make)
	// to Glacier to retrieve the objects we need to retrieve.
	Requests []*GlacierRestoreRequest
}

// NewGlacierRestoreState creates a new GlacierRestoreState object.
func NewGlacierRestoreState(message *nsq.Message, workItem *WorkItem) *GlacierRestoreState {
	return &GlacierRestoreState{
		NSQMessage:  message,
		WorkItem:    workItem,
		WorkSummary: NewWorkSummary(),
		Requests:    make([]*GlacierRestoreRequest, 0),
	}
}

// FindRequest returns the GlacierRestoreRequest for the specified
// GenericFile identifier. If it returns nil, we have not yet submitted
// a retrieval request to Glacier for that file. Be sure to check the
// returned GlacierRestoreRequest to see whether RequestAccepted is true.
func (state *GlacierRestoreState) FindRequest(gfIdentifier string) *GlacierRestoreRequest {
	var request *GlacierRestoreRequest
	if state.Requests != nil {
		for _, req := range state.Requests {
			if req.GenericFileIdentifier == gfIdentifier {
				request = req
				break
			}
		}
	}
	return request
}

// GetReport returns a GlacierRequestReport describing what work
// remains to be done, and how long we can expect the items to
// remain in the S3 buckets.
func (state *GlacierRestoreState) GetReport(genericFiles []*GenericFile) *GlacierRequestReport {
	report := NewGlacierRequestReport()
	report.FilesRequired = len(state.Requests)
	requests := make(map[string]*GlacierRestoreRequest, len(state.Requests))
	for _, req := range state.Requests {
		requests[req.GenericFileIdentifier] = req
		report.FilesRequested += 1
		if req.RequestAccepted == false {
			report.RequestsNotAccepted = append(report.RequestsNotAccepted, req.GenericFileIdentifier)
		}
		if report.EarliestRequest.IsZero() || req.RequestedAt.Before(report.EarliestRequest) {
			report.EarliestRequest = req.RequestedAt
		}
		if report.LatestRequest.IsZero() || req.RequestedAt.After(report.LatestRequest) {
			report.LatestRequest = req.RequestedAt
		}
		if report.EarliestExpiry.IsZero() || req.EstimatedDeletionFromS3.Before(report.EarliestExpiry) {
			if req.RequestAccepted {
				report.EarliestExpiry = req.EstimatedDeletionFromS3
			}
		}
		if report.LatestExpiry.IsZero() || req.EstimatedDeletionFromS3.After(report.LatestExpiry) {
			if req.RequestAccepted {
				report.LatestExpiry = req.EstimatedDeletionFromS3
			}
		}
	}
	for _, gf := range genericFiles {
		_, wasRequested := requests[gf.Identifier]
		if wasRequested == false {
			report.FilesNotRequested = append(report.FilesNotRequested, gf.Identifier)
		}
	}
	return report
}

// GlacierRequestReport provides information on whether all Glacier
// files have been requested, which ones still need to be requested,
// and how long the files should remain available in S3.
type GlacierRequestReport struct {
	// FilesRequired is the number of files we need to request
	// from Glacier. When restoring a single file, this will be
	// set to one. When restoring a full IntellectualObject, this
	// we be set to the number of saved, active (non-deleted) files
	// that make up the object.
	FilesRequired int
	// FilesRequested is the number of file retrieval requests
	// we've made to Glacier. Glacier may have rejected some of
	// these requests. See RequestsNotAccepted.
	FilesRequested int
	// FilesNotRequested is a list of GenericFile identifiers that
	// we were supposed to request from Glacier but have not yet
	// requested.
	FilesNotRequested []string
	// RequestsNotAccepted is a list of GenericFile identifiers that
	// we requested from Glacier that were denied (or errored).
	// We should retry these.
	RequestsNotAccepted []string
	// EarliestRequest is the timestamp on the earliest Glacier retrieval
	// request for this job.
	EarliestRequest time.Time
	// LatestRequest is the timestamp on the latest Glacier retrieval
	// request for this job.
	LatestRequest time.Time
	// EarliestExpiry is the approximate earliest date-time at which
	// a restored file will be deleted from S3. Once restored from
	// Glacier, files only stay in S3 for a few days.
	// See APTGlacierRestoreInit.DAYS_TO_KEEP_IN_S3
	EarliestExpiry time.Time
	// LatestExpiry is the approximate latest date-time at which
	// a restored file will be deleted from S3. Once restored from
	// Glacier, files only stay in S3 for a few days.
	// See APTGlacierRestoreInit.DAYS_TO_KEEP_IN_S3
	LatestExpiry time.Time
}

// NewGlacierRequestReport creates a new GlacierRequestReport
func NewGlacierRequestReport() *GlacierRequestReport {
	return &GlacierRequestReport{
		FilesNotRequested:   make([]string, 0),
		RequestsNotAccepted: make([]string, 0),
	}
}

// AllRetrievalsInitialed returns true if we have initiated the retrieval
// process for all of the files we were suppsed to retrieve.
func (report *GlacierRequestReport) AllRetrievalsInitialed() bool {
	return len(report.FilesNotRequested) == 0 && len(report.RequestsNotAccepted) == 0
}

// GlacierRestoreRequest describes a request to restore a file
// from Glacier to S3.
type GlacierRestoreRequest struct {
	// GenericFileIdentifier is the identifier of the generic
	// file we want to restore.
	GenericFileIdentifier string
	// GlacierBucket is the bucket that contains the item
	// we want to restore.
	GlacierBucket string
	// GlacierKey is the key we want to restore
	// (usually a UUID, for APTrust).
	GlacierKey string
	// RequestAccepted indicates whether Glacier accepted
	// our request to restore this object.
	RequestAccepted bool
	// RequestedAt is the timestamp of the last request to
	// restore this object.
	RequestedAt time.Time
	// EstimatedDeletionFromS3 describes approximately when
	// this item should be available at the RestorationURL.
	// This time can vary, depending on what level of Glacier
	// retrieval service we're using. Using the standard service
	// level, this should be about four hours after RequestedAt,
	// if the requests succeeded.
	EstimatedDeletionFromS3 time.Time
	// SomeoneElseRequested will be true if apt_glacier_restore
	// thinks someone else requested retrieval of the object.
	// If this is true, EstimatedDeletionFromS3 may not be
	// reliable, because we don't know when the retrieval
	// request occurred, or with what parameters.
	SomeoneElseRequested bool
}
<|endoftext|>


<commit_before>package streamtools

import (
	"github.com/bitly/go-simplejson"
	"log"
)

func maskJSON(mask *simplejson.Json, input *simplejson.Json) *simplejson.Json {
	t, _ := simplejson.NewJson([]byte(`{}`))

	maskMap, err := mask.Map()
	if err != nil {
		log.Println(err.Error())
	}

	inputMap, err := input.Map()
	if err != nil {
		log.Println(err.Error())
	}

	for k, _ := range maskMap {
		switch inputMap[k].(type) {
		case map[string]interface{}:
			t.Set(k, maskJSON(mask.Get(k), input.Get(k)))
		default:
			t.Set(k, input.Get(k))
		}
	}
	return t
}

func Mask(inChan chan *simplejson.Json, outChan chan *simplejson.Json, RuleChan chan *simplejson.Json) {
	mask, _ := simplejson.NewJson([]byte(`{}`))
	for {
		select {
		case inputRule := <-RuleChan:
			mask = inputRule
		case msg := <-inChan:
			outChan <- maskJSON(mask, msg)
		}
	}
}
<commit_msg>changed mask notation, added doc.<commit_after>package streamtools

import (
	"github.com/bitly/go-simplejson"
	"log"
)

func maskJSON(mask *simplejson.Json, input *simplejson.Json) *simplejson.Json {
	t, _ := simplejson.NewJson([]byte(`{}`))

	maskMap, err := mask.Map()
	if err != nil {
		log.Println(err.Error())
	}

	if len(maskMap) == 0 {
		return input
	}

	inputMap, err := input.Map()
	if err != nil {
		log.Println(err.Error())
	}

	for k, _ := range maskMap {
		switch inputMap[k].(type) {
		case map[string]interface{}:
			t.Set(k, maskJSON(mask.Get(k), input.Get(k)))
		default:
			t.Set(k, input.Get(k))
		}
	}

	return t
}

// Mask modifies a JSON stream with an additive key filter. Mask uses the JSON
// object recieved through the rule channel to determine which keys should be
// included in the resulting object. An empty JSON object ({}) is used as the
// notation to include all values for a key.
//
// For instance, if the JSON rule is:
//	{"a":{}, "b":{"d":{}},"x":{}}
// And an incoming message looks like:
//	{"a":24, "b":{"c":"test", "d":[1,3,4]}, "f":5, "x":{"y":5, "z":10}}
// The resulting object after the application of Mask would be:
//	{"a":24, "b":{"d":[1,3,4]}, "x":{"y":5, "z":10}
func Mask(inChan chan *simplejson.Json, outChan chan *simplejson.Json, RuleChan chan *simplejson.Json) {
	mask, _ := simplejson.NewJson([]byte(`{}`))
	for {
		select {
		case inputRule := <-RuleChan:
			mask = inputRule
		case msg := <-inChan:
			outChan <- maskJSON(mask, msg)
		}
	}
}
<|endoftext|>


<commit_before>package layout

import (
	"encoding/json"
	"io"
	"io/ioutil"
	"os"

	"github.com/containers/image/manifest"
	"github.com/containers/image/types"
	imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
)

type ociImageSource struct {
	ref ociReference
}

// newImageSource returns an ImageSource for reading from an existing directory.
func newImageSource(ref ociReference) types.ImageSource {
	return &ociImageSource{ref: ref}
}

// Reference returns the reference used to set up this source.
func (s *ociImageSource) Reference() types.ImageReference {
	return s.ref
}

// Close removes resources associated with an initialized ImageSource, if any.
func (s *ociImageSource) Close() {
}

// GetManifest returns the image's manifest along with its MIME type (which may be empty when it can't be determined but the manifest is available).
// It may use a remote (= slow) service.
func (s *ociImageSource) GetManifest() ([]byte, string, error) {
	descriptorPath := s.ref.descriptorPath(s.ref.tag)
	data, err := ioutil.ReadFile(descriptorPath)
	if err != nil {
		return nil, "", err
	}

	desc := imgspecv1.Descriptor{}
	err = json.Unmarshal(data, &desc)
	if err != nil {
		return nil, "", err
	}

	manifestPath, err := s.ref.blobPath(desc.Digest)
	if err != nil {
		return nil, "", err
	}
	m, err := ioutil.ReadFile(manifestPath)
	if err != nil {
		return nil, "", err
	}

	return m, manifest.GuessMIMEType(m), nil
}

func (s *ociImageSource) GetTargetManifest(digest string) ([]byte, string, error) {
	manifestPath, err := s.ref.blobPath(digest)
	if err != nil {
		return nil, "", err
	}

	m, err := ioutil.ReadFile(manifestPath)
	if err != nil {
		return nil, "", err
	}

	return m, manifest.GuessMIMEType(m), nil
}

// GetBlob returns a stream for the specified blob, and the blob’s size (or -1 if unknown).
func (s *ociImageSource) GetBlob(digest string) (io.ReadCloser, int64, error) {
	path, err := s.ref.blobPath(digest)
	if err != nil {
		return nil, 0, err
	}

	r, err := os.Open(path)
	if err != nil {
		return nil, 0, nil
	}
	fi, err := r.Stat()
	if err != nil {
		return nil, 0, nil
	}
	return r, fi.Size(), nil
}

func (s *ociImageSource) GetSignatures() ([][]byte, error) {
	return [][]byte{}, nil
}
<commit_msg>OCI source: return error if open blob failed<commit_after>package layout

import (
	"encoding/json"
	"io"
	"io/ioutil"
	"os"

	"github.com/containers/image/manifest"
	"github.com/containers/image/types"
	imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
)

type ociImageSource struct {
	ref ociReference
}

// newImageSource returns an ImageSource for reading from an existing directory.
func newImageSource(ref ociReference) types.ImageSource {
	return &ociImageSource{ref: ref}
}

// Reference returns the reference used to set up this source.
func (s *ociImageSource) Reference() types.ImageReference {
	return s.ref
}

// Close removes resources associated with an initialized ImageSource, if any.
func (s *ociImageSource) Close() {
}

// GetManifest returns the image's manifest along with its MIME type (which may be empty when it can't be determined but the manifest is available).
// It may use a remote (= slow) service.
func (s *ociImageSource) GetManifest() ([]byte, string, error) {
	descriptorPath := s.ref.descriptorPath(s.ref.tag)
	data, err := ioutil.ReadFile(descriptorPath)
	if err != nil {
		return nil, "", err
	}

	desc := imgspecv1.Descriptor{}
	err = json.Unmarshal(data, &desc)
	if err != nil {
		return nil, "", err
	}

	manifestPath, err := s.ref.blobPath(desc.Digest)
	if err != nil {
		return nil, "", err
	}
	m, err := ioutil.ReadFile(manifestPath)
	if err != nil {
		return nil, "", err
	}

	return m, manifest.GuessMIMEType(m), nil
}

func (s *ociImageSource) GetTargetManifest(digest string) ([]byte, string, error) {
	manifestPath, err := s.ref.blobPath(digest)
	if err != nil {
		return nil, "", err
	}

	m, err := ioutil.ReadFile(manifestPath)
	if err != nil {
		return nil, "", err
	}

	return m, manifest.GuessMIMEType(m), nil
}

// GetBlob returns a stream for the specified blob, and the blob's size.
func (s *ociImageSource) GetBlob(digest string) (io.ReadCloser, int64, error) {
	path, err := s.ref.blobPath(digest)
	if err != nil {
		return nil, 0, err
	}

	r, err := os.Open(path)
	if err != nil {
		return nil, 0, err
	}
	fi, err := r.Stat()
	if err != nil {
		return nil, 0, err
	}
	return r, fi.Size(), nil
}

func (s *ociImageSource) GetSignatures() ([][]byte, error) {
	return [][]byte{}, nil
}
<|endoftext|>


<commit_before>// Copyright 2015 FactomProject Authors. All rights reserved.
// Use of this source code is governed by the MIT license
// that can be found in the LICENSE file.

package process

import (
	"errors"
	"github.com/FactomProject/FactomCode/common"
	cp "github.com/FactomProject/FactomCode/controlpanel"
	"github.com/FactomProject/FactomCode/database"
	"github.com/FactomProject/btcd/wire"
	"github.com/davecgh/go-spew/spew"
	"strconv"
	"time"
)

// processDirBlock validates dir block and save it to factom db.
// similar to blockChain.BC_ProcessBlock
func processDirBlock(msg *wire.MsgDirBlock) error {

	// Error condiftion for Milestone 1
	if nodeMode == common.SERVER_NODE {
		return errors.New("Server received msg:" + msg.Command())
	}

	blk, _ := db.FetchDBlockByHeight(msg.DBlk.Header.DBHeight)
	if blk != nil {
		procLog.Info("DBlock already exists for height:" + string(msg.DBlk.Header.DBHeight))
		cp.CP.AddUpdate(
			"DBOverlap",                                                          // tag
			"warning",                                                            // Category
			"Directory Block Overlap",                                            // Title
			"DBlock already exists for height:"+string(msg.DBlk.Header.DBHeight), // Message
			0) // Expire
		return nil
	}

	msg.DBlk.IsSealed = true
	dchain.AddDBlockToDChain(msg.DBlk)

	//Add it to mem pool before saving it in db
	fMemPool.addBlockMsg(msg, strconv.Itoa(int(msg.DBlk.Header.DBHeight))) // store in mempool with the height as the key

	procLog.Debug("SyncUp: MsgDirBlock DBHeight=", msg.DBlk.Header.DBHeight)
	cp.CP.AddUpdate(
		"DBSyncUp", // tag
		"Status",   // Category
		"SyncUp:",  // Title
		"MsgDirBlock DBHeigth=:"+string(msg.DBlk.Header.DBHeight), // Message
		0) // Expire

	return nil
}

// processFBlock validates admin block and save it to factom db.
// similar to blockChain.BC_ProcessBlock
func processFBlock(msg *wire.MsgFBlock) error {

	// Error condiftion for Milestone 1
	if nodeMode == common.SERVER_NODE {
		return errors.New("Server received msg:" + msg.Command())
	}

	key, _ := msg.SC.GetHash().MarshalText()
	//Add it to mem pool before saving it in db
	fMemPool.addBlockMsg(msg, string(key)) // stored in mem pool with the MR as the key

	procLog.Debug("SyncUp: MsgFBlock DBHeight=", msg.SC.GetDBHeight())

	return nil

}

// processABlock validates admin block and save it to factom db.
// similar to blockChain.BC_ProcessBlock
func processABlock(msg *wire.MsgABlock) error {

	// Error condiftion for Milestone 1
	if nodeMode == common.SERVER_NODE {
		return errors.New("Server received msg:" + msg.Command())
	}

	//Add it to mem pool before saving it in db
	abHash, err := msg.ABlk.PartialHash()
	if err != nil {
		return err
	}
	fMemPool.addBlockMsg(msg, abHash.String()) // store in mem pool with ABHash as key

	procLog.Debug("SyncUp: MsgABlock DBHeight=", msg.ABlk.Header.DBHeight)

	return nil
}

// procesFBlock validates entry credit block and save it to factom db.
// similar to blockChain.BC_ProcessBlock
func procesECBlock(msg *wire.MsgECBlock) error {

	// Error condiftion for Milestone 1
	if nodeMode == common.SERVER_NODE {
		return errors.New("Server received msg:" + msg.Command())
	}

	//Add it to mem pool before saving it in db
	fMemPool.addBlockMsg(msg, msg.ECBlock.HeaderHash().String())

	procLog.Debug("SyncUp: MsgCBlock DBHeight=", msg.ECBlock.Header.DBHeight)

	return nil
}

// processEBlock validates entry block and save it to factom db.
// similar to blockChain.BC_ProcessBlock
func processEBlock(msg *wire.MsgEBlock) error {

	// Error condiftion for Milestone 1
	if nodeMode == common.SERVER_NODE {
		return errors.New("Server received msg:" + msg.Command())
	}
	/*
		if msg.EBlk.Header.DBHeight >= dchain.NextBlockHeight || msg.EBlk.Header.DBHeight < 0 {
			return errors.New("MsgEBlock has an invalid DBHeight:" + strconv.Itoa(int(msg.EBlk.Header.DBHeight)))
		}
	*/
	//Add it to mem pool before saving it in db
	fMemPool.addBlockMsg(msg, msg.EBlk.KeyMR().String()) // store it in mem pool with MR as the key

	procLog.Debug("SyncUp: MsgEBlock DBHeight=", msg.EBlk.Header.DBHeight)

	return nil
}

// processEntry validates entry and save it to factom db.
// similar to blockChain.BC_ProcessBlock
func processEntry(msg *wire.MsgEntry) error {

	// Error condiftion for Milestone 1
	if nodeMode == common.SERVER_NODE {
		return errors.New("Server received msg:" + msg.Command())
	}

	// store the entry in mem pool
	h := msg.Entry.Hash()
	fMemPool.addBlockMsg(msg, h.String()) // store it in mem pool with hash as the key

	procLog.Debug("SyncUp: MsgEntry hash=", msg.Entry.Hash())

	return nil
}

// Validate the new blocks in mem pool and store them in db
func validateAndStoreBlocks(fMemPool *ftmMemPool, db database.Db, dchain *common.DChain, outCtlMsgQ chan wire.FtmInternalMsg) {
	var myDBHeight int64
	var sleeptime int
	var dblk *common.DirectoryBlock

	for true {
		dblk = nil
		_, myDBHeight, _ = db.FetchBlockHeightCache()

		adj := (len(dchain.Blocks) - int(myDBHeight))
		if adj <= 0 {
			adj = 1
		}
		// in milliseconds
		sleeptime = 100 + 1000/adj

		if len(dchain.Blocks) > int(myDBHeight+1) {
			dblk = dchain.Blocks[myDBHeight+1]
		}
		if dblk != nil {
			if validateBlocksFromMemPool(dblk, fMemPool, db) {
				err := storeBlocksFromMemPool(dblk, fMemPool, db)
				if err == nil {
					deleteBlocksFromMemPool(dblk, fMemPool)
				} else {
					panic("error in deleteBlocksFromMemPool.")
				}
			} else {
				time.Sleep(time.Duration(sleeptime * 1000000)) // Nanoseconds for duration
			}
		} else {
			time.Sleep(time.Duration(sleeptime * 1000000)) // Nanoseconds for duration

			//TODO: send an internal msg to sync up with peers
		}

	}

}

// Validate the new blocks in mem pool and store them in db
func validateBlocksFromMemPool(b *common.DirectoryBlock, fMemPool *ftmMemPool, db database.Db) bool {

	// Validate the genesis block
	if b.Header.DBHeight == 0 {
		h, _ := common.CreateHash(b)
		if h.String() != common.GENESIS_DIR_BLOCK_HASH {
			// panic for milestone 1
			//panic("Genesis dir block is not as expected: " + h.String())
			procLog.Errorf("Genesis dir block is not as expected: " + h.String())
		}
	}

	for _, dbEntry := range b.DBEntries {
		switch dbEntry.ChainID.String() {
		case ecchain.ChainID.String():
			if _, ok := fMemPool.blockpool[dbEntry.KeyMR.String()]; !ok {
				return false
			}
		case achain.ChainID.String():
			if msg, ok := fMemPool.blockpool[dbEntry.KeyMR.String()]; !ok {
				return false
			} else {
				// validate signature of the previous dir block
				aBlkMsg, _ := msg.(*wire.MsgABlock)
				if !validateDBSignature(aBlkMsg.ABlk, dchain) {
					return false
				}
			}
		case fchain.ChainID.String():
			if _, ok := fMemPool.blockpool[dbEntry.KeyMR.String()]; !ok {
				return false
			}
		default:
			if msg, ok := fMemPool.blockpool[dbEntry.KeyMR.String()]; !ok {
				return false
			} else {
				eBlkMsg, _ := msg.(*wire.MsgEBlock)
				// validate every entry in EBlock
				for _, ebEntry := range eBlkMsg.EBlk.Body.EBEntries {
					if _, foundInMemPool := fMemPool.blockpool[ebEntry.String()]; !foundInMemPool {
						// continue if the entry arleady exists in db
						entry, _ := db.FetchEntryByHash(ebEntry)
						if entry == nil {
							return false
						}
					}
				}
			}
		}
	}

	return true
}

// Validate the new blocks in mem pool and store them in db
// Need to make a batch insert in db in milestone 2
func storeBlocksFromMemPool(b *common.DirectoryBlock, fMemPool *ftmMemPool, db database.Db) error {

	for _, dbEntry := range b.DBEntries {
		switch dbEntry.ChainID.String() {
		case ecchain.ChainID.String():
			ecBlkMsg := fMemPool.blockpool[dbEntry.KeyMR.String()].(*wire.MsgECBlock)
			err := db.ProcessECBlockBatch(ecBlkMsg.ECBlock)
			if err != nil {
				return err
			}
			// needs to be improved??
			initializeECreditMap(ecBlkMsg.ECBlock)
			// for debugging
			exportECBlock(ecBlkMsg.ECBlock)
		case achain.ChainID.String():
			aBlkMsg := fMemPool.blockpool[dbEntry.KeyMR.String()].(*wire.MsgABlock)
			err := db.ProcessABlockBatch(aBlkMsg.ABlk)
			if err != nil {
				return err
			}
			// for debugging
			exportABlock(aBlkMsg.ABlk)
		case fchain.ChainID.String():
			fBlkMsg := fMemPool.blockpool[dbEntry.KeyMR.String()].(*wire.MsgFBlock)
			err := db.ProcessFBlockBatch(fBlkMsg.SC)
			if err != nil {
				return err
			}
			// Initialize the Factoid State
			err = common.FactoidState.AddTransactionBlock(fBlkMsg.SC)
			FactoshisPerCredit = fBlkMsg.SC.GetExchRate()
			if err != nil {
				return err
			}

			// for debugging
			exportFctBlock(fBlkMsg.SC)
		default:
			// handle Entry Block
			eBlkMsg, _ := fMemPool.blockpool[dbEntry.KeyMR.String()].(*wire.MsgEBlock)
			// store entry in db first
			for _, ebEntry := range eBlkMsg.EBlk.Body.EBEntries {
				if msg, foundInMemPool := fMemPool.blockpool[ebEntry.String()]; foundInMemPool {
					err := db.InsertEntry(msg.(*wire.MsgEntry).Entry)
					if err != nil {
						return err
					}
				}
			}
			// Store Entry Block in db
			err := db.ProcessEBlockBatch(eBlkMsg.EBlk)
			if err != nil {
				return err
			}

			// create a chain in db if it's not existing
			chain := chainIDMap[eBlkMsg.EBlk.Header.ChainID.String()]
			if chain == nil {
				chain = new(common.EChain)
				chain.ChainID = eBlkMsg.EBlk.Header.ChainID
				if eBlkMsg.EBlk.Header.EBSequence == 0 {
					chain.FirstEntry, _ = db.FetchEntryByHash(eBlkMsg.EBlk.Body.EBEntries[0])
				}
				db.InsertChain(chain)
				chainIDMap[chain.ChainID.String()] = chain
			} else if chain.FirstEntry == nil && eBlkMsg.EBlk.Header.EBSequence == 0 {
				chain.FirstEntry, _ = db.FetchEntryByHash(eBlkMsg.EBlk.Body.EBEntries[0])
				db.InsertChain(chain)
			}

			// for debugging
			exportEBlock(eBlkMsg.EBlk)
		}
	}

	// Store the dir block
	err := db.ProcessDBlockBatch(b)
	if err != nil {
		return err
	}

	// Update dir block height cache in db
	commonHash, _ := common.CreateHash(b)
	db.UpdateBlockHeightCache(b.Header.DBHeight, commonHash)

	// for debugging
	exportDBlock(b)

	return nil
}

// Validate the new blocks in mem pool and store them in db
func deleteBlocksFromMemPool(b *common.DirectoryBlock, fMemPool *ftmMemPool) error {

	for _, dbEntry := range b.DBEntries {
		switch dbEntry.ChainID.String() {
		case ecchain.ChainID.String():
			fMemPool.deleteBlockMsg(dbEntry.KeyMR.String())
		case achain.ChainID.String():
			fMemPool.deleteBlockMsg(dbEntry.KeyMR.String())
		case fchain.ChainID.String():
			fMemPool.deleteBlockMsg(dbEntry.KeyMR.String())
		default:
			eBlkMsg, _ := fMemPool.blockpool[dbEntry.KeyMR.String()].(*wire.MsgEBlock)
			for _, ebEntry := range eBlkMsg.EBlk.Body.EBEntries {
				fMemPool.deleteBlockMsg(ebEntry.String())
			}
			fMemPool.deleteBlockMsg(dbEntry.KeyMR.String())
		}
	}
	fMemPool.deleteBlockMsg(strconv.Itoa(int(b.Header.DBHeight)))

	return nil
}

func validateDBSignature(aBlock *common.AdminBlock, dchain *common.DChain) bool {

	dbSigEntry := aBlock.GetDBSignature()
	if dbSigEntry == nil {
		if aBlock.Header.DBHeight == 0 {
			return true
		} else {
			return false
		}
	} else {
		dbSig := dbSigEntry.(*common.DBSignatureEntry)
		if serverPubKey.String() != dbSig.PubKey.String() {
			return false
		} else {
			// obtain the previous directory block
			dblk := dchain.Blocks[aBlock.Header.DBHeight-1]
			if dblk == nil {
				return false
			} else {
				// validatet the signature
				bHeader, _ := dblk.Header.MarshalBinary()
				if !serverPubKey.Verify(bHeader, (*[64]byte)(dbSig.PrevDBSig)) {
					procLog.Infof("No valid signature found in Admin Block = %s\n", spew.Sdump(aBlock))
					return false
				}
			}
		}
	}

	return true
}
<commit_msg>Following factoid refactoring.<commit_after>// Copyright 2015 FactomProject Authors. All rights reserved.
// Use of this source code is governed by the MIT license
// that can be found in the LICENSE file.

package process

import (
	"errors"
	"github.com/FactomProject/FactomCode/common"
	cp "github.com/FactomProject/FactomCode/controlpanel"
	"github.com/FactomProject/FactomCode/database"
	"github.com/FactomProject/btcd/wire"
	"github.com/davecgh/go-spew/spew"
	"strconv"
	"time"
)

// processDirBlock validates dir block and save it to factom db.
// similar to blockChain.BC_ProcessBlock
func processDirBlock(msg *wire.MsgDirBlock) error {

	// Error condiftion for Milestone 1
	if nodeMode == common.SERVER_NODE {
		return errors.New("Server received msg:" + msg.Command())
	}

	blk, _ := db.FetchDBlockByHeight(msg.DBlk.Header.DBHeight)
	if blk != nil {
		procLog.Info("DBlock already exists for height:" + string(msg.DBlk.Header.DBHeight))
		cp.CP.AddUpdate(
			"DBOverlap",                                                          // tag
			"warning",                                                            // Category
			"Directory Block Overlap",                                            // Title
			"DBlock already exists for height:"+string(msg.DBlk.Header.DBHeight), // Message
			0) // Expire
		return nil
	}

	msg.DBlk.IsSealed = true
	dchain.AddDBlockToDChain(msg.DBlk)

	//Add it to mem pool before saving it in db
	fMemPool.addBlockMsg(msg, strconv.Itoa(int(msg.DBlk.Header.DBHeight))) // store in mempool with the height as the key

	procLog.Debug("SyncUp: MsgDirBlock DBHeight=", msg.DBlk.Header.DBHeight)
	cp.CP.AddUpdate(
		"DBSyncUp", // tag
		"Status",   // Category
		"SyncUp:",  // Title
		"MsgDirBlock DBHeigth=:"+string(msg.DBlk.Header.DBHeight), // Message
		0) // Expire

	return nil
}

// processFBlock validates admin block and save it to factom db.
// similar to blockChain.BC_ProcessBlock
func processFBlock(msg *wire.MsgFBlock) error {

	// Error condiftion for Milestone 1
	if nodeMode == common.SERVER_NODE {
		return errors.New("Server received msg:" + msg.Command())
	}

	key, _ := msg.SC.GetHash().CustomMarshalText()
	//Add it to mem pool before saving it in db
	fMemPool.addBlockMsg(msg, string(key)) // stored in mem pool with the MR as the key

	procLog.Debug("SyncUp: MsgFBlock DBHeight=", msg.SC.GetDBHeight())

	return nil

}

// processABlock validates admin block and save it to factom db.
// similar to blockChain.BC_ProcessBlock
func processABlock(msg *wire.MsgABlock) error {

	// Error condiftion for Milestone 1
	if nodeMode == common.SERVER_NODE {
		return errors.New("Server received msg:" + msg.Command())
	}

	//Add it to mem pool before saving it in db
	abHash, err := msg.ABlk.PartialHash()
	if err != nil {
		return err
	}
	fMemPool.addBlockMsg(msg, abHash.String()) // store in mem pool with ABHash as key

	procLog.Debug("SyncUp: MsgABlock DBHeight=", msg.ABlk.Header.DBHeight)

	return nil
}

// procesFBlock validates entry credit block and save it to factom db.
// similar to blockChain.BC_ProcessBlock
func procesECBlock(msg *wire.MsgECBlock) error {

	// Error condiftion for Milestone 1
	if nodeMode == common.SERVER_NODE {
		return errors.New("Server received msg:" + msg.Command())
	}

	//Add it to mem pool before saving it in db
	fMemPool.addBlockMsg(msg, msg.ECBlock.HeaderHash().String())

	procLog.Debug("SyncUp: MsgCBlock DBHeight=", msg.ECBlock.Header.DBHeight)

	return nil
}

// processEBlock validates entry block and save it to factom db.
// similar to blockChain.BC_ProcessBlock
func processEBlock(msg *wire.MsgEBlock) error {

	// Error condiftion for Milestone 1
	if nodeMode == common.SERVER_NODE {
		return errors.New("Server received msg:" + msg.Command())
	}
	/*
		if msg.EBlk.Header.DBHeight >= dchain.NextBlockHeight || msg.EBlk.Header.DBHeight < 0 {
			return errors.New("MsgEBlock has an invalid DBHeight:" + strconv.Itoa(int(msg.EBlk.Header.DBHeight)))
		}
	*/
	//Add it to mem pool before saving it in db
	fMemPool.addBlockMsg(msg, msg.EBlk.KeyMR().String()) // store it in mem pool with MR as the key

	procLog.Debug("SyncUp: MsgEBlock DBHeight=", msg.EBlk.Header.DBHeight)

	return nil
}

// processEntry validates entry and save it to factom db.
// similar to blockChain.BC_ProcessBlock
func processEntry(msg *wire.MsgEntry) error {

	// Error condiftion for Milestone 1
	if nodeMode == common.SERVER_NODE {
		return errors.New("Server received msg:" + msg.Command())
	}

	// store the entry in mem pool
	h := msg.Entry.Hash()
	fMemPool.addBlockMsg(msg, h.String()) // store it in mem pool with hash as the key

	procLog.Debug("SyncUp: MsgEntry hash=", msg.Entry.Hash())

	return nil
}

// Validate the new blocks in mem pool and store them in db
func validateAndStoreBlocks(fMemPool *ftmMemPool, db database.Db, dchain *common.DChain, outCtlMsgQ chan wire.FtmInternalMsg) {
	var myDBHeight int64
	var sleeptime int
	var dblk *common.DirectoryBlock

	for true {
		dblk = nil
		_, myDBHeight, _ = db.FetchBlockHeightCache()

		adj := (len(dchain.Blocks) - int(myDBHeight))
		if adj <= 0 {
			adj = 1
		}
		// in milliseconds
		sleeptime = 100 + 1000/adj

		if len(dchain.Blocks) > int(myDBHeight+1) {
			dblk = dchain.Blocks[myDBHeight+1]
		}
		if dblk != nil {
			if validateBlocksFromMemPool(dblk, fMemPool, db) {
				err := storeBlocksFromMemPool(dblk, fMemPool, db)
				if err == nil {
					deleteBlocksFromMemPool(dblk, fMemPool)
				} else {
					panic("error in deleteBlocksFromMemPool.")
				}
			} else {
				time.Sleep(time.Duration(sleeptime * 1000000)) // Nanoseconds for duration
			}
		} else {
			time.Sleep(time.Duration(sleeptime * 1000000)) // Nanoseconds for duration

			//TODO: send an internal msg to sync up with peers
		}

	}

}

// Validate the new blocks in mem pool and store them in db
func validateBlocksFromMemPool(b *common.DirectoryBlock, fMemPool *ftmMemPool, db database.Db) bool {

	// Validate the genesis block
	if b.Header.DBHeight == 0 {
		h, _ := common.CreateHash(b)
		if h.String() != common.GENESIS_DIR_BLOCK_HASH {
			// panic for milestone 1
			//panic("Genesis dir block is not as expected: " + h.String())
			procLog.Errorf("Genesis dir block is not as expected: " + h.String())
		}
	}

	for _, dbEntry := range b.DBEntries {
		switch dbEntry.ChainID.String() {
		case ecchain.ChainID.String():
			if _, ok := fMemPool.blockpool[dbEntry.KeyMR.String()]; !ok {
				return false
			}
		case achain.ChainID.String():
			if msg, ok := fMemPool.blockpool[dbEntry.KeyMR.String()]; !ok {
				return false
			} else {
				// validate signature of the previous dir block
				aBlkMsg, _ := msg.(*wire.MsgABlock)
				if !validateDBSignature(aBlkMsg.ABlk, dchain) {
					return false
				}
			}
		case fchain.ChainID.String():
			if _, ok := fMemPool.blockpool[dbEntry.KeyMR.String()]; !ok {
				return false
			}
		default:
			if msg, ok := fMemPool.blockpool[dbEntry.KeyMR.String()]; !ok {
				return false
			} else {
				eBlkMsg, _ := msg.(*wire.MsgEBlock)
				// validate every entry in EBlock
				for _, ebEntry := range eBlkMsg.EBlk.Body.EBEntries {
					if _, foundInMemPool := fMemPool.blockpool[ebEntry.String()]; !foundInMemPool {
						// continue if the entry arleady exists in db
						entry, _ := db.FetchEntryByHash(ebEntry)
						if entry == nil {
							return false
						}
					}
				}
			}
		}
	}

	return true
}

// Validate the new blocks in mem pool and store them in db
// Need to make a batch insert in db in milestone 2
func storeBlocksFromMemPool(b *common.DirectoryBlock, fMemPool *ftmMemPool, db database.Db) error {

	for _, dbEntry := range b.DBEntries {
		switch dbEntry.ChainID.String() {
		case ecchain.ChainID.String():
			ecBlkMsg := fMemPool.blockpool[dbEntry.KeyMR.String()].(*wire.MsgECBlock)
			err := db.ProcessECBlockBatch(ecBlkMsg.ECBlock)
			if err != nil {
				return err
			}
			// needs to be improved??
			initializeECreditMap(ecBlkMsg.ECBlock)
			// for debugging
			exportECBlock(ecBlkMsg.ECBlock)
		case achain.ChainID.String():
			aBlkMsg := fMemPool.blockpool[dbEntry.KeyMR.String()].(*wire.MsgABlock)
			err := db.ProcessABlockBatch(aBlkMsg.ABlk)
			if err != nil {
				return err
			}
			// for debugging
			exportABlock(aBlkMsg.ABlk)
		case fchain.ChainID.String():
			fBlkMsg := fMemPool.blockpool[dbEntry.KeyMR.String()].(*wire.MsgFBlock)
			err := db.ProcessFBlockBatch(fBlkMsg.SC)
			if err != nil {
				return err
			}
			// Initialize the Factoid State
			err = common.FactoidState.AddTransactionBlock(fBlkMsg.SC)
			FactoshisPerCredit = fBlkMsg.SC.GetExchRate()
			if err != nil {
				return err
			}

			// for debugging
			exportFctBlock(fBlkMsg.SC)
		default:
			// handle Entry Block
			eBlkMsg, _ := fMemPool.blockpool[dbEntry.KeyMR.String()].(*wire.MsgEBlock)
			// store entry in db first
			for _, ebEntry := range eBlkMsg.EBlk.Body.EBEntries {
				if msg, foundInMemPool := fMemPool.blockpool[ebEntry.String()]; foundInMemPool {
					err := db.InsertEntry(msg.(*wire.MsgEntry).Entry)
					if err != nil {
						return err
					}
				}
			}
			// Store Entry Block in db
			err := db.ProcessEBlockBatch(eBlkMsg.EBlk)
			if err != nil {
				return err
			}

			// create a chain in db if it's not existing
			chain := chainIDMap[eBlkMsg.EBlk.Header.ChainID.String()]
			if chain == nil {
				chain = new(common.EChain)
				chain.ChainID = eBlkMsg.EBlk.Header.ChainID
				if eBlkMsg.EBlk.Header.EBSequence == 0 {
					chain.FirstEntry, _ = db.FetchEntryByHash(eBlkMsg.EBlk.Body.EBEntries[0])
				}
				db.InsertChain(chain)
				chainIDMap[chain.ChainID.String()] = chain
			} else if chain.FirstEntry == nil && eBlkMsg.EBlk.Header.EBSequence == 0 {
				chain.FirstEntry, _ = db.FetchEntryByHash(eBlkMsg.EBlk.Body.EBEntries[0])
				db.InsertChain(chain)
			}

			// for debugging
			exportEBlock(eBlkMsg.EBlk)
		}
	}

	// Store the dir block
	err := db.ProcessDBlockBatch(b)
	if err != nil {
		return err
	}

	// Update dir block height cache in db
	commonHash, _ := common.CreateHash(b)
	db.UpdateBlockHeightCache(b.Header.DBHeight, commonHash)

	// for debugging
	exportDBlock(b)

	return nil
}

// Validate the new blocks in mem pool and store them in db
func deleteBlocksFromMemPool(b *common.DirectoryBlock, fMemPool *ftmMemPool) error {

	for _, dbEntry := range b.DBEntries {
		switch dbEntry.ChainID.String() {
		case ecchain.ChainID.String():
			fMemPool.deleteBlockMsg(dbEntry.KeyMR.String())
		case achain.ChainID.String():
			fMemPool.deleteBlockMsg(dbEntry.KeyMR.String())
		case fchain.ChainID.String():
			fMemPool.deleteBlockMsg(dbEntry.KeyMR.String())
		default:
			eBlkMsg, _ := fMemPool.blockpool[dbEntry.KeyMR.String()].(*wire.MsgEBlock)
			for _, ebEntry := range eBlkMsg.EBlk.Body.EBEntries {
				fMemPool.deleteBlockMsg(ebEntry.String())
			}
			fMemPool.deleteBlockMsg(dbEntry.KeyMR.String())
		}
	}
	fMemPool.deleteBlockMsg(strconv.Itoa(int(b.Header.DBHeight)))

	return nil
}

func validateDBSignature(aBlock *common.AdminBlock, dchain *common.DChain) bool {

	dbSigEntry := aBlock.GetDBSignature()
	if dbSigEntry == nil {
		if aBlock.Header.DBHeight == 0 {
			return true
		} else {
			return false
		}
	} else {
		dbSig := dbSigEntry.(*common.DBSignatureEntry)
		if serverPubKey.String() != dbSig.PubKey.String() {
			return false
		} else {
			// obtain the previous directory block
			dblk := dchain.Blocks[aBlock.Header.DBHeight-1]
			if dblk == nil {
				return false
			} else {
				// validatet the signature
				bHeader, _ := dblk.Header.MarshalBinary()
				if !serverPubKey.Verify(bHeader, (*[64]byte)(dbSig.PrevDBSig)) {
					procLog.Infof("No valid signature found in Admin Block = %s\n", spew.Sdump(aBlock))
					return false
				}
			}
		}
	}

	return true
}
<|endoftext|>


<commit_before>package cite

import (
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestParseDirective(t *testing.T) {
	line := "insert: https://www.rfc-editor.org/rfc/rfc918.txt (13-16)"
	dir, err := ParseDirective(line)
	require.NoError(t, err)
	assert.Equal(t, "insert", dir.ActionRaw)
	assert.Equal(t, "https://www.rfc-editor.org/rfc/rfc918.txt", dir.Citation.URL.String())
	assert.Equal(t, "13-16", dir.Citation.Extra)
}

func TestParseDirectiveNoExtra(t *testing.T) {
	line := "Action: http://google.org"
	dir, err := ParseDirective(line)
	require.NoError(t, err)
	assert.Equal(t, "Action", dir.ActionRaw)
	assert.Equal(t, "http://google.org", dir.Citation.URL.String())
	assert.Equal(t, "", dir.Citation.Extra)
}

func TestParseDirectiveGarbage(t *testing.T) {
	line := "jk lol"
	dir, err := ParseDirective(line)
	assert.Nil(t, dir)
	assert.NoError(t, err)
}

// TestParseDirectiveBadURL tests the case where the URL regular expression
// matches but the extracted URL does not parse. This should be a rare case,
// but it is possible to find examples ("http%") being the most compact.
func TestParseDirectiveBadURL(t *testing.T) {
	line := "Action: http%"
	dir, err := ParseDirective(line)
	assert.Error(t, err)
	assert.Nil(t, dir)
}

func TestDirectiveAction(t *testing.T) {
	dir := Directive{
		ActionRaw: "MiXeDCAsE",
	}
	assert.Equal(t, "mixedcase", dir.Action())
}
<commit_msg>Processor tests<commit_after>package cite

import (
	"bytes"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestParseDirective(t *testing.T) {
	line := "insert: https://www.rfc-editor.org/rfc/rfc918.txt (13-16)"
	dir, err := ParseDirective(line)
	require.NoError(t, err)
	assert.Equal(t, "insert", dir.ActionRaw)
	assert.Equal(t, "https://www.rfc-editor.org/rfc/rfc918.txt", dir.Citation.URL.String())
	assert.Equal(t, "13-16", dir.Citation.Extra)
}

func TestParseDirectiveNoExtra(t *testing.T) {
	line := "Action: http://google.org"
	dir, err := ParseDirective(line)
	require.NoError(t, err)
	assert.Equal(t, "Action", dir.ActionRaw)
	assert.Equal(t, "http://google.org", dir.Citation.URL.String())
	assert.Equal(t, "", dir.Citation.Extra)
}

func TestParseDirectiveGarbage(t *testing.T) {
	line := "jk lol"
	dir, err := ParseDirective(line)
	assert.Nil(t, dir)
	assert.NoError(t, err)
}

// TestParseDirectiveBadURL tests the case where the URL regular expression
// matches but the extracted URL does not parse. This should be a rare case,
// but it is possible to find examples ("http%") being the most compact.
func TestParseDirectiveBadURL(t *testing.T) {
	line := "Action: http%"
	dir, err := ParseDirective(line)
	assert.Error(t, err)
	assert.Nil(t, dir)
}

func TestDirectiveAction(t *testing.T) {
	dir := Directive{
		ActionRaw: "MiXeDCAsE",
	}
	assert.Equal(t, "mixedcase", dir.Action())
}

func BuildSingleCommentSource(line string) Source {
	comment := "// " + line
	code := bytes.NewReader([]byte(comment))
	return ParseCode(code)
}

func TestProcessLinesParseDirectiveError(t *testing.T) {
	p := NewProcessor(nil)
	src := BuildSingleCommentSource("Action: http%")
	_, err := p.Process(src)
	assert.Error(t, err)
}

func TestProcessLinesUnknownResource(t *testing.T) {
	p := NewProcessor(nil)
	src := BuildSingleCommentSource("Action: http://unknown.com")
	_, err := p.Process(src)
	assert.Equal(t, ErrUnknownResource, err)
}

func TestProcessLinesBadResource(t *testing.T) {
	builders := []ResourceBuilder{BuildGithubResourceFromCitation}
	p := NewProcessor(builders)
	src := BuildSingleCommentSource("Action: http://github.com/bad/path")
	_, err := p.Process(src)
	assert.Error(t, err)
}

func TestProcessLinesErrUnknownAction(t *testing.T) {
	builders := []ResourceBuilder{BuildPlainResourceFromCitation}
	p := NewProcessor(builders)
	src := BuildSingleCommentSource("Action: http://website.com/doc.txt (1-2)")
	_, err := p.Process(src)
	assert.Equal(t, ErrUnknownAction, err)
}

func TestProcessLinesHandlerError(t *testing.T) {
	builders := []ResourceBuilder{BuildPlainResourceFromCitation}
	p := NewProcessor(builders)
	p.AddHandler("action", func(_ Resource, _ []string) ([]string, []string, error) {
		return nil, nil, assert.AnError
	})
	src := BuildSingleCommentSource("Action: http://website.com/doc.txt (1-2)")
	_, err := p.Process(src)
	assert.Equal(t, assert.AnError, err)
}

// TODO error getting resource (eg bad github ref)
// TODO didnt find any resource
// TODO no handler for action
// TODO error in handler
<|endoftext|>


<commit_before>// Copyright 2012 The go-gl 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 gltext

// A Glyph describes metrics for a single font glyph.
// These indicate which area of a given image contains the
// glyph data and how the glyph should be spaced in a rendered string.
type Point struct {
	X float32
	Y float32
}

type Glyph struct {
	X      int `json:"x"`      // The x location of the glyph on a sprite sheet.
	Y      int `json:"y"`      // The y location of the glyph on a sprite sheet.
	Width  int `json:"width"`  // The width of the glyph on a sprite sheet.
	Height int `json:"height"` // The height of the glyph on a sprite sheet.

	// Advance determines the distance to the next glyph.
	// This is used to properly align non-monospaced fonts.
	Advance int `json:"advance"`
}

func (g *Glyph) GetTexturePositions(font FontLike) (tP1, tP2 Point) {
	// Quad width/height
	vw := float32(g.Width)
	vh := float32(g.Height)

	// Unfortunately with the current font, if I don't add a small offset to the Y axis location
	// the bottom edge of the character above might appear.
	//
	// EG:
	// Wrapping 16 characters per line:
	// runesPerRow := fixed.Int26_6(16)
	// runeRanges := make(gltext.RuneRanges, 0)
	// runeRange := gltext.RuneRange{Low: 1, High: 128}
	// runeRanges = append(runeRanges, runeRange)
	//
	// The resulting image file will place "g" above "w".  The very bottom edge of "g" will show up
	// when using the "w" character in a line of text. So the dirty hack is to remove just a bit of
	// the original top as per below.  This is not ideal.  Either I am not understanding something
	// about the glyph layout or this will have to be tweaked based on the font being used.
	// See the file example_image.png.

	// texture point 1
	tP1 = Point{X: float32(g.X) / font.GetTextureWidth(), Y: float32(g.Y+1) / font.GetTextureHeight()}

	// texture point 2
	tP2 = Point{X: (float32(g.X) + vw) / font.GetTextureWidth(), Y: (float32(g.Y) + vh) / font.GetTextureHeight()}

	return
}

// A Charset represents a set of glyph descriptors for a font.
// Each glyph descriptor holds glyph metrics which are used to
// properly align the given glyph in the resulting rendered string.
type Charset []Glyph

// Scale scales all glyphs by the given factor and repositions them
// appropriately. A scale of 1 retains the original size. A scale of 2
// doubles the size of each glyph, etc.
//
// This is useful when the accompanying sprite sheet is scaled by the
// same factor. In this case, we want the glyph data to match up with the
// new image.
func (c Charset) Scale(factor int) {
	if factor <= 1 {
		// A factor of zero results in zero-sized glyphs and
		// is therefore not valid. A factor of 1 does not change
		// the glyphs, so we can ignore it.
		return
	}

	// Multiply each glyph field by the given factor
	// to scale them up to the new size.
	for i := range c {
		c[i].X *= factor
		c[i].Y *= factor
		c[i].Width *= factor
		c[i].Height *= factor
		c[i].Advance *= factor
	}
}
<commit_msg>Removed typo.<commit_after>// Copyright 2012 The go-gl 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 gltext

// A Glyph describes metrics for a single font glyph.
// These indicate which area of a given image contains the
// glyph data and how the glyph should be spaced in a rendered string.
type Point struct {
	X float32
	Y float32
}

type Glyph struct {
	X      int `json:"x"`      // The x location of the glyph on a sprite sheet.
	Y      int `json:"y"`      // The y location of the glyph on a sprite sheet.
	Width  int `json:"width"`  // The width of the glyph on a sprite sheet.
	Height int `json:"height"` // The height of the glyph on a sprite sheet.

	// Advance determines the distance to the next glyph.
	// This is used to properly align non-monospaced fonts.
	Advance int `json:"advance"`
}

func (g *Glyph) GetTexturePositions(font FontLike) (tP1, tP2 Point) {
	// Quad width/height
	vw := float32(g.Width)
	vh := float32(g.Height)

	// Unfortunately with the current font, if I don't add a small offset to the Y axis location
	// the bottom edge of the character above might appear.
	//
	// EG:
	// Wrapping 16 characters per line:
	// runesPerRow := fixed.Int26_6(16)
	// runeRanges := make(gltext.RuneRanges, 0)
	// runeRange := gltext.RuneRange{Low: 1, High: 128}
	// runeRanges = append(runeRanges, runeRange)
	//
	// The resulting image file will place "g" above "w".  The very bottom edge of "g" will show up
	// when using the "w" character in a line of text. So the dirty hack is to remove just a bit of
	// the original top as per below.  This is not ideal.  Either I am not understanding something
	// about the glyph layout or this will have to be tweaked based on the font being used.
	// See the file example_image.png.

	// texture point 1
	tP1 = Point{X: float32(g.X) / font.GetTextureWidth(), Y: float32(g.Y) / font.GetTextureHeight()}

	// texture point 2
	tP2 = Point{X: (float32(g.X) + vw) / font.GetTextureWidth(), Y: (float32(g.Y) + vh) / font.GetTextureHeight()}

	return
}

// A Charset represents a set of glyph descriptors for a font.
// Each glyph descriptor holds glyph metrics which are used to
// properly align the given glyph in the resulting rendered string.
type Charset []Glyph

// Scale scales all glyphs by the given factor and repositions them
// appropriately. A scale of 1 retains the original size. A scale of 2
// doubles the size of each glyph, etc.
//
// This is useful when the accompanying sprite sheet is scaled by the
// same factor. In this case, we want the glyph data to match up with the
// new image.
func (c Charset) Scale(factor int) {
	if factor <= 1 {
		// A factor of zero results in zero-sized glyphs and
		// is therefore not valid. A factor of 1 does not change
		// the glyphs, so we can ignore it.
		return
	}

	// Multiply each glyph field by the given factor
	// to scale them up to the new size.
	for i := range c {
		c[i].X *= factor
		c[i].Y *= factor
		c[i].Width *= factor
		c[i].Height *= factor
		c[i].Advance *= factor
	}
}
<|endoftext|>