<commit_before>package openstack

import (
	"fmt"
	"io"
	"launchpad.net/goose/errors"
	"launchpad.net/goose/swift"
	"launchpad.net/juju-core/environs"
	"sync"
	"time"
)

// storage implements environs.Storage on an OpenStack container.
type storage struct {
	sync.Mutex
	madeContainer bool
	containerName string
	containerACL  swift.ACL
	swift         *swift.Client
}

// makeContainer makes the environment's control container, the
// place where bootstrap information and deployed charms
// are stored. To avoid two round trips on every PUT operation,
// we do this only once for each environ.
func (s *storage) makeContainer(containerName string, containerACL swift.ACL) error {
	s.Lock()
	defer s.Unlock()
	if s.madeContainer {
		return nil
	}
	// try to make the container - CreateContainer will succeed if the container already exists.
	err := s.swift.CreateContainer(containerName, containerACL)
	if err == nil {
		s.madeContainer = true
	}
	return err
}

func (s *storage) Put(file string, r io.Reader, length int64) error {
	if err := s.makeContainer(s.containerName, s.containerACL); err != nil {
		return fmt.Errorf("cannot make Swift control container: %v", err)
	}
	err := s.swift.PutReader(s.containerName, file, r, length)
	if err != nil {
		return fmt.Errorf("cannot write file %q to control container %q: %v", file, s.containerName, err)
	}
	return nil
}

func (s *storage) Get(file string) (r io.ReadCloser, err error) {
	for a := shortAttempt.Start(); a.Next(); {
		r, err = s.swift.GetReader(s.containerName, file)
		if errors.IsNotFound(err) {
			continue
		}
	}
	err, _ = maybeNotFound(err)
	if err != nil {
		return nil, err
	}
	return r, nil
}

func (s *storage) URL(name string) (string, error) {
	// 10 years should be good enough.
	expires := time.Now().AddDate(10, 0, 0)
	return s.swift.SignedURL(s.containerName, name, expires)
}

func (s *storage) Remove(file string) error {
	err := s.swift.DeleteObject(s.containerName, file)
	// If we can't delete the object because the bucket doesn't
	// exist, then we don't care.
	if err, ok := maybeNotFound(err); !ok {
		return err
	}
	return nil
}

func (s *storage) List(prefix string) ([]string, error) {
	contents, err := s.swift.List(s.containerName, prefix, "", "", 0)
	if err != nil {
		// If the container is not found, it's not an error
		// because it's only created when the first
		// file is put.
		if err, ok := maybeNotFound(err); !ok {
			return nil, err
		}
		return nil, nil
	}
	var names []string
	for _, item := range contents {
		names = append(names, item.Name)
	}
	return names, nil
}

func (s *storage) deleteAll() error {
	names, err := s.List("")
	if err != nil {
		return err
	}
	// Remove all the objects in parallel so that we incur less round-trips.
	// If we're in danger of having hundreds of objects,
	// we'll want to change this to limit the number
	// of concurrent operations.
	if len(names) > 100 {
		return fmt.Errorf("Too many files to remove: %d", len(names))
	}
	var wg sync.WaitGroup
	wg.Add(len(names))
	errc := make(chan error, len(names))
	for _, name := range names {
		name := name
		go func() {
			if err := s.Remove(name); err != nil {
				errc <- err
			}
			wg.Done()
		}()
	}
	wg.Wait()
	select {
	case err := <-errc:
		return fmt.Errorf("cannot delete all provider state: %v", err)
	default:
	}

	s.Lock()
	defer s.Unlock()
	// Even DeleteContainer fails, it won't harm if we try again - the operation
	// might have succeeded even if we get an error.
	s.madeContainer = false
	err = s.swift.DeleteContainer(s.containerName)
	err, ok := maybeNotFound(err)
	if ok {
		return nil
	}
	return err
}

// maybeNotFound returns a environs.NotFoundError if the root cause of the specified error is due to a file or
// container not being found.
func maybeNotFound(err error) (error, bool) {
	if err != nil && errors.IsNotFound(err) {
		return &environs.NotFoundError{err}, true
	}
	return err, false
}
<commit_msg>Add missing return statement<commit_after>package openstack

import (
	"fmt"
	"io"
	"launchpad.net/goose/errors"
	"launchpad.net/goose/swift"
	"launchpad.net/juju-core/environs"
	"sync"
	"time"
)

// storage implements environs.Storage on an OpenStack container.
type storage struct {
	sync.Mutex
	madeContainer bool
	containerName string
	containerACL  swift.ACL
	swift         *swift.Client
}

// makeContainer makes the environment's control container, the
// place where bootstrap information and deployed charms
// are stored. To avoid two round trips on every PUT operation,
// we do this only once for each environ.
func (s *storage) makeContainer(containerName string, containerACL swift.ACL) error {
	s.Lock()
	defer s.Unlock()
	if s.madeContainer {
		return nil
	}
	// try to make the container - CreateContainer will succeed if the container already exists.
	err := s.swift.CreateContainer(containerName, containerACL)
	if err == nil {
		s.madeContainer = true
	}
	return err
}

func (s *storage) Put(file string, r io.Reader, length int64) error {
	if err := s.makeContainer(s.containerName, s.containerACL); err != nil {
		return fmt.Errorf("cannot make Swift control container: %v", err)
	}
	err := s.swift.PutReader(s.containerName, file, r, length)
	if err != nil {
		return fmt.Errorf("cannot write file %q to control container %q: %v", file, s.containerName, err)
	}
	return nil
}

func (s *storage) Get(file string) (r io.ReadCloser, err error) {
	for a := shortAttempt.Start(); a.Next(); {
		r, err = s.swift.GetReader(s.containerName, file)
		if errors.IsNotFound(err) {
			continue
		}
		return
	}
	err, _ = maybeNotFound(err)
	if err != nil {
		return nil, err
	}
	return r, nil
}

func (s *storage) URL(name string) (string, error) {
	// 10 years should be good enough.
	expires := time.Now().AddDate(10, 0, 0)
	return s.swift.SignedURL(s.containerName, name, expires)
}

func (s *storage) Remove(file string) error {
	err := s.swift.DeleteObject(s.containerName, file)
	// If we can't delete the object because the bucket doesn't
	// exist, then we don't care.
	if err, ok := maybeNotFound(err); !ok {
		return err
	}
	return nil
}

func (s *storage) List(prefix string) ([]string, error) {
	contents, err := s.swift.List(s.containerName, prefix, "", "", 0)
	if err != nil {
		// If the container is not found, it's not an error
		// because it's only created when the first
		// file is put.
		if err, ok := maybeNotFound(err); !ok {
			return nil, err
		}
		return nil, nil
	}
	var names []string
	for _, item := range contents {
		names = append(names, item.Name)
	}
	return names, nil
}

func (s *storage) deleteAll() error {
	names, err := s.List("")
	if err != nil {
		return err
	}
	// Remove all the objects in parallel so that we incur less round-trips.
	// If we're in danger of having hundreds of objects,
	// we'll want to change this to limit the number
	// of concurrent operations.
	if len(names) > 100 {
		return fmt.Errorf("Too many files to remove: %d", len(names))
	}
	var wg sync.WaitGroup
	wg.Add(len(names))
	errc := make(chan error, len(names))
	for _, name := range names {
		name := name
		go func() {
			if err := s.Remove(name); err != nil {
				errc <- err
			}
			wg.Done()
		}()
	}
	wg.Wait()
	select {
	case err := <-errc:
		return fmt.Errorf("cannot delete all provider state: %v", err)
	default:
	}

	s.Lock()
	defer s.Unlock()
	// Even DeleteContainer fails, it won't harm if we try again - the operation
	// might have succeeded even if we get an error.
	s.madeContainer = false
	err = s.swift.DeleteContainer(s.containerName)
	err, ok := maybeNotFound(err)
	if ok {
		return nil
	}
	return err
}

// maybeNotFound returns a environs.NotFoundError if the root cause of the specified error is due to a file or
// container not being found.
func maybeNotFound(err error) (error, bool) {
	if err != nil && errors.IsNotFound(err) {
		return &environs.NotFoundError{err}, true
	}
	return err, false
}
<|endoftext|>


<commit_before>// Copyright 2017 Tom Thorogood. All rights reserved.
// Use of this source code is governed by a Modified
// BSD License that can be found in the LICENSE file.

// Package id3v2 implements support for reading ID3v2 tags.
package id3v2

//go:generate go run generate_ids.go

import (
	"bufio"
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"sync"
	"unicode/utf16"
)

// This is an implementation of v2.4.0 of the ID3v2 tagging format,
// defined in: http://id3.org/id3v2.4.0-structure, and v2.3.0 of
// the ID3v2 tagging format, defined in: http://id3.org/id3v2.3.0.

// Version is the version of the ID3v2 tag block.
type Version byte

const (
	// Version24 is v2.4.x of the ID3v2 specification.
	Version24 Version = 0x04
	// Version23 is v2.3.x of the ID3v2 specification.
	Version23 Version = 0x03
)

const (
	tagFlagUnsynchronisation = 1 << (7 - iota)
	tagFlagExtendedHeader
	tagFlagExperimental
	tagFlagFooter

	knownTagFlags = tagFlagUnsynchronisation | tagFlagExtendedHeader |
		tagFlagExperimental | tagFlagFooter
)

// FrameFlags are the frame-level ID3v2 flags.
type FrameFlags uint16

// These are the frame-level flags from v2.4.0 of the specification.
const (
	_ FrameFlags = 1 << (15 - iota)
	FrameFlagV24TagAlterPreservation
	FrameFlagV24FileAlterPreservation
	FrameFlagV24ReadOnly
	_
	_
	_
	_
	_
	FrameFlagV24GroupingIdentity
	_
	_
	FrameFlagV24Compression
	FrameFlagV24Encryption
	FrameFlagV24Unsynchronisation
	FrameFlagV24DataLengthIndicator
)

// These are the frame-level flags from v2.3.0 of the specification.
const (
	FrameFlagV23TagAlterPreservation FrameFlags = 1 << (15 - iota)
	FrameFlagV23FileAlterPreservation
	FrameFlagV23ReadOnly
	_
	_
	_
	_
	_
	FrameFlagV23Compression
	FrameFlagV23Encryption
	FrameFlagV23GroupingIdentity
)

const encodingFrameFlags FrameFlags = 0x00ff

const (
	textEncodingISO88591 = 0x00
	textEncodingUTF16    = 0x01
	textEncodingUTF16BE  = 0x02
	textEncodingUTF8     = 0x03
)

// FrameID is a four-byte frame identifier.
type FrameID uint32

const syncsafeInvalid = ^uint32(0)

func syncsafe(data []byte) uint32 {
	_ = data[3]

	if data[0]&0x80 != 0 || data[1]&0x80 != 0 ||
		data[2]&0x80 != 0 || data[3]&0x80 != 0 {
		return syncsafeInvalid
	}

	return uint32(data[0])<<21 | uint32(data[1])<<14 |
		uint32(data[2])<<7 | uint32(data[3])
}

func id3Split(data []byte, atEOF bool) (advance int, token []byte, err error) {
	i := bytes.Index(data, []byte("ID3"))
	if i == -1 {
		if len(data) < 2 {
			return 0, nil, nil
		}

		return len(data) - 2, nil, nil
	}

	data = data[i:]
	if len(data) < 10 {
		if atEOF {
			return 0, nil, io.ErrUnexpectedEOF
		}

		return i, nil, nil
	}

	size := syncsafe(data[6:])

	if data[3] == 0xff || data[4] == 0xff || size == syncsafeInvalid {
		// Skipping when we find the string "ID3" in the file but
		// the remaining header is invalid is consistent with the
		// detection logic in §3.1. This also reduces the
		// likelihood of errors being caused by the byte sequence
		// "ID3" (49 44 33) occuring in the audio, but does not
		// eliminate the possibility of errors in this case.
		//
		// Quoting from §3.1 of id3v2.4.0-structure.txt:
		//   An ID3v2 tag can be detected with the following pattern:
		//     $49 44 33 yy yy xx zz zz zz zz
		//   Where yy is less than $FF, xx is the 'flags' byte and zz
		//   is less than $80.
		return i + 3, nil, nil
	}

	if Version(data[3]) > Version24 {
		// Quoting from §3.1 of id3v2.4.0-structure.txt:
		//   If software with ID3v2.4.0 and below support should
		//   encounter version five or higher it should simply
		//   ignore the whole tag.
		return i + 3, nil, nil
	}

	if Version(data[3]) < Version23 {
		// This package only supports v2.3.0 and v2.4.0, skip
		// versions bellow v2.3.0.
		return i + 3, nil, nil
	}

	if data[5]&^knownTagFlags != 0 {
		// Skip tag blocks that contain unknown flags.
		//
		// Quoting from §3.1 of id3v2.4.0-structure.txt:
		//   If one of these undefined flags are set, the tag might
		//   not be readable for a parser that does not know the
		//   flags function.
		return i + 3, nil, nil
	}

	if data[5]&tagFlagFooter == tagFlagFooter {
		size += 10
	}

	if len(data) < 10+int(size) {
		if atEOF {
			return 0, nil, io.ErrUnexpectedEOF
		}

		return i, nil, nil
	}

	return i + 10 + int(size), data[:10+size], nil
}

const invalidFrameID = ^FrameID(0)

func validIDByte(b byte) bool {
	return (b >= 'A' && b <= 'Z') || (b >= '0' && b <= '9')
}

func frameID(data []byte) FrameID {
	_ = data[3]

	if validIDByte(data[0]) && validIDByte(data[1]) && validIDByte(data[2]) &&
		// Although it violates the specification, some software
		// incorrectly encodes v2.2.0 three character tags as
		// four character v2.3.0 tags with a trailing zero byte
		// when upgrading the tagging format version.
		(validIDByte(data[3]) || data[3] == 0) {
		return FrameID(binary.BigEndian.Uint32(data))
	}

	for _, v := range data {
		if v != 0 {
			return invalidFrameID
		}
	}

	// This is probably the begging of padding.
	return 0
}

var bufPool = &sync.Pool{
	New: func() interface{} {
		buf := make([]byte, 4<<10)
		return &buf
	},
}

// Scan reads all valid ID3v2 tags from the reader and
// returns all the frames in order. It returns an error
// if the tags are invalid.
func Scan(r io.Reader) (Frames, error) {
	buf := bufPool.Get()
	defer bufPool.Put(buf)

	s := bufio.NewScanner(r)
	s.Buffer(*buf.(*[]byte), 1<<28)
	s.Split(id3Split)

	var frames Frames

	for s.Scan() {
		data := s.Bytes()

		header := data[:10]
		data = data[10:]

		if string(header[:3]) != "ID3" {
			panic("id3: bufio.Scanner failed")
		}

		version := Version(header[3])
		switch version {
		case Version24, Version23:
		default:
			panic("id3: bufio.Scanner failed")
		}

		flags := header[5]

		if flags&tagFlagFooter == tagFlagFooter {
			footer := data[len(data)-10:]
			data = data[:len(data)-10]

			if string(footer[:3]) != "3DI" ||
				!bytes.Equal(header[3:], footer[3:]) {
				return nil, errors.New("id3: invalid footer")
			}
		}

		if flags&tagFlagExtendedHeader == tagFlagExtendedHeader {
			size := syncsafe(data)
			if size == syncsafeInvalid || len(data) < int(size) {
				return nil, errors.New("id3: invalid extended header")
			}

			extendedHeader := data[:size]
			data = data[size:]

			_ = extendedHeader
		}

	frames:
		for len(data) > 10 {
			_ = data[9]

			frame := &Frame{
				ID:      frameID(data),
				Version: version,
				Flags:   FrameFlags(binary.BigEndian.Uint16(data[8:])),
			}

			switch frame.ID {
			case 0:
				// We've probably hit padding, the padding
				// validity check below will handle this.
				break frames
			case invalidFrameID:
				return nil, errors.New("id3: invalid frame id")
			}

			var size uint32
			switch version {
			case Version24:
				size = syncsafe(data[4:])
				if size == syncsafeInvalid {
					return nil, errors.New("id3: invalid frame size")
				}
			case Version23:
				size = binary.BigEndian.Uint32(data[4:])
			default:
				panic("unhandled version")
			}

			if len(data) < 10+int(size) {
				return nil, errors.New("id3: frame size exceeds length of tag data")
			}

			if flags&tagFlagUnsynchronisation == tagFlagUnsynchronisation ||
				(version == Version24 && frame.Flags&FrameFlagV24Unsynchronisation != 0) {
				frame.Data = make([]byte, 0, size)

				for i := uint32(0); i < size; i++ {
					v := data[10+i]
					frame.Data = append(frame.Data, v)

					if v == 0xff && i+1 < size && data[10+i+1] == 0x00 {
						i++
					}
				}

				if version == Version24 {
					// Clear the frame level unsynchronisation flag
					frame.Flags &^= FrameFlagV24Unsynchronisation
				}
			} else {
				frame.Data = append([]byte(nil), data[10:10+size]...)
			}

			frames = append(frames, frame)
			data = data[10+size:]
		}

		if flags&tagFlagFooter == tagFlagFooter && len(data) != 0 {
			return nil, errors.New("id3: padding with footer")
		}

		for _, v := range data {
			if v != 0 {
				return nil, errors.New("id3: invalid padding")
			}
		}
	}

	if s.Err() != nil {
		return nil, s.Err()
	}

	return frames, nil
}

// Frames is a slice of ID3v2 frames.
type Frames []*Frame

// Lookup returns the last frame associated with a
// given frame id, or nil.
func (f Frames) Lookup(id FrameID) *Frame {
	for i := len(f) - 1; i >= 0; i-- {
		if f[i].ID == id {
			return f[i]
		}
	}

	return nil
}

// Frame is a single ID3v2 frame.
type Frame struct {
	ID      FrameID
	Version Version
	Flags   FrameFlags
	Data    []byte
}

func (f *Frame) String() string {
	data, terminus := f.Data, ""
	if len(data) > 128 {
		data, terminus = data[:128], "..."
	}

	var version string
	switch f.Version {
	case Version24:
		version = "v2.4"
	case Version23:
		version = "v2.3"
	default:
		version = "?"
	}

	return fmt.Sprintf("&ID3Frame{ID: %s, Version: %s, Flags: 0x%04x, Data: %d:%q%s}",
		f.ID.String(), version, f.Flags, len(f.Data), data, terminus)
}

// Text interprets the frame data as a text string,
// according to §4 of id3v2.4.0-structure.txt.
func (f *Frame) Text() (string, error) {
	if len(f.Data) < 2 {
		return "", errors.New("id3: frame data is invalid")
	}

	if f.Flags&encodingFrameFlags != 0 {
		return "", errors.New("id3: encoding frame flags are not supported")
	}

	data := f.Data[1:]
	var ord binary.ByteOrder = binary.BigEndian

	switch f.Data[0] {
	case textEncodingISO88591:
		for _, v := range data {
			if v&0x80 == 0 {
				continue
			}

			runes := make([]rune, len(data))
			for i, v := range data {
				runes[i] = rune(v)
			}

			return string(runes), nil
		}

		fallthrough
	case textEncodingUTF8:
		if data[len(data)-1] == 0x00 {
			// The specification requires that the string be
			// terminated with 0x00, but not all implementations
			// do this.
			data = data[:len(data)-1]
		}

		return string(data), nil
	case textEncodingUTF16:
		if len(data) < 2 {
			return "", errors.New("id3: missing UTF-16 BOM")
		}

		if data[0] == 0xff && data[1] == 0xfe {
			ord = binary.LittleEndian
		} else if data[0] == 0xfe && data[1] == 0xff {
			ord = binary.BigEndian
		} else {
			return "", errors.New("id3: invalid UTF-16 BOM")
		}

		data = data[2:]
		fallthrough
	case textEncodingUTF16BE:
		if len(data)%2 != 0 {
			return "", errors.New("id3: UTF-16 data is not even number of bytes")
		}

		u16s := make([]uint16, len(data)/2)
		for i := range u16s {
			u16s[i] = ord.Uint16(data[i*2:])
		}

		if u16s[len(u16s)-1] == 0x0000 {
			// The specification requires that the string be
			// terminated with 0x00 0x00, but not all
			// implementations do this.
			u16s = u16s[:len(u16s)-1]
		}

		return string(utf16.Decode(u16s)), nil
	default:
		return "", errors.New("id3: frame uses unsupported encoding")
	}
}
<commit_msg>Fix misspelling of `occurring`<commit_after>// Copyright 2017 Tom Thorogood. All rights reserved.
// Use of this source code is governed by a Modified
// BSD License that can be found in the LICENSE file.

// Package id3v2 implements support for reading ID3v2 tags.
package id3v2

//go:generate go run generate_ids.go

import (
	"bufio"
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"sync"
	"unicode/utf16"
)

// This is an implementation of v2.4.0 of the ID3v2 tagging format,
// defined in: http://id3.org/id3v2.4.0-structure, and v2.3.0 of
// the ID3v2 tagging format, defined in: http://id3.org/id3v2.3.0.

// Version is the version of the ID3v2 tag block.
type Version byte

const (
	// Version24 is v2.4.x of the ID3v2 specification.
	Version24 Version = 0x04
	// Version23 is v2.3.x of the ID3v2 specification.
	Version23 Version = 0x03
)

const (
	tagFlagUnsynchronisation = 1 << (7 - iota)
	tagFlagExtendedHeader
	tagFlagExperimental
	tagFlagFooter

	knownTagFlags = tagFlagUnsynchronisation | tagFlagExtendedHeader |
		tagFlagExperimental | tagFlagFooter
)

// FrameFlags are the frame-level ID3v2 flags.
type FrameFlags uint16

// These are the frame-level flags from v2.4.0 of the specification.
const (
	_ FrameFlags = 1 << (15 - iota)
	FrameFlagV24TagAlterPreservation
	FrameFlagV24FileAlterPreservation
	FrameFlagV24ReadOnly
	_
	_
	_
	_
	_
	FrameFlagV24GroupingIdentity
	_
	_
	FrameFlagV24Compression
	FrameFlagV24Encryption
	FrameFlagV24Unsynchronisation
	FrameFlagV24DataLengthIndicator
)

// These are the frame-level flags from v2.3.0 of the specification.
const (
	FrameFlagV23TagAlterPreservation FrameFlags = 1 << (15 - iota)
	FrameFlagV23FileAlterPreservation
	FrameFlagV23ReadOnly
	_
	_
	_
	_
	_
	FrameFlagV23Compression
	FrameFlagV23Encryption
	FrameFlagV23GroupingIdentity
)

const encodingFrameFlags FrameFlags = 0x00ff

const (
	textEncodingISO88591 = 0x00
	textEncodingUTF16    = 0x01
	textEncodingUTF16BE  = 0x02
	textEncodingUTF8     = 0x03
)

// FrameID is a four-byte frame identifier.
type FrameID uint32

const syncsafeInvalid = ^uint32(0)

func syncsafe(data []byte) uint32 {
	_ = data[3]

	if data[0]&0x80 != 0 || data[1]&0x80 != 0 ||
		data[2]&0x80 != 0 || data[3]&0x80 != 0 {
		return syncsafeInvalid
	}

	return uint32(data[0])<<21 | uint32(data[1])<<14 |
		uint32(data[2])<<7 | uint32(data[3])
}

func id3Split(data []byte, atEOF bool) (advance int, token []byte, err error) {
	i := bytes.Index(data, []byte("ID3"))
	if i == -1 {
		if len(data) < 2 {
			return 0, nil, nil
		}

		return len(data) - 2, nil, nil
	}

	data = data[i:]
	if len(data) < 10 {
		if atEOF {
			return 0, nil, io.ErrUnexpectedEOF
		}

		return i, nil, nil
	}

	size := syncsafe(data[6:])

	if data[3] == 0xff || data[4] == 0xff || size == syncsafeInvalid {
		// Skipping when we find the string "ID3" in the file but
		// the remaining header is invalid is consistent with the
		// detection logic in §3.1. This also reduces the
		// likelihood of errors being caused by the byte sequence
		// "ID3" (49 44 33) occurring in the audio, but does not
		// eliminate the possibility of errors in this case.
		//
		// Quoting from §3.1 of id3v2.4.0-structure.txt:
		//   An ID3v2 tag can be detected with the following pattern:
		//     $49 44 33 yy yy xx zz zz zz zz
		//   Where yy is less than $FF, xx is the 'flags' byte and zz
		//   is less than $80.
		return i + 3, nil, nil
	}

	if Version(data[3]) > Version24 {
		// Quoting from §3.1 of id3v2.4.0-structure.txt:
		//   If software with ID3v2.4.0 and below support should
		//   encounter version five or higher it should simply
		//   ignore the whole tag.
		return i + 3, nil, nil
	}

	if Version(data[3]) < Version23 {
		// This package only supports v2.3.0 and v2.4.0, skip
		// versions bellow v2.3.0.
		return i + 3, nil, nil
	}

	if data[5]&^knownTagFlags != 0 {
		// Skip tag blocks that contain unknown flags.
		//
		// Quoting from §3.1 of id3v2.4.0-structure.txt:
		//   If one of these undefined flags are set, the tag might
		//   not be readable for a parser that does not know the
		//   flags function.
		return i + 3, nil, nil
	}

	if data[5]&tagFlagFooter == tagFlagFooter {
		size += 10
	}

	if len(data) < 10+int(size) {
		if atEOF {
			return 0, nil, io.ErrUnexpectedEOF
		}

		return i, nil, nil
	}

	return i + 10 + int(size), data[:10+size], nil
}

const invalidFrameID = ^FrameID(0)

func validIDByte(b byte) bool {
	return (b >= 'A' && b <= 'Z') || (b >= '0' && b <= '9')
}

func frameID(data []byte) FrameID {
	_ = data[3]

	if validIDByte(data[0]) && validIDByte(data[1]) && validIDByte(data[2]) &&
		// Although it violates the specification, some software
		// incorrectly encodes v2.2.0 three character tags as
		// four character v2.3.0 tags with a trailing zero byte
		// when upgrading the tagging format version.
		(validIDByte(data[3]) || data[3] == 0) {
		return FrameID(binary.BigEndian.Uint32(data))
	}

	for _, v := range data {
		if v != 0 {
			return invalidFrameID
		}
	}

	// This is probably the begging of padding.
	return 0
}

var bufPool = &sync.Pool{
	New: func() interface{} {
		buf := make([]byte, 4<<10)
		return &buf
	},
}

// Scan reads all valid ID3v2 tags from the reader and
// returns all the frames in order. It returns an error
// if the tags are invalid.
func Scan(r io.Reader) (Frames, error) {
	buf := bufPool.Get()
	defer bufPool.Put(buf)

	s := bufio.NewScanner(r)
	s.Buffer(*buf.(*[]byte), 1<<28)
	s.Split(id3Split)

	var frames Frames

	for s.Scan() {
		data := s.Bytes()

		header := data[:10]
		data = data[10:]

		if string(header[:3]) != "ID3" {
			panic("id3: bufio.Scanner failed")
		}

		version := Version(header[3])
		switch version {
		case Version24, Version23:
		default:
			panic("id3: bufio.Scanner failed")
		}

		flags := header[5]

		if flags&tagFlagFooter == tagFlagFooter {
			footer := data[len(data)-10:]
			data = data[:len(data)-10]

			if string(footer[:3]) != "3DI" ||
				!bytes.Equal(header[3:], footer[3:]) {
				return nil, errors.New("id3: invalid footer")
			}
		}

		if flags&tagFlagExtendedHeader == tagFlagExtendedHeader {
			size := syncsafe(data)
			if size == syncsafeInvalid || len(data) < int(size) {
				return nil, errors.New("id3: invalid extended header")
			}

			extendedHeader := data[:size]
			data = data[size:]

			_ = extendedHeader
		}

	frames:
		for len(data) > 10 {
			_ = data[9]

			frame := &Frame{
				ID:      frameID(data),
				Version: version,
				Flags:   FrameFlags(binary.BigEndian.Uint16(data[8:])),
			}

			switch frame.ID {
			case 0:
				// We've probably hit padding, the padding
				// validity check below will handle this.
				break frames
			case invalidFrameID:
				return nil, errors.New("id3: invalid frame id")
			}

			var size uint32
			switch version {
			case Version24:
				size = syncsafe(data[4:])
				if size == syncsafeInvalid {
					return nil, errors.New("id3: invalid frame size")
				}
			case Version23:
				size = binary.BigEndian.Uint32(data[4:])
			default:
				panic("unhandled version")
			}

			if len(data) < 10+int(size) {
				return nil, errors.New("id3: frame size exceeds length of tag data")
			}

			if flags&tagFlagUnsynchronisation == tagFlagUnsynchronisation ||
				(version == Version24 && frame.Flags&FrameFlagV24Unsynchronisation != 0) {
				frame.Data = make([]byte, 0, size)

				for i := uint32(0); i < size; i++ {
					v := data[10+i]
					frame.Data = append(frame.Data, v)

					if v == 0xff && i+1 < size && data[10+i+1] == 0x00 {
						i++
					}
				}

				if version == Version24 {
					// Clear the frame level unsynchronisation flag
					frame.Flags &^= FrameFlagV24Unsynchronisation
				}
			} else {
				frame.Data = append([]byte(nil), data[10:10+size]...)
			}

			frames = append(frames, frame)
			data = data[10+size:]
		}

		if flags&tagFlagFooter == tagFlagFooter && len(data) != 0 {
			return nil, errors.New("id3: padding with footer")
		}

		for _, v := range data {
			if v != 0 {
				return nil, errors.New("id3: invalid padding")
			}
		}
	}

	if s.Err() != nil {
		return nil, s.Err()
	}

	return frames, nil
}

// Frames is a slice of ID3v2 frames.
type Frames []*Frame

// Lookup returns the last frame associated with a
// given frame id, or nil.
func (f Frames) Lookup(id FrameID) *Frame {
	for i := len(f) - 1; i >= 0; i-- {
		if f[i].ID == id {
			return f[i]
		}
	}

	return nil
}

// Frame is a single ID3v2 frame.
type Frame struct {
	ID      FrameID
	Version Version
	Flags   FrameFlags
	Data    []byte
}

func (f *Frame) String() string {
	data, terminus := f.Data, ""
	if len(data) > 128 {
		data, terminus = data[:128], "..."
	}

	var version string
	switch f.Version {
	case Version24:
		version = "v2.4"
	case Version23:
		version = "v2.3"
	default:
		version = "?"
	}

	return fmt.Sprintf("&ID3Frame{ID: %s, Version: %s, Flags: 0x%04x, Data: %d:%q%s}",
		f.ID.String(), version, f.Flags, len(f.Data), data, terminus)
}

// Text interprets the frame data as a text string,
// according to §4 of id3v2.4.0-structure.txt.
func (f *Frame) Text() (string, error) {
	if len(f.Data) < 2 {
		return "", errors.New("id3: frame data is invalid")
	}

	if f.Flags&encodingFrameFlags != 0 {
		return "", errors.New("id3: encoding frame flags are not supported")
	}

	data := f.Data[1:]
	var ord binary.ByteOrder = binary.BigEndian

	switch f.Data[0] {
	case textEncodingISO88591:
		for _, v := range data {
			if v&0x80 == 0 {
				continue
			}

			runes := make([]rune, len(data))
			for i, v := range data {
				runes[i] = rune(v)
			}

			return string(runes), nil
		}

		fallthrough
	case textEncodingUTF8:
		if data[len(data)-1] == 0x00 {
			// The specification requires that the string be
			// terminated with 0x00, but not all implementations
			// do this.
			data = data[:len(data)-1]
		}

		return string(data), nil
	case textEncodingUTF16:
		if len(data) < 2 {
			return "", errors.New("id3: missing UTF-16 BOM")
		}

		if data[0] == 0xff && data[1] == 0xfe {
			ord = binary.LittleEndian
		} else if data[0] == 0xfe && data[1] == 0xff {
			ord = binary.BigEndian
		} else {
			return "", errors.New("id3: invalid UTF-16 BOM")
		}

		data = data[2:]
		fallthrough
	case textEncodingUTF16BE:
		if len(data)%2 != 0 {
			return "", errors.New("id3: UTF-16 data is not even number of bytes")
		}

		u16s := make([]uint16, len(data)/2)
		for i := range u16s {
			u16s[i] = ord.Uint16(data[i*2:])
		}

		if u16s[len(u16s)-1] == 0x0000 {
			// The specification requires that the string be
			// terminated with 0x00 0x00, but not all
			// implementations do this.
			u16s = u16s[:len(u16s)-1]
		}

		return string(utf16.Decode(u16s)), nil
	default:
		return "", errors.New("id3: frame uses unsupported encoding")
	}
}
<|endoftext|>


<commit_before>package dynamodb

import (
	"fmt"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/dynamodb"
	"github.com/gruntwork-io/terragrunt/aws_helper"
	"github.com/gruntwork-io/terragrunt/errors"
	"github.com/gruntwork-io/terragrunt/options"
	"github.com/gruntwork-io/terragrunt/util"
)

// DynamoDB only allows 10 table creates/deletes simultaneously. To ensure we don't hit this error, especially when
// running many automated tests in parallel, we use a counting semaphore
var tableCreateDeleteSemaphore = NewCountingSemaphore(10)

// Terraform requires the DynamoDB table to have a primary key with this name
const ATTR_LOCK_ID = "LockID"

// Default is to retry for up to 5 minutes
const MAX_RETRIES_WAITING_FOR_TABLE_TO_BE_ACTIVE = 30
const SLEEP_BETWEEN_TABLE_STATUS_CHECKS = 10 * time.Second

const DEFAULT_READ_CAPACITY_UNITS = 1
const DEFAULT_WRITE_CAPACITY_UNITS = 1

// Create an authenticated client for DynamoDB
func CreateDynamoDbClient(config *aws_helper.AwsSessionConfig, terragruntOptions *options.TerragruntOptions) (*dynamodb.DynamoDB, error) {
	session, err := aws_helper.CreateAwsSession(config, terragruntOptions)
	if err != nil {
		return nil, err
	}

	return dynamodb.New(session), nil
}

// Create the lock table in DynamoDB if it doesn't already exist
func CreateLockTableIfNecessary(tableName string, tags map[string]string, client *dynamodb.DynamoDB, terragruntOptions *options.TerragruntOptions) error {
	tableExists, err := LockTableExistsAndIsActive(tableName, client)
	if err != nil {
		return err
	}

	if !tableExists {
		terragruntOptions.Logger.Printf("Lock table %s does not exist in DynamoDB. Will need to create it just this first time.", tableName)
		return CreateLockTable(tableName, tags, DEFAULT_READ_CAPACITY_UNITS, DEFAULT_WRITE_CAPACITY_UNITS, client, terragruntOptions)
	}

	return nil
}

// Return true if the lock table exists in DynamoDB and is in "active" state
func LockTableExistsAndIsActive(tableName string, client *dynamodb.DynamoDB) (bool, error) {
	output, err := client.DescribeTable(&dynamodb.DescribeTableInput{TableName: aws.String(tableName)})
	if err != nil {
		if awsErr, isAwsErr := err.(awserr.Error); isAwsErr && awsErr.Code() == "ResourceNotFoundException" {
			return false, nil
		} else {
			return false, errors.WithStackTrace(err)
		}
	}

	return *output.Table.TableStatus == dynamodb.TableStatusActive, nil
}

// Return true if the lock table's SSEncryption is turned on
func LockTableCheckSSEncryptionIsOn(tableName string, client *dynamodb.DynamoDB) (bool, error) {
	output, err := client.DescribeTable(&dynamodb.DescribeTableInput{TableName: aws.String(tableName)})
	if err != nil {
		return false, errors.WithStackTrace(err)
	}

	return output.Table.SSEDescription != nil && aws.StringValue(output.Table.SSEDescription.Status) == dynamodb.SSEStatusEnabled, nil
}

// Create a lock table in DynamoDB and wait until it is in "active" state. If the table already exists, merely wait
// until it is in "active" state.
func CreateLockTable(tableName string, tags map[string]string, readCapacityUnits int, writeCapacityUnits int, client *dynamodb.DynamoDB, terragruntOptions *options.TerragruntOptions) error {
	tableCreateDeleteSemaphore.Acquire()
	defer tableCreateDeleteSemaphore.Release()

	terragruntOptions.Logger.Printf("Creating table %s in DynamoDB", tableName)

	attributeDefinitions := []*dynamodb.AttributeDefinition{
		&dynamodb.AttributeDefinition{AttributeName: aws.String(ATTR_LOCK_ID), AttributeType: aws.String(dynamodb.ScalarAttributeTypeS)},
	}

	keySchema := []*dynamodb.KeySchemaElement{
		&dynamodb.KeySchemaElement{AttributeName: aws.String(ATTR_LOCK_ID), KeyType: aws.String(dynamodb.KeyTypeHash)},
	}

	createTableOutput, err := client.CreateTable(&dynamodb.CreateTableInput{
		TableName:            aws.String(tableName),
		AttributeDefinitions: attributeDefinitions,
		KeySchema:            keySchema,
		ProvisionedThroughput: &dynamodb.ProvisionedThroughput{
			ReadCapacityUnits:  aws.Int64(int64(readCapacityUnits)),
			WriteCapacityUnits: aws.Int64(int64(writeCapacityUnits)),
		},
	})

	if err != nil {
		if isTableAlreadyBeingCreatedOrUpdatedError(err) {
			terragruntOptions.Logger.Printf("Looks like someone created table %s at the same time. Will wait for it to be in active state.", tableName)
		} else {
			return errors.WithStackTrace(err)
		}
	}

	err = waitForTableToBeActive(tableName, client, MAX_RETRIES_WAITING_FOR_TABLE_TO_BE_ACTIVE, SLEEP_BETWEEN_TABLE_STATUS_CHECKS, terragruntOptions)

	if err != nil {
		return err
	}

	if createTableOutput != nil && createTableOutput.TableDescription != nil && createTableOutput.TableDescription.TableArn != nil {
		// Do not tag in case somebody else had created the table

		err = tagTableIfTagsGiven(tags, createTableOutput.TableDescription.TableArn, client, terragruntOptions)

		if err != nil {
			return errors.WithStackTrace(err)
		}
	}

	return nil
}

func tagTableIfTagsGiven(tags map[string]string, tableArn *string, client *dynamodb.DynamoDB, terragruntOptions *options.TerragruntOptions) error {

	if tags == nil || len(tags) == 0 {
		terragruntOptions.Logger.Printf("No tags for lock table given.")
		return nil
	}

	// we were able to create the table successfully, now add tags
	terragruntOptions.Logger.Printf("Adding tags to lock table: %s", tags)

	var tagsConverted []*dynamodb.Tag

	for k, v := range tags {
		tagsConverted = append(tagsConverted, &dynamodb.Tag{Key: aws.String(k), Value: aws.String(v)})
	}

	var input = dynamodb.TagResourceInput{
		ResourceArn: tableArn,
		Tags:        tagsConverted}

	_, err := client.TagResource(&input)

	return err
}

// Delete the given table in DynamoDB
func DeleteTable(tableName string, client *dynamodb.DynamoDB) error {
	tableCreateDeleteSemaphore.Acquire()
	defer tableCreateDeleteSemaphore.Release()

	_, err := client.DeleteTable(&dynamodb.DeleteTableInput{TableName: aws.String(tableName)})
	return err
}

// Return true if the given error is the error message returned by AWS when the resource already exists and is being
// updated by someone else
func isTableAlreadyBeingCreatedOrUpdatedError(err error) bool {
	awsErr, isAwsErr := err.(awserr.Error)
	return isAwsErr && awsErr.Code() == "ResourceInUseException"
}

// Wait for the given DynamoDB table to be in the "active" state. If it's not in "active" state, sleep for the
// specified amount of time, and try again, up to a maximum of maxRetries retries.
func waitForTableToBeActive(tableName string, client *dynamodb.DynamoDB, maxRetries int, sleepBetweenRetries time.Duration, terragruntOptions *options.TerragruntOptions) error {
	return waitForTableToBeActiveWithRandomSleep(tableName, client, maxRetries, sleepBetweenRetries, sleepBetweenRetries, terragruntOptions)
}

// Waits for the given table as described above, but sleeps a random amount of time greater than sleepBetweenRetriesMin
// and less than sleepBetweenRetriesMax between tries. This is to avoid an AWS issue where all waiting requests fire at
// the same time, which continually triggered AWS's "subscriber limit exceeded" API error.
func waitForTableToBeActiveWithRandomSleep(tableName string, client *dynamodb.DynamoDB, maxRetries int, sleepBetweenRetriesMin time.Duration, sleepBetweenRetriesMax time.Duration, terragruntOptions *options.TerragruntOptions) error {
	for i := 0; i < maxRetries; i++ {
		tableReady, err := LockTableExistsAndIsActive(tableName, client)
		if err != nil {
			return err
		}

		if tableReady {
			terragruntOptions.Logger.Printf("Success! Table %s is now in active state.", tableName)
			return nil
		}

		sleepBetweenRetries := util.GetRandomTime(sleepBetweenRetriesMin, sleepBetweenRetriesMax)
		terragruntOptions.Logger.Printf("Table %s is not yet in active state. Will check again after %s.", tableName, sleepBetweenRetries)
		time.Sleep(sleepBetweenRetries)
	}

	return errors.WithStackTrace(TableActiveRetriesExceeded{TableName: tableName, Retries: maxRetries})
}

// Encrypt the TFState Lock table - If Necessary
func UpdateLockTableSetSSEncryptionOnIfNecessary(tableName string, client *dynamodb.DynamoDB, terragruntOptions *options.TerragruntOptions) error {
	tableSSEncrypted, err := LockTableCheckSSEncryptionIsOn(tableName, client)
	if err != nil {
		return errors.WithStackTrace(err)
	}

	if tableSSEncrypted {
		terragruntOptions.Logger.Printf("Table %s already has encryption enabled", tableName)
		return nil
	}

	tableCreateDeleteSemaphore.Acquire()
	defer tableCreateDeleteSemaphore.Release()

	terragruntOptions.Logger.Printf("Enabling server-side encryption on table %s in AWS DynamoDB", tableName)

	input := &dynamodb.UpdateTableInput{
		SSESpecification: &dynamodb.SSESpecification{
			Enabled: aws.Bool(true),
			SSEType: aws.String("KMS"),
		},
		TableName: aws.String(tableName),
	}

	if _, err := client.UpdateTable(input); err != nil {
		if isTableAlreadyBeingCreatedOrUpdatedError(err) {
			terragruntOptions.Logger.Printf("Looks like someone is already updating table %s at the same time. Will wait for that update to complete.", tableName)
		} else {
			return errors.WithStackTrace(err)
		}
	}

	if err := waitForEncryptionToBeEnabled(tableName, client, terragruntOptions); err != nil {
		return errors.WithStackTrace(err)
	}

	return waitForTableToBeActive(tableName, client, MAX_RETRIES_WAITING_FOR_TABLE_TO_BE_ACTIVE, SLEEP_BETWEEN_TABLE_STATUS_CHECKS, terragruntOptions)
}

// Wait until encryption is enabled for the given table
func waitForEncryptionToBeEnabled(tableName string, client *dynamodb.DynamoDB, terragruntOptions *options.TerragruntOptions) error {
	maxRetries := 15
	sleepBetweenRetries := 20 * time.Second

	terragruntOptions.Logger.Printf("Waiting for encryption to be enabled on table %s", tableName)

	for i := 0; i < maxRetries; i++ {
		tableSSEncrypted, err := LockTableCheckSSEncryptionIsOn(tableName, client)
		if err != nil {
			return errors.WithStackTrace(err)
		}

		if tableSSEncrypted {
			terragruntOptions.Logger.Printf("Encryption is now enabled for table %s!", tableName)
			return nil
		}

		terragruntOptions.Logger.Printf("Encryption is still not enabled for table %s. Will sleep for %v and try again.", tableName, sleepBetweenRetries)
		time.Sleep(sleepBetweenRetries)
	}

	return errors.WithStackTrace(TableEncryptedRetriesExceeded{TableName: tableName, Retries: maxRetries})
}

// Custom error types

type TableActiveRetriesExceeded struct {
	TableName string
	Retries   int
}

func (err TableActiveRetriesExceeded) Error() string {
	return fmt.Sprintf("Table %s is still not in active state after %d retries.", err.TableName, err.Retries)
}

type TableDoesNotExist struct {
	TableName  string
	Underlying error
}

func (err TableDoesNotExist) Error() string {
	return fmt.Sprintf("Table %s does not exist in DynamoDB! Original error from AWS: %v", err.TableName, err.Underlying)
}

type TableEncryptedRetriesExceeded struct {
	TableName string
	Retries   int
}

func (err TableEncryptedRetriesExceeded) Error() string {
	return fmt.Sprintf("Table %s still does not have encryption enabled after %d retries.", err.TableName, err.Retries)
}
<commit_msg>Updates billing mode for managed DynamoDB lock table to PAY_PER_REQUEST<commit_after>package dynamodb

import (
	"fmt"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/dynamodb"
	"github.com/gruntwork-io/terragrunt/aws_helper"
	"github.com/gruntwork-io/terragrunt/errors"
	"github.com/gruntwork-io/terragrunt/options"
	"github.com/gruntwork-io/terragrunt/util"
)

// DynamoDB only allows 10 table creates/deletes simultaneously. To ensure we don't hit this error, especially when
// running many automated tests in parallel, we use a counting semaphore
var tableCreateDeleteSemaphore = NewCountingSemaphore(10)

// Terraform requires the DynamoDB table to have a primary key with this name
const ATTR_LOCK_ID = "LockID"

// Default is to retry for up to 5 minutes
const MAX_RETRIES_WAITING_FOR_TABLE_TO_BE_ACTIVE = 30
const SLEEP_BETWEEN_TABLE_STATUS_CHECKS = 10 * time.Second

const DYNAMODB_PAY_PER_REQUEST_BILLING_MODE = "PAY_PER_REQUEST"

// Create an authenticated client for DynamoDB
func CreateDynamoDbClient(config *aws_helper.AwsSessionConfig, terragruntOptions *options.TerragruntOptions) (*dynamodb.DynamoDB, error) {
	session, err := aws_helper.CreateAwsSession(config, terragruntOptions)
	if err != nil {
		return nil, err
	}

	return dynamodb.New(session), nil
}

// Create the lock table in DynamoDB if it doesn't already exist
func CreateLockTableIfNecessary(tableName string, tags map[string]string, client *dynamodb.DynamoDB, terragruntOptions *options.TerragruntOptions) error {
	tableExists, err := LockTableExistsAndIsActive(tableName, client)
	if err != nil {
		return err
	}

	if !tableExists {
		terragruntOptions.Logger.Printf("Lock table %s does not exist in DynamoDB. Will need to create it just this first time.", tableName)
		return CreateLockTable(tableName, tags, client, terragruntOptions)
	}

	return nil
}

// Return true if the lock table exists in DynamoDB and is in "active" state
func LockTableExistsAndIsActive(tableName string, client *dynamodb.DynamoDB) (bool, error) {
	output, err := client.DescribeTable(&dynamodb.DescribeTableInput{TableName: aws.String(tableName)})
	if err != nil {
		if awsErr, isAwsErr := err.(awserr.Error); isAwsErr && awsErr.Code() == "ResourceNotFoundException" {
			return false, nil
		} else {
			return false, errors.WithStackTrace(err)
		}
	}

	return *output.Table.TableStatus == dynamodb.TableStatusActive, nil
}

// Return true if the lock table's SSEncryption is turned on
func LockTableCheckSSEncryptionIsOn(tableName string, client *dynamodb.DynamoDB) (bool, error) {
	output, err := client.DescribeTable(&dynamodb.DescribeTableInput{TableName: aws.String(tableName)})
	if err != nil {
		return false, errors.WithStackTrace(err)
	}

	return output.Table.SSEDescription != nil && aws.StringValue(output.Table.SSEDescription.Status) == dynamodb.SSEStatusEnabled, nil
}

// Create a lock table in DynamoDB and wait until it is in "active" state. If the table already exists, merely wait
// until it is in "active" state.
func CreateLockTable(tableName string, tags map[string]string, client *dynamodb.DynamoDB, terragruntOptions *options.TerragruntOptions) error {
	tableCreateDeleteSemaphore.Acquire()
	defer tableCreateDeleteSemaphore.Release()

	terragruntOptions.Logger.Printf("Creating table %s in DynamoDB", tableName)

	createTableOutput, err := client.CreateTable(&dynamodb.CreateTableInput{
		TableName:   aws.String(tableName),
		BillingMode: aws.String(DYNAMODB_PAY_PER_REQUEST_BILLING_MODE),
		AttributeDefinitions: []*dynamodb.AttributeDefinition{
			{
				AttributeName: aws.String(ATTR_LOCK_ID),
				AttributeType: aws.String(dynamodb.ScalarAttributeTypeS),
			},
		},
		KeySchema: []*dynamodb.KeySchemaElement{
			{
				AttributeName: aws.String(ATTR_LOCK_ID),
				KeyType:       aws.String(dynamodb.KeyTypeHash),
			},
		},
	})

	if err != nil {
		if isTableAlreadyBeingCreatedOrUpdatedError(err) {
			terragruntOptions.Logger.Printf("Looks like someone created table %s at the same time. Will wait for it to be in active state.", tableName)
		} else {
			return errors.WithStackTrace(err)
		}
	}

	err = waitForTableToBeActive(tableName, client, MAX_RETRIES_WAITING_FOR_TABLE_TO_BE_ACTIVE, SLEEP_BETWEEN_TABLE_STATUS_CHECKS, terragruntOptions)

	if err != nil {
		return err
	}

	if createTableOutput != nil && createTableOutput.TableDescription != nil && createTableOutput.TableDescription.TableArn != nil {
		// Do not tag in case somebody else had created the table

		err = tagTableIfTagsGiven(tags, createTableOutput.TableDescription.TableArn, client, terragruntOptions)

		if err != nil {
			return errors.WithStackTrace(err)
		}
	}

	return nil
}

func tagTableIfTagsGiven(tags map[string]string, tableArn *string, client *dynamodb.DynamoDB, terragruntOptions *options.TerragruntOptions) error {

	if tags == nil || len(tags) == 0 {
		terragruntOptions.Logger.Printf("No tags for lock table given.")
		return nil
	}

	// we were able to create the table successfully, now add tags
	terragruntOptions.Logger.Printf("Adding tags to lock table: %s", tags)

	var tagsConverted []*dynamodb.Tag

	for k, v := range tags {
		tagsConverted = append(tagsConverted, &dynamodb.Tag{Key: aws.String(k), Value: aws.String(v)})
	}

	var input = dynamodb.TagResourceInput{
		ResourceArn: tableArn,
		Tags:        tagsConverted}

	_, err := client.TagResource(&input)

	return err
}

// Delete the given table in DynamoDB
func DeleteTable(tableName string, client *dynamodb.DynamoDB) error {
	tableCreateDeleteSemaphore.Acquire()
	defer tableCreateDeleteSemaphore.Release()

	_, err := client.DeleteTable(&dynamodb.DeleteTableInput{TableName: aws.String(tableName)})
	return err
}

// Return true if the given error is the error message returned by AWS when the resource already exists and is being
// updated by someone else
func isTableAlreadyBeingCreatedOrUpdatedError(err error) bool {
	awsErr, isAwsErr := err.(awserr.Error)
	return isAwsErr && awsErr.Code() == "ResourceInUseException"
}

// Wait for the given DynamoDB table to be in the "active" state. If it's not in "active" state, sleep for the
// specified amount of time, and try again, up to a maximum of maxRetries retries.
func waitForTableToBeActive(tableName string, client *dynamodb.DynamoDB, maxRetries int, sleepBetweenRetries time.Duration, terragruntOptions *options.TerragruntOptions) error {
	return waitForTableToBeActiveWithRandomSleep(tableName, client, maxRetries, sleepBetweenRetries, sleepBetweenRetries, terragruntOptions)
}

// Waits for the given table as described above, but sleeps a random amount of time greater than sleepBetweenRetriesMin
// and less than sleepBetweenRetriesMax between tries. This is to avoid an AWS issue where all waiting requests fire at
// the same time, which continually triggered AWS's "subscriber limit exceeded" API error.
func waitForTableToBeActiveWithRandomSleep(tableName string, client *dynamodb.DynamoDB, maxRetries int, sleepBetweenRetriesMin time.Duration, sleepBetweenRetriesMax time.Duration, terragruntOptions *options.TerragruntOptions) error {
	for i := 0; i < maxRetries; i++ {
		tableReady, err := LockTableExistsAndIsActive(tableName, client)
		if err != nil {
			return err
		}

		if tableReady {
			terragruntOptions.Logger.Printf("Success! Table %s is now in active state.", tableName)
			return nil
		}

		sleepBetweenRetries := util.GetRandomTime(sleepBetweenRetriesMin, sleepBetweenRetriesMax)
		terragruntOptions.Logger.Printf("Table %s is not yet in active state. Will check again after %s.", tableName, sleepBetweenRetries)
		time.Sleep(sleepBetweenRetries)
	}

	return errors.WithStackTrace(TableActiveRetriesExceeded{TableName: tableName, Retries: maxRetries})
}

// Encrypt the TFState Lock table - If Necessary
func UpdateLockTableSetSSEncryptionOnIfNecessary(tableName string, client *dynamodb.DynamoDB, terragruntOptions *options.TerragruntOptions) error {
	tableSSEncrypted, err := LockTableCheckSSEncryptionIsOn(tableName, client)
	if err != nil {
		return errors.WithStackTrace(err)
	}

	if tableSSEncrypted {
		terragruntOptions.Logger.Printf("Table %s already has encryption enabled", tableName)
		return nil
	}

	tableCreateDeleteSemaphore.Acquire()
	defer tableCreateDeleteSemaphore.Release()

	terragruntOptions.Logger.Printf("Enabling server-side encryption on table %s in AWS DynamoDB", tableName)

	input := &dynamodb.UpdateTableInput{
		SSESpecification: &dynamodb.SSESpecification{
			Enabled: aws.Bool(true),
			SSEType: aws.String("KMS"),
		},
		TableName: aws.String(tableName),
	}

	if _, err := client.UpdateTable(input); err != nil {
		if isTableAlreadyBeingCreatedOrUpdatedError(err) {
			terragruntOptions.Logger.Printf("Looks like someone is already updating table %s at the same time. Will wait for that update to complete.", tableName)
		} else {
			return errors.WithStackTrace(err)
		}
	}

	if err := waitForEncryptionToBeEnabled(tableName, client, terragruntOptions); err != nil {
		return errors.WithStackTrace(err)
	}

	return waitForTableToBeActive(tableName, client, MAX_RETRIES_WAITING_FOR_TABLE_TO_BE_ACTIVE, SLEEP_BETWEEN_TABLE_STATUS_CHECKS, terragruntOptions)
}

// Wait until encryption is enabled for the given table
func waitForEncryptionToBeEnabled(tableName string, client *dynamodb.DynamoDB, terragruntOptions *options.TerragruntOptions) error {
	maxRetries := 15
	sleepBetweenRetries := 20 * time.Second

	terragruntOptions.Logger.Printf("Waiting for encryption to be enabled on table %s", tableName)

	for i := 0; i < maxRetries; i++ {
		tableSSEncrypted, err := LockTableCheckSSEncryptionIsOn(tableName, client)
		if err != nil {
			return errors.WithStackTrace(err)
		}

		if tableSSEncrypted {
			terragruntOptions.Logger.Printf("Encryption is now enabled for table %s!", tableName)
			return nil
		}

		terragruntOptions.Logger.Printf("Encryption is still not enabled for table %s. Will sleep for %v and try again.", tableName, sleepBetweenRetries)
		time.Sleep(sleepBetweenRetries)
	}

	return errors.WithStackTrace(TableEncryptedRetriesExceeded{TableName: tableName, Retries: maxRetries})
}

// Custom error types

type TableActiveRetriesExceeded struct {
	TableName string
	Retries   int
}

func (err TableActiveRetriesExceeded) Error() string {
	return fmt.Sprintf("Table %s is still not in active state after %d retries.", err.TableName, err.Retries)
}

type TableDoesNotExist struct {
	TableName  string
	Underlying error
}

func (err TableDoesNotExist) Error() string {
	return fmt.Sprintf("Table %s does not exist in DynamoDB! Original error from AWS: %v", err.TableName, err.Underlying)
}

type TableEncryptedRetriesExceeded struct {
	TableName string
	Retries   int
}

func (err TableEncryptedRetriesExceeded) Error() string {
	return fmt.Sprintf("Table %s still does not have encryption enabled after %d retries.", err.TableName, err.Retries)
}
<|endoftext|>


<commit_before>package raytracer
<commit_msg>image data structure<commit_after>package raytracer

import ()

type image struct {
	imagesize int
	width     int
	height    int
	//structure for the data missing, maybe data []byte
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"errors"
	"fmt"
	"os"
	"os/exec"
	"strings"
)

const (
	// DefaultHeight is the default height of an Image
	DefaultHeight = 500
	// DefaultWidth is the default width of an Image
	DefaultWidth = 500
)

var (
	Black = NewColor(0, 0, 0)
	White = NewColor(255, 255, 255)
)

type Color struct {
	r byte
	b byte
	g byte
}

func NewColor(r, g, b byte) Color {
	return Color{r, g, b}
}

// Image represents an image
type Image struct {
	frame  [][]Color
	height int
	width  int
}

// NewImage returns a new Image with the given height and width
func NewImage(height, width int) *Image {
	frame := make([][]Color, height)
	for i := 0; i < height; i++ {
		frame[i] = make([]Color, width)
	}
	image := &Image{
		frame:  frame,
		height: height,
		width:  width,
	}
	image.Fill(Black)
	return image
}

// DrawLines draws all lines onto the Image
func (image *Image) DrawLines(em *Matrix, c Color) error {
	if em.cols < 2 {
		return errors.New("2 or more points are required for drawing")
	}
	for i := 0; i < em.cols-1; i += 2 {
		p0 := em.GetColumn(i)
		p1 := em.GetColumn(i + 1)
		image.DrawLine(int(p0[0]), int(p0[1]), int(p1[0]), int(p1[1]), c)
	}
	return nil
}

// DrawPolygons draws all polygons onto the Image
func (image *Image) DrawPolygons(em *Matrix, c Color) error {
	if em.cols < 3 {
		return errors.New("3 or more points are required for drawing")
	}
	for i := 0; i < em.cols-2; i += 3 {
		p0 := em.GetColumn(i)
		p1 := em.GetColumn(i + 1)
		p2 := em.GetColumn(i + 2)
		if isVisible(p0, p1, p2) {
			image.DrawLine(int(p0[0]), int(p0[1]), int(p1[0]), int(p1[1]), c)
			image.DrawLine(int(p1[0]), int(p1[1]), int(p2[0]), int(p2[1]), c)
			image.DrawLine(int(p2[0]), int(p2[1]), int(p0[0]), int(p0[1]), c)
		}
	}
	return nil
}

// DrawLine draws a single line onto the Image
func (image *Image) DrawLine(x1, y1, x2, y2 int, c Color) {
	if x1 > x2 {
		x1, x2 = x2, x1
		y1, y2 = y2, y1
	}

	A := 2 * (y2 - y1)
	B := 2 * -(x2 - x1)
	m := float32(A) / float32(-B)
	if m >= 0 {
		if m <= 1 {
			image.drawOctant1(x1, y1, x2, y2, A, B, c)
		} else {
			image.drawOctant2(x1, y1, x2, y2, A, B, c)
		}
	} else {
		if m < -1 {
			image.drawOctant7(x1, y1, x2, y2, A, B, c)
		} else {
			image.drawOctant8(x1, y1, x2, y2, A, B, c)
		}
	}
}

func (image *Image) drawOctant1(x1, y1, x2, y2, A, B int, c Color) {
	d := A + B/2
	for x1 <= x2 {
		image.set(x1, y1, c)
		if d > 0 {
			y1++
			d += B
		}
		x1++
		d += A
	}
}

func (image *Image) drawOctant2(x1, y1, x2, y2, A, B int, c Color) {
	d := A/2 + B
	for y1 <= y2 {
		image.set(x1, y1, c)
		if d < 0 {
			x1++
			d += A
		}
		y1++
		d += B
	}
}

func (image *Image) drawOctant7(x1, y1, x2, y2, A, B int, c Color) {
	d := A/2 + B
	for y1 >= y2 {
		image.set(x1, y1, c)
		if d > 0 {
			x1++
			d += A
		}
		y1--
		d -= B
	}
}

func (image *Image) drawOctant8(x1, y1, x2, y2, A, B int, c Color) {
	d := A - B/2
	for x1 <= x2 {
		image.set(x1, y1, c)
		if d < 0 {
			y1--
			d -= B
		}
		x1++
		d += A
	}
}

// Fill completely fills the Image with a single color
func (image *Image) Fill(c Color) {
	for y := 0; y < image.height; y++ {
		for x := 0; x < image.width; x++ {
			image.set(x, y, c)
		}
	}
}

func (image *Image) set(x, y int, c Color) {
	if (x < 0 || x >= image.width) || (y < 0 || y >= image.height) {
		return
	}
	image.frame[y][x] = c
}

// SavePpm will save the Image as a ppm
func (image *Image) SavePpm(name string) error {
	f, err := os.Create(name)
	if err != nil {
		return err
	}
	defer f.Close()

	w := bufio.NewWriter(f)
	defer w.Flush()

	fmt.Fprintln(w, "P3", image.width, image.height, 255)
	for y := 0; y < image.height; y++ {
		for x := 0; x < image.width; x++ {
			color := image.frame[image.height-y-1][x]
			fmt.Fprintln(w, color.r, color.b, color.g)
		}
	}
	return nil
}

// Save will save an Image into a given format
func (image *Image) Save(name string) error {
	index := strings.Index(name, ".")
	extension := ".ppm"
	if index == -1 {
		extension = ".png"
	} else {
		extension = name[index:]
		name = name[:index]
	}

	if extension == ".ppm" {
		// save as ppm without converting
		err := image.SavePpm(fmt.Sprint(name, ".ppm"))
		return err
	}

	ppm := fmt.Sprint(name, "-tmp.ppm")
	err := image.SavePpm(ppm)
	if err != nil {
		return err
	}
	defer os.Remove(ppm)
	err = exec.Command("convert", ppm, fmt.Sprint(name, extension)).Run()
	return err
}

// Display displays the Image
func (image *Image) Display() error {
	filename := "tmp.ppm"
	err := image.SavePpm(filename)
	if err != nil {
		return err
	}
	defer os.Remove(filename)

	err = exec.Command("display", filename).Run()
	return err
}

// MakeAnimation converts individual frames to a gif
func MakeAnimation(basename string) error {
	path := fmt.Sprintf("%s/%s*", FramesDirectory, basename)
	gif := fmt.Sprintf("%s.gif", basename)
	err := exec.Command("convert", "-delay", "3", path, gif).Run()
	return err
}

func isVisible(p0, p1, p2 []float64) bool {
	a := []float64{p1[0] - p0[0], p1[1] - p0[1], p1[2] - p0[2]}
	b := []float64{p2[0] - p0[0], p2[1] - p0[1], p2[2] - p0[2]}
	normal := CrossProduct(a, b)
	return normal[2] > 0
}
<commit_msg>Add comments on plotting behavior<commit_after>package main

import (
	"bufio"
	"errors"
	"fmt"
	"os"
	"os/exec"
	"strings"
)

const (
	// DefaultHeight is the default height of an Image
	DefaultHeight = 500
	// DefaultWidth is the default width of an Image
	DefaultWidth = 500
)

var (
	Black = NewColor(0, 0, 0)
	White = NewColor(255, 255, 255)
)

type Color struct {
	r byte
	b byte
	g byte
}

func NewColor(r, g, b byte) Color {
	return Color{r, g, b}
}

// Image represents an image
type Image struct {
	frame  [][]Color
	height int
	width  int
}

// NewImage returns a new Image with the given height and width
func NewImage(height, width int) *Image {
	frame := make([][]Color, height)
	for i := 0; i < height; i++ {
		frame[i] = make([]Color, width)
	}
	image := &Image{
		frame:  frame,
		height: height,
		width:  width,
	}
	image.Fill(Black)
	return image
}

// DrawLines draws all lines onto the Image
func (image *Image) DrawLines(em *Matrix, c Color) error {
	if em.cols < 2 {
		return errors.New("2 or more points are required for drawing")
	}
	for i := 0; i < em.cols-1; i += 2 {
		p0 := em.GetColumn(i)
		p1 := em.GetColumn(i + 1)
		image.DrawLine(int(p0[0]), int(p0[1]), int(p1[0]), int(p1[1]), c)
	}
	return nil
}

// DrawPolygons draws all polygons onto the Image
func (image *Image) DrawPolygons(em *Matrix, c Color) error {
	if em.cols < 3 {
		return errors.New("3 or more points are required for drawing")
	}
	for i := 0; i < em.cols-2; i += 3 {
		p0 := em.GetColumn(i)
		p1 := em.GetColumn(i + 1)
		p2 := em.GetColumn(i + 2)
		if isVisible(p0, p1, p2) {
			image.DrawLine(int(p0[0]), int(p0[1]), int(p1[0]), int(p1[1]), c)
			image.DrawLine(int(p1[0]), int(p1[1]), int(p2[0]), int(p2[1]), c)
			image.DrawLine(int(p2[0]), int(p2[1]), int(p0[0]), int(p0[1]), c)
		}
	}
	return nil
}

// DrawLine draws a single line onto the Image
func (image *Image) DrawLine(x1, y1, x2, y2 int, c Color) {
	if x1 > x2 {
		x1, x2 = x2, x1
		y1, y2 = y2, y1
	}

	A := 2 * (y2 - y1)
	B := 2 * -(x2 - x1)
	m := float32(A) / float32(-B)
	if m >= 0 {
		if m <= 1 {
			image.drawOctant1(x1, y1, x2, y2, A, B, c)
		} else {
			image.drawOctant2(x1, y1, x2, y2, A, B, c)
		}
	} else {
		if m < -1 {
			image.drawOctant7(x1, y1, x2, y2, A, B, c)
		} else {
			image.drawOctant8(x1, y1, x2, y2, A, B, c)
		}
	}
}

func (image *Image) drawOctant1(x1, y1, x2, y2, A, B int, c Color) {
	d := A + B/2
	for x1 <= x2 {
		image.set(x1, y1, c)
		if d > 0 {
			y1++
			d += B
		}
		x1++
		d += A
	}
}

func (image *Image) drawOctant2(x1, y1, x2, y2, A, B int, c Color) {
	d := A/2 + B
	for y1 <= y2 {
		image.set(x1, y1, c)
		if d < 0 {
			x1++
			d += A
		}
		y1++
		d += B
	}
}

func (image *Image) drawOctant7(x1, y1, x2, y2, A, B int, c Color) {
	d := A/2 + B
	for y1 >= y2 {
		image.set(x1, y1, c)
		if d > 0 {
			x1++
			d += A
		}
		y1--
		d -= B
	}
}

func (image *Image) drawOctant8(x1, y1, x2, y2, A, B int, c Color) {
	d := A - B/2
	for x1 <= x2 {
		image.set(x1, y1, c)
		if d < 0 {
			y1--
			d -= B
		}
		x1++
		d += A
	}
}

// Fill completely fills the Image with a single color
func (image *Image) Fill(c Color) {
	for y := 0; y < image.height; y++ {
		for x := 0; x < image.width; x++ {
			image.set(x, y, c)
		}
	}
}

func (image *Image) set(x, y int, c Color) {
	if (x < 0 || x >= image.width) || (y < 0 || y >= image.height) {
		return
	}
	// Plot so that the y coodinate is the row, and the x coordinate is the column
	image.frame[y][x] = c
}

// SavePpm will save the Image as a ppm
func (image *Image) SavePpm(name string) error {
	f, err := os.Create(name)
	if err != nil {
		return err
	}
	defer f.Close()

	w := bufio.NewWriter(f)
	defer w.Flush()

	fmt.Fprintln(w, "P3", image.width, image.height, 255)
	for y := 0; y < image.height; y++ {
		// Adjust y coordinate that the origin is the bottom left
		adjustedY := image.height - y - 1
		for x := 0; x < image.width; x++ {
			color := image.frame[adjustedY][x]
			fmt.Fprintln(w, color.r, color.b, color.g)
		}
	}
	return nil
}

// Save will save an Image into a given format
func (image *Image) Save(name string) error {
	index := strings.Index(name, ".")
	extension := ".ppm"
	if index == -1 {
		extension = ".png"
	} else {
		extension = name[index:]
		name = name[:index]
	}

	if extension == ".ppm" {
		// save as ppm without converting
		err := image.SavePpm(fmt.Sprint(name, ".ppm"))
		return err
	}

	ppm := fmt.Sprint(name, "-tmp.ppm")
	err := image.SavePpm(ppm)
	if err != nil {
		return err
	}
	defer os.Remove(ppm)
	err = exec.Command("convert", ppm, fmt.Sprint(name, extension)).Run()
	return err
}

// Display displays the Image
func (image *Image) Display() error {
	filename := "tmp.ppm"
	err := image.SavePpm(filename)
	if err != nil {
		return err
	}
	defer os.Remove(filename)

	err = exec.Command("display", filename).Run()
	return err
}

// MakeAnimation converts individual frames to a gif
func MakeAnimation(basename string) error {
	path := fmt.Sprintf("%s/%s*", FramesDirectory, basename)
	gif := fmt.Sprintf("%s.gif", basename)
	err := exec.Command("convert", "-delay", "3", path, gif).Run()
	return err
}

func isVisible(p0, p1, p2 []float64) bool {
	a := []float64{p1[0] - p0[0], p1[1] - p0[1], p1[2] - p0[2]}
	b := []float64{p2[0] - p0[0], p2[1] - p0[1], p2[2] - p0[2]}
	normal := CrossProduct(a, b)
	return normal[2] > 0
}
<|endoftext|>


<commit_before>package venom

import (
	"encoding/json"
	"encoding/xml"
	"fmt"
	"io/ioutil"
	"os"
	"time"

	log "github.com/Sirupsen/logrus"
	"gopkg.in/yaml.v2"
)

// Version of Venom
// One Line for this, used by release.sh script
// Keep "const Version on one line"
const Version = "0.0.8"

// PrintFunc used by venom to print output
var PrintFunc = fmt.Printf

var (
	executors = map[string]Executor{}
	contexts  = map[string]TestCaseContext{}
)

const (
	// ContextKey is key for Test Case Context. this
	// can be used by executors for getting context
	ContextKey = "tcContext"
)

// RegisterExecutor register Test Executors
func RegisterExecutor(name string, e Executor) {
	executors[name] = e
}

// WrapExecutor initializes a test by name
// no type -> exec is default
func WrapExecutor(t map[string]interface{}, tcc TestCaseContext) (*ExecutorWrap, error) {
	var name string
	var retry, delay, timeout int

	if itype, ok := t["type"]; ok {
		name = fmt.Sprintf("%s", itype)
	}

	if name == "" && tcc.GetName() != "default" {
		name = tcc.GetName()
	} else if name == "" {
		name = "exec"
	}

	retry, errRetry := getAttrInt(t, "retry")
	if errRetry != nil {
		return nil, errRetry
	}
	delay, errDelay := getAttrInt(t, "delay")
	if errDelay != nil {
		return nil, errDelay
	}
	timeout, errTimeout := getAttrInt(t, "timeout")
	if errTimeout != nil {
		return nil, errTimeout
	}

	if e, ok := executors[name]; ok {
		ew := &ExecutorWrap{
			executor: e,
			retry:    retry,
			delay:    delay,
			timeout:  timeout,
		}
		return ew, nil
	}

	return nil, fmt.Errorf("[%s] type '%s' is not implemented", tcc.GetName(), name)
}

// RegisterTestCaseContext new register TestCaseContext
func RegisterTestCaseContext(name string, tcc TestCaseContext) {
	contexts[name] = tcc
}

// ContextWrap initializes a context for a testcase
// no type -> parent context
func ContextWrap(tc *TestCase) (TestCaseContext, error) {
	if tc.Context == nil {
		return contexts["default"], nil
	}
	var typeName string
	if itype, ok := tc.Context["type"]; ok {
		typeName = fmt.Sprintf("%s", itype)
	}

	if typeName == "" {
		return nil, fmt.Errorf("context type '%s' is not implemented", typeName)
	}
	contexts[typeName].SetTestCase(*tc)
	return contexts[typeName], nil
}

func getAttrInt(t map[string]interface{}, name string) (int, error) {
	var out int
	if i, ok := t[name]; ok {
		var ok bool
		out, ok = i.(int)
		if !ok {
			return -1, fmt.Errorf("attribute %s '%s' is not an integer", name, i)
		}
	}
	if out < 0 {
		out = 0
	}
	return out, nil
}

// Exit func display an error message on stderr and exit 1
func Exit(format string, args ...interface{}) {
	fmt.Fprintf(os.Stderr, format, args...)
	os.Exit(1)
}

// OutputResult output result to sdtout, files...
func OutputResult(format string, resume, resumeFailures bool, outputDir string, tests Tests, elapsed time.Duration, detailsLevel string) error {
	var data []byte
	var err error
	switch format {
	case "json":
		data, err = json.Marshal(tests)
		if err != nil {
			log.Fatalf("Error: cannot format output json (%s)", err)
		}
	case "yml", "yaml":
		data, err = yaml.Marshal(tests)
		if err != nil {
			log.Fatalf("Error: cannot format output yaml (%s)", err)
		}
	default:
		dataxml, errm := xml.Marshal(tests)
		if errm != nil {
			log.Fatalf("Error: cannot format xml output: %s", errm)
		}
		data = append([]byte("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"), dataxml...)
	}

	if detailsLevel == "high" {
		PrintFunc(string(data))
	}

	if resume {
		outputResume(tests, elapsed, resumeFailures)
	}

	if outputDir != "" {
		filename := outputDir + "/" + "test_results" + "." + format
		if err := ioutil.WriteFile(filename, data, 0644); err != nil {
			return fmt.Errorf("Error while creating file %s, err:%s", filename, err)
		}
	}
	return nil
}

func outputResume(tests Tests, elapsed time.Duration, resumeFailures bool) {

	if resumeFailures {
		for _, t := range tests.TestSuites {
			if t.Failures > 0 || t.Errors > 0 {
				PrintFunc("FAILED %s\n", t.Name)
				PrintFunc("--------------\n")

				for _, tc := range t.TestCases {
					for _, f := range tc.Failures {
						PrintFunc("%s\n", f.Value)
					}
					for _, f := range tc.Errors {
						PrintFunc("%s\n", f.Value)
					}
				}
				PrintFunc("-=-=-=-=-=-=-=-=-\n")
			}
		}
	}

	totalTestCases := 0
	totalTestSteps := 0
	for _, t := range tests.TestSuites {
		if t.Failures > 0 || t.Errors > 0 {
			PrintFunc("FAILED %s\n", t.Name)
		}
		totalTestCases += len(t.TestCases)
		for _, tc := range t.TestCases {
			totalTestSteps += len(tc.TestSteps)
		}
	}

	PrintFunc("Total:%d TotalOK:%d TotalKO:%d TotalSkipped:%d TotalTestSuite:%d TotalTestCase:%d TotalTestStep:%d Duration:%s\n",
		tests.Total,
		tests.TotalOK,
		tests.TotalKO,
		tests.TotalSkipped,
		len(tests.TestSuites),
		totalTestCases,
		totalTestSteps,
		elapsed,
	)
}
<commit_msg>[auto] bump version to v0.0.9<commit_after>package venom

import (
	"encoding/json"
	"encoding/xml"
	"fmt"
	"io/ioutil"
	"os"
	"time"

	log "github.com/Sirupsen/logrus"
	"gopkg.in/yaml.v2"
)

// Version of Venom
// One Line for this, used by release.sh script
// Keep "const Version on one line"
const Version = "0.0.9"

// PrintFunc used by venom to print output
var PrintFunc = fmt.Printf

var (
	executors = map[string]Executor{}
	contexts  = map[string]TestCaseContext{}
)

const (
	// ContextKey is key for Test Case Context. this
	// can be used by executors for getting context
	ContextKey = "tcContext"
)

// RegisterExecutor register Test Executors
func RegisterExecutor(name string, e Executor) {
	executors[name] = e
}

// WrapExecutor initializes a test by name
// no type -> exec is default
func WrapExecutor(t map[string]interface{}, tcc TestCaseContext) (*ExecutorWrap, error) {
	var name string
	var retry, delay, timeout int

	if itype, ok := t["type"]; ok {
		name = fmt.Sprintf("%s", itype)
	}

	if name == "" && tcc.GetName() != "default" {
		name = tcc.GetName()
	} else if name == "" {
		name = "exec"
	}

	retry, errRetry := getAttrInt(t, "retry")
	if errRetry != nil {
		return nil, errRetry
	}
	delay, errDelay := getAttrInt(t, "delay")
	if errDelay != nil {
		return nil, errDelay
	}
	timeout, errTimeout := getAttrInt(t, "timeout")
	if errTimeout != nil {
		return nil, errTimeout
	}

	if e, ok := executors[name]; ok {
		ew := &ExecutorWrap{
			executor: e,
			retry:    retry,
			delay:    delay,
			timeout:  timeout,
		}
		return ew, nil
	}

	return nil, fmt.Errorf("[%s] type '%s' is not implemented", tcc.GetName(), name)
}

// RegisterTestCaseContext new register TestCaseContext
func RegisterTestCaseContext(name string, tcc TestCaseContext) {
	contexts[name] = tcc
}

// ContextWrap initializes a context for a testcase
// no type -> parent context
func ContextWrap(tc *TestCase) (TestCaseContext, error) {
	if tc.Context == nil {
		return contexts["default"], nil
	}
	var typeName string
	if itype, ok := tc.Context["type"]; ok {
		typeName = fmt.Sprintf("%s", itype)
	}

	if typeName == "" {
		return nil, fmt.Errorf("context type '%s' is not implemented", typeName)
	}
	contexts[typeName].SetTestCase(*tc)
	return contexts[typeName], nil
}

func getAttrInt(t map[string]interface{}, name string) (int, error) {
	var out int
	if i, ok := t[name]; ok {
		var ok bool
		out, ok = i.(int)
		if !ok {
			return -1, fmt.Errorf("attribute %s '%s' is not an integer", name, i)
		}
	}
	if out < 0 {
		out = 0
	}
	return out, nil
}

// Exit func display an error message on stderr and exit 1
func Exit(format string, args ...interface{}) {
	fmt.Fprintf(os.Stderr, format, args...)
	os.Exit(1)
}

// OutputResult output result to sdtout, files...
func OutputResult(format string, resume, resumeFailures bool, outputDir string, tests Tests, elapsed time.Duration, detailsLevel string) error {
	var data []byte
	var err error
	switch format {
	case "json":
		data, err = json.Marshal(tests)
		if err != nil {
			log.Fatalf("Error: cannot format output json (%s)", err)
		}
	case "yml", "yaml":
		data, err = yaml.Marshal(tests)
		if err != nil {
			log.Fatalf("Error: cannot format output yaml (%s)", err)
		}
	default:
		dataxml, errm := xml.Marshal(tests)
		if errm != nil {
			log.Fatalf("Error: cannot format xml output: %s", errm)
		}
		data = append([]byte("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"), dataxml...)
	}

	if detailsLevel == "high" {
		PrintFunc(string(data))
	}

	if resume {
		outputResume(tests, elapsed, resumeFailures)
	}

	if outputDir != "" {
		filename := outputDir + "/" + "test_results" + "." + format
		if err := ioutil.WriteFile(filename, data, 0644); err != nil {
			return fmt.Errorf("Error while creating file %s, err:%s", filename, err)
		}
	}
	return nil
}

func outputResume(tests Tests, elapsed time.Duration, resumeFailures bool) {

	if resumeFailures {
		for _, t := range tests.TestSuites {
			if t.Failures > 0 || t.Errors > 0 {
				PrintFunc("FAILED %s\n", t.Name)
				PrintFunc("--------------\n")

				for _, tc := range t.TestCases {
					for _, f := range tc.Failures {
						PrintFunc("%s\n", f.Value)
					}
					for _, f := range tc.Errors {
						PrintFunc("%s\n", f.Value)
					}
				}
				PrintFunc("-=-=-=-=-=-=-=-=-\n")
			}
		}
	}

	totalTestCases := 0
	totalTestSteps := 0
	for _, t := range tests.TestSuites {
		if t.Failures > 0 || t.Errors > 0 {
			PrintFunc("FAILED %s\n", t.Name)
		}
		totalTestCases += len(t.TestCases)
		for _, tc := range t.TestCases {
			totalTestSteps += len(tc.TestSteps)
		}
	}

	PrintFunc("Total:%d TotalOK:%d TotalKO:%d TotalSkipped:%d TotalTestSuite:%d TotalTestCase:%d TotalTestStep:%d Duration:%s\n",
		tests.Total,
		tests.TotalOK,
		tests.TotalKO,
		tests.TotalSkipped,
		len(tests.TestSuites),
		totalTestCases,
		totalTestSteps,
		elapsed,
	)
}
<|endoftext|>


<commit_before>package venom

import (
	"encoding/json"
	"encoding/xml"
	"fmt"
	"io/ioutil"
	"os"
	"time"

	log "github.com/Sirupsen/logrus"
	"gopkg.in/yaml.v2"
)

// Version of Venom
// One Line for this, used by release.sh script
// Keep "const Version on one line"
const Version = "0.0.1"

// PrintFunc used by venom to print output
var PrintFunc = fmt.Printf

var (
	executors = map[string]Executor{}
	contexts  = map[string]TestCaseContext{}
)

const (
	// ContextKey is key for Test Case Context. this
	// can be used by executors for getting context
	ContextKey = "tcContext"
)

// RegisterExecutor register Test Executors
func RegisterExecutor(name string, e Executor) {
	executors[name] = e
}

// getExecutorWrap initializes a test by name
// no type -> exec is default
func getExecutorWrap(t map[string]interface{}, tcc TestCaseContext) (*executorWrap, error) {
	var name string
	var retry, delay, timeout int

	if itype, ok := t["type"]; ok {
		name = fmt.Sprintf("%s", itype)
	}

	if name == "" && tcc.GetName() != "default" {
		name = tcc.GetName()
	} else if name == "" {
		name = "exec"
	}

	retry, errRetry := getAttrInt(t, "retry")
	if errRetry != nil {
		return nil, errRetry
	}
	delay, errDelay := getAttrInt(t, "delay")
	if errDelay != nil {
		return nil, errDelay
	}
	timeout, errTimeout := getAttrInt(t, "timeout")
	if errTimeout != nil {
		return nil, errTimeout
	}

	if e, ok := executors[name]; ok {
		ew := &executorWrap{
			executor: e,
			retry:    retry,
			delay:    delay,
			timeout:  timeout,
		}
		return ew, nil
	}

	return nil, fmt.Errorf("[%s] type '%s' is not implemented", tcc.GetName(), name)
}

// RegisterTestCaseContext new register TestCaseContext
func RegisterTestCaseContext(name string, tcc TestCaseContext) {
	contexts[name] = tcc
}

// getContextWrap initializes a context for a testcase
// no type -> parent context
func getContextWrap(tc *TestCase) (TestCaseContext, error) {
	if tc.Context == nil {
		return contexts["default"], nil
	}
	var typeName string
	if itype, ok := tc.Context["type"]; ok {
		typeName = fmt.Sprintf("%s", itype)
	}

	if typeName == "" {
		return nil, fmt.Errorf("context type '%s' is not implemented", typeName)
	}
	contexts[typeName].SetTestCase(*tc)
	return contexts[typeName], nil
}

func getAttrInt(t map[string]interface{}, name string) (int, error) {
	var out int
	if i, ok := t[name]; ok {
		var ok bool
		out, ok = i.(int)
		if !ok {
			return -1, fmt.Errorf("attribute %s '%s' is not an integer", name, i)
		}
	}
	if out < 0 {
		out = 0
	}
	return out, nil
}

// Exit func display an error message on stderr and exit 1
func Exit(format string, args ...interface{}) {
	fmt.Fprintf(os.Stderr, format, args...)
	os.Exit(1)
}

// OutputResult output result to sdtout, files...
func OutputResult(format string, resume, resumeFailures bool, outputDir string, tests Tests, elapsed time.Duration, detailsLevel string) error {
	var data []byte
	var err error
	switch format {
	case "json":
		data, err = json.Marshal(tests)
		if err != nil {
			log.Fatalf("Error: cannot format output json (%s)", err)
		}
	case "yml", "yaml":
		data, err = yaml.Marshal(tests)
		if err != nil {
			log.Fatalf("Error: cannot format output yaml (%s)", err)
		}
	default:
		dataxml, errm := xml.Marshal(tests)
		if errm != nil {
			log.Fatalf("Error: cannot format xml output: %s", errm)
		}
		data = append([]byte("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"), dataxml...)
	}

	if detailsLevel == "high" {
		PrintFunc(string(data))
	}

	if resume {
		outputResume(tests, elapsed, resumeFailures)
	}

	if outputDir != "" {
		filename := outputDir + "/" + "test_results" + "." + format
		if err := ioutil.WriteFile(filename, data, 0644); err != nil {
			return fmt.Errorf("Error while creating file %s, err:%s", filename, err)
		}
	}
	return nil
}

func outputResume(tests Tests, elapsed time.Duration, resumeFailures bool) {

	if resumeFailures {
		for _, t := range tests.TestSuites {
			if t.Failures > 0 || t.Errors > 0 {
				PrintFunc("FAILED %s\n", t.Name)
				PrintFunc("--------------\n")

				for _, tc := range t.TestCases {
					for _, f := range tc.Failures {
						PrintFunc("%s\n", f.Value)
					}
					for _, f := range tc.Errors {
						PrintFunc("%s\n", f.Value)
					}
				}
				PrintFunc("-=-=-=-=-=-=-=-=-\n")
			}
		}
	}

	totalTestCases := 0
	totalTestSteps := 0
	for _, t := range tests.TestSuites {
		if t.Failures > 0 || t.Errors > 0 {
			PrintFunc("FAILED %s\n", t.Name)
		}
		totalTestCases += len(t.TestCases)
		for _, tc := range t.TestCases {
			totalTestSteps += len(tc.TestSteps)
		}
	}

	PrintFunc("Total:%d TotalOK:%d TotalKO:%d TotalSkipped:%d TotalTestSuite:%d TotalTestCase:%d TotalTestStep:%d Duration:%s\n",
		tests.Total,
		tests.TotalOK,
		tests.TotalKO,
		tests.TotalSkipped,
		len(tests.TestSuites),
		totalTestCases,
		totalTestSteps,
		elapsed,
	)
}
<commit_msg>[auto] bump version to v0.0.2<commit_after>package venom

import (
	"encoding/json"
	"encoding/xml"
	"fmt"
	"io/ioutil"
	"os"
	"time"

	log "github.com/Sirupsen/logrus"
	"gopkg.in/yaml.v2"
)

// Version of Venom
// One Line for this, used by release.sh script
// Keep "const Version on one line"
const Version = "0.0.2"

// PrintFunc used by venom to print output
var PrintFunc = fmt.Printf

var (
	executors = map[string]Executor{}
	contexts  = map[string]TestCaseContext{}
)

const (
	// ContextKey is key for Test Case Context. this
	// can be used by executors for getting context
	ContextKey = "tcContext"
)

// RegisterExecutor register Test Executors
func RegisterExecutor(name string, e Executor) {
	executors[name] = e
}

// getExecutorWrap initializes a test by name
// no type -> exec is default
func getExecutorWrap(t map[string]interface{}, tcc TestCaseContext) (*executorWrap, error) {
	var name string
	var retry, delay, timeout int

	if itype, ok := t["type"]; ok {
		name = fmt.Sprintf("%s", itype)
	}

	if name == "" && tcc.GetName() != "default" {
		name = tcc.GetName()
	} else if name == "" {
		name = "exec"
	}

	retry, errRetry := getAttrInt(t, "retry")
	if errRetry != nil {
		return nil, errRetry
	}
	delay, errDelay := getAttrInt(t, "delay")
	if errDelay != nil {
		return nil, errDelay
	}
	timeout, errTimeout := getAttrInt(t, "timeout")
	if errTimeout != nil {
		return nil, errTimeout
	}

	if e, ok := executors[name]; ok {
		ew := &executorWrap{
			executor: e,
			retry:    retry,
			delay:    delay,
			timeout:  timeout,
		}
		return ew, nil
	}

	return nil, fmt.Errorf("[%s] type '%s' is not implemented", tcc.GetName(), name)
}

// RegisterTestCaseContext new register TestCaseContext
func RegisterTestCaseContext(name string, tcc TestCaseContext) {
	contexts[name] = tcc
}

// getContextWrap initializes a context for a testcase
// no type -> parent context
func getContextWrap(tc *TestCase) (TestCaseContext, error) {
	if tc.Context == nil {
		return contexts["default"], nil
	}
	var typeName string
	if itype, ok := tc.Context["type"]; ok {
		typeName = fmt.Sprintf("%s", itype)
	}

	if typeName == "" {
		return nil, fmt.Errorf("context type '%s' is not implemented", typeName)
	}
	contexts[typeName].SetTestCase(*tc)
	return contexts[typeName], nil
}

func getAttrInt(t map[string]interface{}, name string) (int, error) {
	var out int
	if i, ok := t[name]; ok {
		var ok bool
		out, ok = i.(int)
		if !ok {
			return -1, fmt.Errorf("attribute %s '%s' is not an integer", name, i)
		}
	}
	if out < 0 {
		out = 0
	}
	return out, nil
}

// Exit func display an error message on stderr and exit 1
func Exit(format string, args ...interface{}) {
	fmt.Fprintf(os.Stderr, format, args...)
	os.Exit(1)
}

// OutputResult output result to sdtout, files...
func OutputResult(format string, resume, resumeFailures bool, outputDir string, tests Tests, elapsed time.Duration, detailsLevel string) error {
	var data []byte
	var err error
	switch format {
	case "json":
		data, err = json.Marshal(tests)
		if err != nil {
			log.Fatalf("Error: cannot format output json (%s)", err)
		}
	case "yml", "yaml":
		data, err = yaml.Marshal(tests)
		if err != nil {
			log.Fatalf("Error: cannot format output yaml (%s)", err)
		}
	default:
		dataxml, errm := xml.Marshal(tests)
		if errm != nil {
			log.Fatalf("Error: cannot format xml output: %s", errm)
		}
		data = append([]byte("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"), dataxml...)
	}

	if detailsLevel == "high" {
		PrintFunc(string(data))
	}

	if resume {
		outputResume(tests, elapsed, resumeFailures)
	}

	if outputDir != "" {
		filename := outputDir + "/" + "test_results" + "." + format
		if err := ioutil.WriteFile(filename, data, 0644); err != nil {
			return fmt.Errorf("Error while creating file %s, err:%s", filename, err)
		}
	}
	return nil
}

func outputResume(tests Tests, elapsed time.Duration, resumeFailures bool) {

	if resumeFailures {
		for _, t := range tests.TestSuites {
			if t.Failures > 0 || t.Errors > 0 {
				PrintFunc("FAILED %s\n", t.Name)
				PrintFunc("--------------\n")

				for _, tc := range t.TestCases {
					for _, f := range tc.Failures {
						PrintFunc("%s\n", f.Value)
					}
					for _, f := range tc.Errors {
						PrintFunc("%s\n", f.Value)
					}
				}
				PrintFunc("-=-=-=-=-=-=-=-=-\n")
			}
		}
	}

	totalTestCases := 0
	totalTestSteps := 0
	for _, t := range tests.TestSuites {
		if t.Failures > 0 || t.Errors > 0 {
			PrintFunc("FAILED %s\n", t.Name)
		}
		totalTestCases += len(t.TestCases)
		for _, tc := range t.TestCases {
			totalTestSteps += len(tc.TestSteps)
		}
	}

	PrintFunc("Total:%d TotalOK:%d TotalKO:%d TotalSkipped:%d TotalTestSuite:%d TotalTestCase:%d TotalTestStep:%d Duration:%s\n",
		tests.Total,
		tests.TotalOK,
		tests.TotalKO,
		tests.TotalSkipped,
		len(tests.TestSuites),
		totalTestCases,
		totalTestSteps,
		elapsed,
	)
}
<|endoftext|>


<commit_before>/*
The MIT License (MIT)

Copyright (c) 2016-2018 Ivan Dejanovic

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

package vm

import (
	"fmt"
	"github.com/ivandejanovic/tpm/common"
	"math"
	"math/bits"
)

// Bit Masks
const (
	INST_MASK     uint64 = 0xFF
	REG_MASK      uint64 = 0xF
	FULL_REG_MASK uint64 = 0x1F
)

//Rotation values
const (
	INST_ROTATION        int = 8
	OPERAND_ONE_ROTATION int = 12
	OPERAND_TWO_ROTATION int = 15
	FULL_REG_ROTATION    int = 13
)

//Register index
const (
	IP_INDEX  uint = 8
	SP_INDEX  uint = 9
	ACC_INDEX uint = 10
)

// Opcodes
const (
	HALT  uint = 0x00
	IN_N  uint = 0x01
	OUT_N uint = 0x02
	IN_S  uint = 0x03
	OUT_S uint = 0x04
	ADD   uint = 0x05
	SUB   uint = 0x06
	MUL   uint = 0x07
	DIV   uint = 0x08
	CON   uint = 0x09
	PUSH  uint = 0x0A
	POP   uint = 0x0B
	LD    uint = 0x0C
	ST    uint = 0x0D
	JMP   uint = 0x0E
	JGR   uint = 0x0F
	JGE   uint = 0x10
	JEQ   uint = 0x11
	JNE   uint = 0x12
	JLE   uint = 0x13
	JLS   uint = 0x14
)

const (
	REG_NUM          uint   = 8
	MEM_CAP          uint64 = 50000
	VAR_MEM_TOP      uint64 = 50000
	VAR_MEM_BOTTOM   uint64 = 40001
	STACK_MEM_TOP    uint64 = 40000
	STACK_MEM_BOTTOM uint64 = 30001
)

type vm struct {
	ip  uint64
	sp  uint64
	acc uint64
	reg [REG_NUM]uint64
	mem [MEM_CAP]uint64
}

func Execute(code []string) {
	vm := &vm{ip: 0, sp: 0, acc: 0}

	vm.load(code)
	vm.execute()
}

func (vm *vm) load(code []string) {
	//Create and initialize op codes map
	opCodes := make(map[uint]string)

	opCodes[HALT] = common.HALT
	opCodes[IN_N] = common.IN_N
	opCodes[OUT_N] = common.OUT_N
	opCodes[IN_S] = common.IN_S
	opCodes[OUT_S] = common.OUT_S
	opCodes[ADD] = common.ADD
	opCodes[SUB] = common.SUB
	opCodes[MUL] = common.MUL
	opCodes[DIV] = common.DIV
	opCodes[CON] = common.CON
	opCodes[PUSH] = common.PUSH
	opCodes[POP] = common.POP
	opCodes[LD] = common.LD
	opCodes[ST] = common.ST
	opCodes[JMP] = common.JMP
	opCodes[JGR] = common.JGR
	opCodes[JGE] = common.JGE
	opCodes[JEQ] = common.JEQ
	opCodes[JNE] = common.JNE
	opCodes[JLE] = common.JLE
	opCodes[JLS] = common.JLS

	for _, inst := range code {
		fmt.Println(inst)
	}
}

func (vm *vm) execute() {
	for {
		inst := vm.mem[vm.ip]
		opcode := uint(bits.RotateLeft64(inst, INST_ROTATION) & INST_MASK)

		switch opcode {
		case HALT:
			break
		case IN_N:
			vm.processInN()
		case OUT_N:
			vm.processOutN()
		case IN_S:
			vm.processInS()
		case OUT_S:
			vm.processOutS()
		case ADD:
			vm.processAdd()
		case SUB:
			vm.processSub()
		case MUL:
			vm.processMul()
		case DIV:
			vm.processDiv()
		case CON:
			vm.processCon()
		case PUSH:
			vm.processPush()
		case POP:
			vm.processPop()
		case LD:
			vm.processLd()
		case ST:
			vm.processSt()
		case JMP:
			vm.processJmp()
		case JGR:
			vm.processJgr()
		case JGE:
			vm.processJge()
		case JEQ:
			vm.processJeq()
		case JNE:
			vm.processJne()
		case JLE:
			vm.processJle()
		case JLS:
			vm.processJls()
		default:
			fmt.Println("Unknow instruction. Aborting.")
			break
		}

		if vm.hasErrors() {
			vm.throwException()
			break
		}
	}
}

func (vm *vm) processInN() {
	var input float64 = 0.0
	_, err := fmt.Scanf("%f", &input)
	if err != nil {
		fmt.Println("")
		vm.setIOErrorFlag()
		return
	}
	vm.acc = math.Float64bits(input)
	vm.ip = vm.ip + 1
}

func (vm *vm) processOutN() {
	output := math.Float64frombits(vm.acc)
	fmt.Println(output)
	vm.ip = vm.ip + 1
}

func (vm *vm) processInS() {

}

func (vm *vm) processOutS() {

}

func (vm *vm) processAdd() {
	operand1 := vm.getOperand(OPERAND_ONE_ROTATION)
	operand2 := vm.getOperand(OPERAND_TWO_ROTATION)
	result := operand1 + operand2
	vm.acc = math.Float64bits(result)
	vm.ip = vm.ip + 1
}

func (vm *vm) processSub() {
	operand1 := vm.getOperand(OPERAND_ONE_ROTATION)
	operand2 := vm.getOperand(OPERAND_TWO_ROTATION)
	result := operand1 - operand2
	vm.acc = math.Float64bits(result)
	vm.ip = vm.ip + 1
}

func (vm *vm) processMul() {
	operand1 := vm.getOperand(OPERAND_ONE_ROTATION)
	operand2 := vm.getOperand(OPERAND_TWO_ROTATION)
	result := operand1 * operand2
	vm.acc = math.Float64bits(result)
	vm.ip = vm.ip + 1
}

func (vm *vm) processDiv() {
	operand1 := vm.getOperand(OPERAND_ONE_ROTATION)
	operand2 := vm.getOperand(OPERAND_TWO_ROTATION)
	result := operand1 / operand2
	vm.acc = math.Float64bits(result)
	vm.ip = vm.ip + 1
}

func (vm *vm) processCon() {

}

func (vm *vm) processPush() {
	//Check if stack is full
	if vm.sp <= STACK_MEM_BOTTOM {
		vm.setMemErrorFlags("Push attempt on full stack.")
		return
	}

	regIndex := vm.getRegisterIndex()
	var value uint64 = 0

	if regIndex < REG_NUM {
		value = vm.reg[regIndex]
	} else if regIndex == IP_INDEX {
		value = uint64(vm.ip)

	} else if regIndex == SP_INDEX {
		value = uint64(vm.sp)
	} else if regIndex == ACC_INDEX {
		value = vm.acc
	} else {
		vm.setMemErrorFlags("Push attempt on unkown register.")
		return
	}

	vm.mem[vm.sp] = value
	vm.sp = vm.sp - 1
}

func (vm *vm) processPop() {
	//Check if stack is empty
	if vm.sp > STACK_MEM_TOP {
		vm.setMemErrorFlags("Pop attempt on empty stack.")
		return
	}

	regIndex := vm.getRegisterIndex()
	value := vm.mem[vm.sp]
	vm.sp = vm.sp + 1

	if regIndex < REG_NUM {
		vm.reg[regIndex] = value
	} else if regIndex == IP_INDEX {
		vm.ip = value
	} else if regIndex == SP_INDEX {
		vm.sp = value
	} else if regIndex == ACC_INDEX {
		vm.acc = value
	} else {
		vm.setMemErrorFlags("Pop attempt on unkown register.")
		return
	}
}

func (vm *vm) processLd() {
	//regIndex := vm.getRegisterIndex()
}

func (vm *vm) processSt() {
	//regIndex := vm.getRegisterIndex()
}

func (vm *vm) processJmp() {

}

func (vm *vm) processJgr() {

}

func (vm *vm) processJge() {

}

func (vm *vm) processJeq() {

}

func (vm *vm) processJne() {

}

func (vm *vm) processJle() {

}

func (vm *vm) processJls() {

}

func (vm *vm) setIOErrorFlag() {
	fmt.Println("IO error flag set!")
}

func (vm *vm) setMemErrorFlags(err string) {
	fmt.Println(err)
}

func (vm *vm) hasErrors() bool {
	return false
}

func (vm *vm) throwException() {
	fmt.Println("Exception thrown!")
}

func (vm *vm) getOperand(rotation int) float64 {
	inst := vm.mem[vm.ip]
	operandReg := bits.RotateLeft64(inst, rotation) & REG_MASK
	operand := math.Float64frombits(operandReg)

	return operand
}

func (vm *vm) getRegisterIndex() uint {
	inst := vm.mem[vm.ip]
	regIndex := uint(bits.RotateLeft64(inst, FULL_REG_ROTATION) & FULL_REG_MASK)

	return regIndex
}
<commit_msg>Renamed the consts to be package private.<commit_after>/*
The MIT License (MIT)

Copyright (c) 2016-2018 Ivan Dejanovic

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOopLdERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF opConTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN opConNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

package vm

import (
	"fmt"
	"github.com/ivandejanovic/tpm/common"
	"math"
	"math/bits"
)

// Bit Masks
const (
	instMask    uint64 = 0xFF
	regMask     uint64 = 0xF
	fullRegMask uint64 = 0x1F
)

//Rotation values
const (
	instRotation       int = 8
	operandOneRotation int = 12
	operandTwoRotation int = 15
	fullRegRotation    int = 13
)

//Register index
const (
	ipIndex  uint = 8
	spIndex  uint = 9
	accIndex uint = 10
)

// Opcodes
const (
	opHalt uint = 0x00
	opInN  uint = 0x01
	opOutN uint = 0x02
	opInS  uint = 0x03
	opOutS uint = 0x04
	opAdd  uint = 0x05
	opSub  uint = 0x06
	opMul  uint = 0x07
	opDiv  uint = 0x08
	opCon  uint = 0x09
	opPush uint = 0x0A
	opPop  uint = 0x0B
	opLd   uint = 0x0C
	opSt   uint = 0x0D
	opJmp  uint = 0x0E
	opJgr  uint = 0x0F
	opJge  uint = 0x10
	opJeq  uint = 0x11
	opJne  uint = 0x12
	opJle  uint = 0x13
	opJls  uint = 0x14
)

const (
	regNum         uint   = 8
	memCap         uint64 = 50000
	varMemTop      uint64 = 50000
	varMemBottom   uint64 = 40001
	stackMemTop    uint64 = 40000
	stackMemBottom uint64 = 30001
)

type vm struct {
	ip  uint64
	sp  uint64
	acc uint64
	reg [regNum]uint64
	mem [memCap]uint64
}

func Execute(code []string) {
	vm := &vm{ip: 0, sp: 0, acc: 0}

	vm.load(code)
	vm.execute()
}

func (vm *vm) load(code []string) {
	//Create and initialize op codes map
	opCodes := make(map[uint]string)

	opCodes[opHalt] = common.HALT
	opCodes[opInN] = common.IN_N
	opCodes[opOutN] = common.OUT_N
	opCodes[opInS] = common.IN_S
	opCodes[opOutS] = common.OUT_S
	opCodes[opAdd] = common.ADD
	opCodes[opSub] = common.SUB
	opCodes[opMul] = common.MUL
	opCodes[opDiv] = common.DIV
	opCodes[opCon] = common.CON
	opCodes[opPush] = common.PUSH
	opCodes[opPop] = common.POP
	opCodes[opLd] = common.LD
	opCodes[opSt] = common.ST
	opCodes[opJmp] = common.JMP
	opCodes[opJgr] = common.JGR
	opCodes[opJge] = common.JGE
	opCodes[opJeq] = common.JEQ
	opCodes[opJne] = common.JNE
	opCodes[opJle] = common.JLE
	opCodes[opJls] = common.JLS

	for _, inst := range code {
		fmt.Println(inst)
	}
}

func (vm *vm) execute() {
	for {
		inst := vm.mem[vm.ip]
		opcode := uint(bits.RotateLeft64(inst, instRotation) & instMask)

		switch opcode {
		case opHalt:
			break
		case opInN:
			vm.processInN()
		case opOutN:
			vm.processOutN()
		case opInS:
			vm.processInS()
		case opOutS:
			vm.processOutS()
		case opAdd:
			vm.processAdd()
		case opSub:
			vm.processSub()
		case opMul:
			vm.processMul()
		case opDiv:
			vm.processDiv()
		case opCon:
			vm.processCon()
		case opPush:
			vm.processPush()
		case opPop:
			vm.processPop()
		case opLd:
			vm.processLd()
		case opSt:
			vm.processSt()
		case opJmp:
			vm.processJmp()
		case opJgr:
			vm.processJgr()
		case opJge:
			vm.processJge()
		case opJeq:
			vm.processJeq()
		case opJne:
			vm.processJne()
		case opJle:
			vm.processJle()
		case opJls:
			vm.processJls()
		default:
			fmt.Println("Unknow instruction. Aborting.")
			break
		}

		if vm.hasErrors() {
			vm.throwException()
			break
		}
	}
}

func (vm *vm) processInN() {
	var input float64 = 0.0
	_, err := fmt.Scanf("%f", &input)
	if err != nil {
		fmt.Println("")
		vm.setIOErrorFlag()
		return
	}
	vm.acc = math.Float64bits(input)
	vm.ip = vm.ip + 1
}

func (vm *vm) processOutN() {
	output := math.Float64frombits(vm.acc)
	fmt.Println(output)
	vm.ip = vm.ip + 1
}

func (vm *vm) processInS() {

}

func (vm *vm) processOutS() {

}

func (vm *vm) processAdd() {
	operand1 := vm.getOperand(operandOneRotation)
	operand2 := vm.getOperand(operandTwoRotation)
	result := operand1 + operand2
	vm.acc = math.Float64bits(result)
	vm.ip = vm.ip + 1
}

func (vm *vm) processSub() {
	operand1 := vm.getOperand(operandOneRotation)
	operand2 := vm.getOperand(operandTwoRotation)
	result := operand1 - operand2
	vm.acc = math.Float64bits(result)
	vm.ip = vm.ip + 1
}

func (vm *vm) processMul() {
	operand1 := vm.getOperand(operandOneRotation)
	operand2 := vm.getOperand(operandTwoRotation)
	result := operand1 * operand2
	vm.acc = math.Float64bits(result)
	vm.ip = vm.ip + 1
}

func (vm *vm) processDiv() {
	operand1 := vm.getOperand(operandOneRotation)
	operand2 := vm.getOperand(operandTwoRotation)
	result := operand1 / operand2
	vm.acc = math.Float64bits(result)
	vm.ip = vm.ip + 1
}

func (vm *vm) processCon() {

}

func (vm *vm) processPush() {
	//Check if stack is full
	if vm.sp <= stackMemBottom {
		vm.setMemErrorFlags("Push attempt on full stack.")
		return
	}

	regIndex := vm.getRegisterIndex()
	var value uint64 = 0

	if regIndex < regNum {
		value = vm.reg[regIndex]
	} else if regIndex == ipIndex {
		value = uint64(vm.ip)

	} else if regIndex == spIndex {
		value = uint64(vm.sp)
	} else if regIndex == accIndex {
		value = vm.acc
	} else {
		vm.setMemErrorFlags("Push attempt on unkown register.")
		return
	}

	vm.mem[vm.sp] = value
	vm.sp = vm.sp - 1
}

func (vm *vm) processPop() {
	//Check if stack is empty
	if vm.sp > stackMemTop {
		vm.setMemErrorFlags("Pop attempt on empty stack.")
		return
	}

	regIndex := vm.getRegisterIndex()
	value := vm.mem[vm.sp]
	vm.sp = vm.sp + 1

	if regIndex < regNum {
		vm.reg[regIndex] = value
	} else if regIndex == ipIndex {
		vm.ip = value
	} else if regIndex == spIndex {
		vm.sp = value
	} else if regIndex == accIndex {
		vm.acc = value
	} else {
		vm.setMemErrorFlags("Pop attempt on unkown register.")
		return
	}
}

func (vm *vm) processLd() {
	//regIndex := vm.getRegisterIndex()
}

func (vm *vm) processSt() {
	//regIndex := vm.getRegisterIndex()
}

func (vm *vm) processJmp() {

}

func (vm *vm) processJgr() {

}

func (vm *vm) processJge() {

}

func (vm *vm) processJeq() {

}

func (vm *vm) processJne() {

}

func (vm *vm) processJle() {

}

func (vm *vm) processJls() {

}

func (vm *vm) setIOErrorFlag() {
	fmt.Println("IO error flag set!")
}

func (vm *vm) setMemErrorFlags(err string) {
	fmt.Println(err)
}

func (vm *vm) hasErrors() bool {
	return false
}

func (vm *vm) throwException() {
	fmt.Println("Exception thrown!")
}

func (vm *vm) getOperand(rotation int) float64 {
	inst := vm.mem[vm.ip]
	operandReg := bits.RotateLeft64(inst, rotation) & regMask
	operand := math.Float64frombits(operandReg)

	return operand
}

func (vm *vm) getRegisterIndex() uint {
	inst := vm.mem[vm.ip]
	regIndex := uint(bits.RotateLeft64(inst, fullRegRotation) & fullRegMask)

	return regIndex
}
<|endoftext|>