<commit_before>// Basic data structures for Go.
package main

import (
	"errors"
	"fmt"
	"math/rand"
	// "time"
)

// Letters for quick lookup.
// These are the letters marked on top of the board.  "I" is
// always left out, likely to avoid confusion with "1".
const BoardLetters = "ABCDEFGHJKLMNOPQRST"
const ActionChars = "cbw"

// Here it would be nice if the type system allows us to say
// "integer with one of these value: 0, 1, 2.
type Color int

const (
	// Stone colors. Used for board state.
	Empty = 0 // No stone here.
	Black = 1
	White = 2

	// Moves. These correspond to board state making it easy to
	// translate between the two. (A capture will clear that point on
	// the board.)
	Capture    = 0
	PlaceBlack = 1
	PlaceWhite = 2
)

// Point where a stone can be placed.
type Point struct {
	X int // Left to right, 0-18 (marked as 1-19 on board.)
	Y int // Bottom to top, 0-18 (ABCDEFGHJKLMNOPQRST.)
}

type Size struct {
	Width  int
	Height int
}

// A move. (Place or capture stone.)
type Move struct {
	Point
	Color
}

func (move Move) String() string {
	return FormatMove(move)
}

func ParseMove(text string) (Move, error) {
	// letter := text[0]
	// number := text[1:len(text)-1]
	// color := text[len(text)-1]

	return Move{}, errors.New("Parser not written")
}

func FormatMove(move Move) string {
	// Todo: check if values are out of range?
	letter := BoardLetters[move.X]
	number := move.Y + 1
	stoneColor := ActionChars[move.Color]

	return fmt.Sprintf("%c%d%c", letter, number, stoneColor)
}

// The board is just a cache of moves. We can recompute the board from
// the moves.
type Game struct {
	Size
	Board map[Point]Color
	Moves []Move
	// Here we should have a stack (or slice) of boards so that we have
	// a history of previous board states.

	// + We need to keep score somehow. (Number of captured stones for
	// each player.)
}

func (game *Game) AddMove(move Move) {
	game.Moves = append(game.Moves, move)
	game.Board[move.Point] = move.Color
}

func (game *Game) AddMoves(moves []Move) {
	for _, move := range moves {
		game.AddMove(move)
	}
}

func (game *Game) PrintBoard() {
	colorChars := ".bw"

	fmt.Print("   ")
	for x := 0; x < game.Width; x++ {
		fmt.Printf(" %c", BoardLetters[x])
	}
	fmt.Println()

	for y := game.Height - 1; y >= 0; y-- {
		line := ""
		for x := 0; x < game.Width; x++ {
			line += fmt.Sprintf(" %c", colorChars[game.Board[Point{x, y}]])
		}
		fmt.Printf(" %2d%s\n", y+1, line)
	}
}

func NewGame(boardSize Size) Game {
	return Game{
		Size:  boardSize,
		Board: make(map[Point]Color),
	}
}

// returns a list of random moves
// the moves are not guaranteed to be valid
// this function can place multiple stones on top of each other
// this is used for debugging detection of invalid moves
// and for implementing grouping and detection of dead groups
func (game *Game) generate_random_moves(num_moves int) []Move {
	// rand.Seed(time.Now().UnixNano())

	moves := []Move{}
	for i := 0; i < num_moves; i++ {
		randomColor := Color(rand.Intn(2) + 1) // either black or white stone
		randomX := rand.Intn(game.Width)
		randomY := rand.Intn(game.Height)
		moves = append(moves, Move{Point{randomX, randomY}, randomColor})
	}
	return moves
}

// finds up to four neighbors for a reference point (east, north, west, south)
// does not check whether the reference point is actually on the board
func (game *Game) findNeighbors(point Point) []Point {
	neighbors := []Point{}
	// east
	if point.X < game.Width-1 {
		neighbors = append(neighbors, Point{point.X + 1, point.Y})
	}
	// north
	if point.Y < game.Height-1 {
		neighbors = append(neighbors, Point{point.X, point.Y + 1})
	}
	// west
	if point.X > 0 {
		neighbors = append(neighbors, Point{point.X - 1, point.Y})
	}
	// south
	if point.Y > 0 {
		neighbors = append(neighbors, Point{point.X, point.Y - 1})
	}
	return neighbors
}

// a variation of the https://en.wikipedia.org/wiki/Flood_fill algorithm
func (game *Game) find_group(group []Point, point Point, color Color, liberties []Point, board_visited []bool) ([]Point, []Point, []bool) {

	if game.Board[point] == 0 {
		// this point is empty, therefore it is a liberty

		// figure out whether we already know about this liberty
		for _, l := range liberties {
			if l == point {
				// this liberty is already known
				// do not append it and return
				return group, liberties, board_visited
			}
		}
		// this is a new libery so we add it to known liberties
		liberties = append(liberties, point)
		return group, liberties, board_visited
	}

	if game.Board[point] != color {
		// this point has different color, return
		return group, liberties, board_visited
	} else {
		// we have the same color
		if board_visited[point.Y*game.Width+point.X] {
			// we have been here before so let us return
			return group, liberties, board_visited
		} else {
			// first time we are here
			board_visited[point.Y*game.Width+point.X] = true
		}
		// add the point to the group
		group = append(group, point)
		// then traverse all neighbors before returning
		for _, neighbor := range game.findNeighbors(point) {
			group, liberties, board_visited = game.find_group(group, neighbor, color, liberties, board_visited)
		}
		return group, liberties, board_visited
	}
}

func (game *Game) findDeadGroups() {

	board_visited := make([]bool, game.Width*game.Height)

	// for debugging
	board_num_liberties := make([]int, game.Width*game.Height)

	group := []Point{}
	for y := 0; y < game.Height; y++ {
		for x := 0; x < game.Width; x++ {
			if game.Board[Point{x, y}] != 0 {
				if !board_visited[y*game.Width+x] {
					liberties := []Point{}
					group, liberties, board_visited = game.find_group(
						[]Point{},
						Point{x, y},
						game.Board[Point{x, y}],
						liberties,
						board_visited)
					for _, point := range group {
						board_num_liberties[point.Y*game.Width+point.X] = len(liberties)
					}
				}
			}
		}
	}

	fmt.Println("\nLiberties of groups:\n")

	for y := game.Height - 1; y >= 0; y-- {
		fmt.Print("   ")
		for x := 0; x < game.Width; x++ {
			num_liberties := board_num_liberties[y*game.Width+x]
			if num_liberties == 0 {
				if game.Board[Point{x, y}] == Empty {
					fmt.Print(" .")
				} else {
					fmt.Print(" *")
				}
			} else {
				fmt.Printf("%2d", board_num_liberties[y*game.Width+x])
			}
		}
		fmt.Print("\n")
	}
}

func main() {
	game := NewGame(Size{9, 11})

	// moves := []Move{{PlaceBlack, Point{0, 0}}, {PlaceWhite, Point{1, 6}}}
	moves := game.generate_random_moves(135)

	fmt.Println()
	fmt.Println("Moves:", moves)
	fmt.Println()
	game.AddMoves(moves)
	game.PrintBoard()
	game.findDeadGroups()

	// fmt.Println(game.Board[Point{}])
	// fmt.Println(game.Board[Point{1, 1}])

	// fmt.Println(moves)
}
<commit_msg>don't think we need the movement consts<commit_after>// Basic data structures for Go.
package main

import (
	"errors"
	"fmt"
	"math/rand"
	// "time"
)

// Letters for quick lookup.
// These are the letters marked on top of the board.  "I" is
// always left out, likely to avoid confusion with "1".
const BoardLetters = "ABCDEFGHJKLMNOPQRST"
const ActionChars = "cbw"

// Here it would be nice if the type system allows us to say
// "integer with one of these value: 0, 1, 2.
type Color int

const (
	// Stone colors. Used for board state.
	Empty = 0 // No stone here.
	Black = 1
	White = 2
)

// Point where a stone can be placed.
type Point struct {
	X int // Left to right, 0-18 (marked as 1-19 on board.)
	Y int // Bottom to top, 0-18 (ABCDEFGHJKLMNOPQRST.)
}

type Size struct {
	Width  int
	Height int
}

// A move. (Place or capture stone.)
type Move struct {
	Point
	Color
}

func (move Move) String() string {
	return FormatMove(move)
}

func ParseMove(text string) (Move, error) {
	// letter := text[0]
	// number := text[1:len(text)-1]
	// color := text[len(text)-1]

	return Move{}, errors.New("Parser not written")
}

func FormatMove(move Move) string {
	// Todo: check if values are out of range?
	letter := BoardLetters[move.X]
	number := move.Y + 1
	stoneColor := ActionChars[move.Color]

	return fmt.Sprintf("%c%d%c", letter, number, stoneColor)
}

// The board is just a cache of moves. We can recompute the board from
// the moves.
type Game struct {
	Size
	Board map[Point]Color
	Moves []Move
	// Here we should have a stack (or slice) of boards so that we have
	// a history of previous board states.

	// + We need to keep score somehow. (Number of captured stones for
	// each player.)
}

func (game *Game) AddMove(move Move) {
	game.Moves = append(game.Moves, move)
	game.Board[move.Point] = move.Color
}

func (game *Game) AddMoves(moves []Move) {
	for _, move := range moves {
		game.AddMove(move)
	}
}

func (game *Game) PrintBoard() {
	colorChars := ".bw"

	fmt.Print("   ")
	for x := 0; x < game.Width; x++ {
		fmt.Printf(" %c", BoardLetters[x])
	}
	fmt.Println()

	for y := game.Height - 1; y >= 0; y-- {
		line := ""
		for x := 0; x < game.Width; x++ {
			line += fmt.Sprintf(" %c", colorChars[game.Board[Point{x, y}]])
		}
		fmt.Printf(" %2d%s\n", y+1, line)
	}
}

func NewGame(boardSize Size) Game {
	return Game{
		Size:  boardSize,
		Board: make(map[Point]Color),
	}
}

// returns a list of random moves
// the moves are not guaranteed to be valid
// this function can place multiple stones on top of each other
// this is used for debugging detection of invalid moves
// and for implementing grouping and detection of dead groups
func (game *Game) generate_random_moves(num_moves int) []Move {
	// rand.Seed(time.Now().UnixNano())

	moves := []Move{}
	for i := 0; i < num_moves; i++ {
		randomColor := Color(rand.Intn(2) + 1) // either black or white stone
		randomX := rand.Intn(game.Width)
		randomY := rand.Intn(game.Height)
		moves = append(moves, Move{Point{randomX, randomY}, randomColor})
	}
	return moves
}

// finds up to four neighbors for a reference point (east, north, west, south)
// does not check whether the reference point is actually on the board
func (game *Game) findNeighbors(point Point) []Point {
	neighbors := []Point{}
	// east
	if point.X < game.Width-1 {
		neighbors = append(neighbors, Point{point.X + 1, point.Y})
	}
	// north
	if point.Y < game.Height-1 {
		neighbors = append(neighbors, Point{point.X, point.Y + 1})
	}
	// west
	if point.X > 0 {
		neighbors = append(neighbors, Point{point.X - 1, point.Y})
	}
	// south
	if point.Y > 0 {
		neighbors = append(neighbors, Point{point.X, point.Y - 1})
	}
	return neighbors
}

// a variation of the https://en.wikipedia.org/wiki/Flood_fill algorithm
func (game *Game) find_group(group []Point, point Point, color Color, liberties []Point, board_visited []bool) ([]Point, []Point, []bool) {

	if game.Board[point] == 0 {
		// this point is empty, therefore it is a liberty

		// figure out whether we already know about this liberty
		for _, l := range liberties {
			if l == point {
				// this liberty is already known
				// do not append it and return
				return group, liberties, board_visited
			}
		}
		// this is a new libery so we add it to known liberties
		liberties = append(liberties, point)
		return group, liberties, board_visited
	}

	if game.Board[point] != color {
		// this point has different color, return
		return group, liberties, board_visited
	} else {
		// we have the same color
		if board_visited[point.Y*game.Width+point.X] {
			// we have been here before so let us return
			return group, liberties, board_visited
		} else {
			// first time we are here
			board_visited[point.Y*game.Width+point.X] = true
		}
		// add the point to the group
		group = append(group, point)
		// then traverse all neighbors before returning
		for _, neighbor := range game.findNeighbors(point) {
			group, liberties, board_visited = game.find_group(group, neighbor, color, liberties, board_visited)
		}
		return group, liberties, board_visited
	}
}

func (game *Game) findDeadGroups() {

	board_visited := make([]bool, game.Width*game.Height)

	// for debugging
	board_num_liberties := make([]int, game.Width*game.Height)

	group := []Point{}
	for y := 0; y < game.Height; y++ {
		for x := 0; x < game.Width; x++ {
			if game.Board[Point{x, y}] != 0 {
				if !board_visited[y*game.Width+x] {
					liberties := []Point{}
					group, liberties, board_visited = game.find_group(
						[]Point{},
						Point{x, y},
						game.Board[Point{x, y}],
						liberties,
						board_visited)
					for _, point := range group {
						board_num_liberties[point.Y*game.Width+point.X] = len(liberties)
					}
				}
			}
		}
	}

	fmt.Println("\nLiberties of groups:\n")

	for y := game.Height - 1; y >= 0; y-- {
		fmt.Print("   ")
		for x := 0; x < game.Width; x++ {
			num_liberties := board_num_liberties[y*game.Width+x]
			if num_liberties == 0 {
				if game.Board[Point{x, y}] == Empty {
					fmt.Print(" .")
				} else {
					fmt.Print(" *")
				}
			} else {
				fmt.Printf("%2d", board_num_liberties[y*game.Width+x])
			}
		}
		fmt.Print("\n")
	}
}

func main() {
	game := NewGame(Size{9, 11})

	moves := game.generate_random_moves(135)

	fmt.Println()
	fmt.Println("Moves:", moves)
	fmt.Println()
	game.AddMoves(moves)
	game.PrintBoard()
	game.findDeadGroups()

	// fmt.Println(game.Board[Point{}])
	// fmt.Println(game.Board[Point{1, 1}])

	// fmt.Println(moves)
}
<|endoftext|>


<commit_before>//+build !travis

package pir
<commit_msg>first attempt at shard_cuda<commit_after>//+build !travis

package pir

// ShardCUDA represents a read-only shard of the database,
// backed by a CUDA implementation of PIR
type ShardCUDA struct {
	log        *common.Logger
	name       string
	context    *ContextCUDA
	bucketSize int
	numBuckets int
	data       []byte
	numThreads int
	cudaData   cuda.DevicePtr
}

// NewShardCUDA creates a new CUDA-backed shard
// The data is represented as a flat byte array = append(bucket_1, bucket_2 ... bucket_n)
// Pre-conditions:
// - len(data) must be a multiple of bucketSize
// Returns: the shard, or an error if mismatched size
func NewShardCUDA(name string, context *ContextCUDA, bucketSize int, data []byte, numThreads int) (*ShardCUDA, error) {
	s := &ShardCUDA{}
	s.log = common.NewLogger(name)
	s.name = name
	s.context = context

	// GetNumBuckets will compute the number of buckets stored in the Shard
	// If len(s.data) is not cleanly divisible by s.bucketSize,
	// returns an error
	if len(data)%bucketSize != 0 {
		return nil, fmt.Errorf("NewShardCL(%v) failed: data(len=%v) not multiple of bucketSize=%v", name, len(data), bucketSize)
	}

	s.bucketSize = bucketSize
	s.numBuckets = (len(data) / bucketSize)
	s.data = data
	s.numThreads = numThreads

	/** CUDA **/
	//  Create buffers
	s.cudaData = cu.MemAlloc(len(data))
	cu.MemcpyHtoD(s.cudaData, unsafe.Pointer(&data[0]), len(data))

	return s, nil
}

/*********************************************
 * PUBLIC METHODS
 *********************************************/

// Free releases all OpenCL buffers
func (s *ShardCUDA) Free() error {
	cu.MemFree(s.cudaData)
	return nil
}

// GetName returns the name of the shard
func (s *ShardCUDA) GetName() string {
	return s.name
}

// GetBucketSize returns the size (in bytes) of a bucket
func (s *ShardCUDA) GetBucketSize() int {
	return s.bucketSize
}

// GetNumBuckets returns the number of buckets in the shard
func (s *ShardCUDA) GetNumBuckets() int {
	return s.numBuckets
}

// GetData returns a slice of the data
func (s *ShardCUDA) GetData() []byte {
	return s.data[:]
}

// Read handles a batch read, where each request is concatentated into `reqs`
//   each request consists of `reqLength` bytes
//   Note: every request starts on a byte boundary
// Returns: a single byte array where responses are concatenated by the order in `reqs`
//   each response consists of `s.bucketSize` bytes
func (s *ShardCUDA) Read(reqs []byte, reqLength int) ([]byte, error) {
	if len(reqs)%reqLength != 0 {
		return nil, fmt.Errorf("ShardCUDA.Read expects len(reqs)=%d to be a multiple of reqLength=%d", len(reqs), reqLength)
	}

	inputSize := len(reqs)
	batchSize := inputSize / reqLength
	outputSize := batchSize * s.bucketSize
	responses := make([]byte, outputSize)

	// Create buffers
	input := cu.MemAlloc(inputSize)
	defer cu.MemFree(input)
	output := cu.MemAlloc(outputSize)
	defer cu.MemFree(output)

	// Copy input to device
	cu.MemcpyHtoD(input, unsafe.Pointer(&reqs[0]), inputSize)

	//Set kernel args
	data := s.clData

	args := []unsafe.Pointer{
		unsafe.Pointer(&data),
	}

	/** START LOCK REGION **/
	s.context.KernelMutex.Lock()

	cu.LaunchKernel(args)
	cu.CtxSynchronize()

	s.context.KernelMutex.Unlock()
	/** END LOCK REGION **/

	// Read responses
	cu.MemcpyDtoH(unsafe.Pointer(&responses[0]), output, outputSize)

	return responses, nil
}

/*********************************************
 * PRIVATE METHODS
 *********************************************/
<|endoftext|>


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

// Tests for the behavior of os.File objects on plain old posix file systems,
// for use in verifying the intended behavior of memfs.

package memfs_test

import (
	"io"
	"io/ioutil"
	"os"
	"path"
	"testing"

	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/ogletest"
)

func TestPosix(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

func getFileOffset(f *os.File) (offset int64, err error) {
	const relativeToCurrent = 1
	offset, err = f.Seek(0, relativeToCurrent)
	return
}

////////////////////////////////////////////////////////////////////////
// Boilerplate
////////////////////////////////////////////////////////////////////////

type PosixTest struct {
	// A temporary directory.
	dir string

	// Files to close when tearing down. Nil entries are skipped.
	toClose []io.Closer
}

var _ SetUpInterface = &PosixTest{}
var _ TearDownInterface = &PosixTest{}

func init() { RegisterTestSuite(&PosixTest{}) }

func (t *PosixTest) SetUp(ti *TestInfo) {
	var err error

	// Create a temporary directory.
	t.dir, err = ioutil.TempDir("", "posix_test")
	if err != nil {
		panic(err)
	}
}

func (t *PosixTest) TearDown() {
	// Close any files we opened.
	for _, c := range t.toClose {
		if c == nil {
			continue
		}

		err := c.Close()
		if err != nil {
			panic(err)
		}
	}

	// Remove the temporary directory.
	err := os.RemoveAll(t.dir)
	if err != nil {
		panic(err)
	}
}

////////////////////////////////////////////////////////////////////////
// Test functions
////////////////////////////////////////////////////////////////////////

func (t *PosixTest) WriteOverlapsEndOfFile() {
	var err error
	var n int

	// Create a file.
	f, err := os.Create(path.Join(t.dir, "foo"))
	t.toClose = append(t.toClose, f)
	AssertEq(nil, err)

	// Make it 4 bytes long.
	err = f.Truncate(4)
	AssertEq(nil, err)

	// Write the range [2, 6).
	n, err = f.WriteAt([]byte("taco"), 2)
	AssertEq(nil, err)
	AssertEq(4, n)

	// Read the full contents of the file.
	contents, err := ioutil.ReadAll(f)
	AssertEq(nil, err)
	ExpectEq("\x00\x00taco", string(contents))
}

func (t *PosixTest) WriteStartsAtEndOfFile() {
	var err error
	var n int

	// Create a file.
	f, err := os.Create(path.Join(t.dir, "foo"))
	t.toClose = append(t.toClose, f)
	AssertEq(nil, err)

	// Make it 2 bytes long.
	err = f.Truncate(2)
	AssertEq(nil, err)

	// Write the range [2, 6).
	n, err = f.WriteAt([]byte("taco"), 2)
	AssertEq(nil, err)
	AssertEq(4, n)

	// Read the full contents of the file.
	contents, err := ioutil.ReadAll(f)
	AssertEq(nil, err)
	ExpectEq("\x00\x00taco", string(contents))
}

func (t *PosixTest) WriteStartsPastEndOfFile() {
	var err error
	var n int

	// Create a file.
	f, err := os.Create(path.Join(t.dir, "foo"))
	t.toClose = append(t.toClose, f)
	AssertEq(nil, err)

	// Write the range [2, 6).
	n, err = f.WriteAt([]byte("taco"), 2)
	AssertEq(nil, err)
	AssertEq(4, n)

	// Read the full contents of the file.
	contents, err := ioutil.ReadAll(f)
	AssertEq(nil, err)
	ExpectEq("\x00\x00taco", string(contents))
}

func (t *PosixTest) WriteAtDoesntChangeOffset_NotAppendMode() {
	var err error
	var n int

	// Create a file.
	f, err := os.Create(path.Join(t.dir, "foo"))
	t.toClose = append(t.toClose, f)
	AssertEq(nil, err)

	// Make it 16 bytes long.
	err = f.Truncate(16)
	AssertEq(nil, err)

	// Seek to offset 4.
	_, err = f.Seek(4, 0)
	AssertEq(nil, err)

	// Write the range [10, 14).
	n, err = f.WriteAt([]byte("taco"), 2)
	AssertEq(nil, err)
	AssertEq(4, n)

	// We should still be at offset 4.
	offset, err := getFileOffset(f)
	AssertEq(nil, err)
	ExpectEq(4, offset)
}

func (t *PosixTest) WriteAtDoesntChangeOffset_AppendMode() {
	var err error
	var n int

	// Create a file in append mode.
	f, err := os.OpenFile(
		path.Join(t.dir, "foo"),
		os.O_RDWR|os.O_APPEND|os.O_CREATE,
		0600)

	t.toClose = append(t.toClose, f)
	AssertEq(nil, err)

	// Make it 16 bytes long.
	err = f.Truncate(16)
	AssertEq(nil, err)

	// Seek to offset 4.
	_, err = f.Seek(4, 0)
	AssertEq(nil, err)

	// Write the range [10, 14).
	n, err = f.WriteAt([]byte("taco"), 2)
	AssertEq(nil, err)
	AssertEq(4, n)

	// We should still be at offset 4.
	offset, err := getFileOffset(f)
	AssertEq(nil, err)
	ExpectEq(4, offset)
}

func (t *PosixTest) AppendMode() {
	var err error
	var n int
	var off int64
	buf := make([]byte, 1024)

	// Create a file with some contents.
	fileName := path.Join(t.dir, "foo")
	err = ioutil.WriteFile(fileName, []byte("Jello, "), 0600)
	AssertEq(nil, err)

	// Open the file in append mode.
	f, err := os.OpenFile(fileName, os.O_RDWR|os.O_APPEND, 0600)
	t.toClose = append(t.toClose, f)
	AssertEq(nil, err)

	// Seek to somewhere silly and then write.
	off, err = f.Seek(2, 0)
	AssertEq(nil, err)
	AssertEq(2, off)

	n, err = f.Write([]byte("world!"))
	AssertEq(nil, err)
	AssertEq(6, n)

	// The offset should have been updated to point at the end of the file.
	off, err = getFileOffset(f)
	AssertEq(nil, err)
	ExpectEq(13, off)

	// A random write should still work, without updating the offset.
	n, err = f.WriteAt([]byte("H"), 0)
	AssertEq(nil, err)
	AssertEq(1, n)

	off, err = getFileOffset(f)
	AssertEq(nil, err)
	ExpectEq(13, off)

	// Read back the contents of the file, which should be correct even though we
	// seeked to a silly place before writing the world part.
	//
	// Linux's support for pwrite is buggy; the pwrite(2) man page says this:
	//
	//     POSIX requires that opening a file with the O_APPEND flag should have
	//     no affect on the location at which pwrite() writes data.  However, on
	//     Linux,  if  a  file  is opened with O_APPEND, pwrite() appends data to
	//     the end of the file, regardless of the value of offset.
	//
	// So we allow either the POSIX result or the Linux result.
	n, err = f.ReadAt(buf, 0)
	AssertEq(io.EOF, err)
	ExpectThat(string(buf[:n]), AnyOf("Hello, world!", "Jello, world!H"))
}

func (t *PosixTest) ReadsPastEndOfFile() {
	var err error
	var n int
	buf := make([]byte, 1024)

	// Create a file.
	f, err := os.Create(path.Join(t.dir, "foo"))
	t.toClose = append(t.toClose, f)
	AssertEq(nil, err)

	// Give it some contents.
	n, err = f.Write([]byte("taco"))
	AssertEq(nil, err)
	AssertEq(4, n)

	// Read a range overlapping EOF.
	n, err = f.ReadAt(buf[:4], 2)
	AssertEq(io.EOF, err)
	ExpectEq(2, n)
	ExpectEq("co", string(buf[:n]))

	// Read a range starting at EOF.
	n, err = f.ReadAt(buf[:4], 4)
	AssertEq(io.EOF, err)
	ExpectEq(0, n)
	ExpectEq("", string(buf[:n]))

	// Read a range starting past EOF.
	n, err = f.ReadAt(buf[:4], 100)
	AssertEq(io.EOF, err)
	ExpectEq(0, n)
	ExpectEq("", string(buf[:n]))
}

func (t *PosixTest) HardLinkDirectory() {
	dirName := path.Join(t.dir, "dir")

	// Create a directory.
	err := os.Mkdir(dirName, 0700)
	AssertEq(nil, err)

	// Attempt to hard-link it to a new name.
	err = os.Link(dirName, path.Join(t.dir, "other"))

	AssertNe(nil, err)
	ExpectThat(err, Error(HasSubstr("link")))
	ExpectThat(err, Error(HasSubstr("not permitted")))
}

func (t *PosixTest) RmdirWhileOpenedForReading() {
	var err error

	// Create a directory.
	err = os.Mkdir(path.Join(t.dir, "dir"), 0700)
	AssertEq(nil, err)

	// Open the directory for reading.
	f, err := os.Open(path.Join(t.dir, "dir"))
	defer func() {
		if f != nil {
			ExpectEq(nil, f.Close())
		}
	}()

	AssertEq(nil, err)

	// Remove the directory.
	err = os.Remove(path.Join(t.dir, "dir"))
	AssertEq(nil, err)

	// Create a new directory, with the same name even, and add some contents
	// within it.
	err = os.MkdirAll(path.Join(t.dir, "dir/foo"), 0700)
	AssertEq(nil, err)

	err = os.MkdirAll(path.Join(t.dir, "dir/bar"), 0700)
	AssertEq(nil, err)

	err = os.MkdirAll(path.Join(t.dir, "dir/baz"), 0700)
	AssertEq(nil, err)

	// We should still be able to stat the open file handle.
	fi, err := f.Stat()
	ExpectEq("dir", fi.Name())

	// Attempt to read from the directory. This shouldn't see any junk from the
	// new directory. It should either succeed with an empty result or should
	// return ENOENT.
	entries, err := f.Readdir(0)

	if err != nil {
		ExpectThat(err, Error(HasSubstr("no such file")))
	} else {
		ExpectThat(entries, ElementsAre())
	}
}
<commit_msg>Better nailed down posix and Linux append mode pwrite semantics.<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Tests for the behavior of os.File objects on plain old posix file systems,
// for use in verifying the intended behavior of memfs.

package memfs_test

import (
	"io"
	"io/ioutil"
	"os"
	"path"
	"runtime"
	"testing"

	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/ogletest"
)

func TestPosix(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

func getFileOffset(f *os.File) (offset int64, err error) {
	const relativeToCurrent = 1
	offset, err = f.Seek(0, relativeToCurrent)
	return
}

////////////////////////////////////////////////////////////////////////
// Boilerplate
////////////////////////////////////////////////////////////////////////

type PosixTest struct {
	// A temporary directory.
	dir string

	// Files to close when tearing down. Nil entries are skipped.
	toClose []io.Closer
}

var _ SetUpInterface = &PosixTest{}
var _ TearDownInterface = &PosixTest{}

func init() { RegisterTestSuite(&PosixTest{}) }

func (t *PosixTest) SetUp(ti *TestInfo) {
	var err error

	// Create a temporary directory.
	t.dir, err = ioutil.TempDir("", "posix_test")
	if err != nil {
		panic(err)
	}
}

func (t *PosixTest) TearDown() {
	// Close any files we opened.
	for _, c := range t.toClose {
		if c == nil {
			continue
		}

		err := c.Close()
		if err != nil {
			panic(err)
		}
	}

	// Remove the temporary directory.
	err := os.RemoveAll(t.dir)
	if err != nil {
		panic(err)
	}
}

////////////////////////////////////////////////////////////////////////
// Test functions
////////////////////////////////////////////////////////////////////////

func (t *PosixTest) WriteOverlapsEndOfFile() {
	var err error
	var n int

	// Create a file.
	f, err := os.Create(path.Join(t.dir, "foo"))
	t.toClose = append(t.toClose, f)
	AssertEq(nil, err)

	// Make it 4 bytes long.
	err = f.Truncate(4)
	AssertEq(nil, err)

	// Write the range [2, 6).
	n, err = f.WriteAt([]byte("taco"), 2)
	AssertEq(nil, err)
	AssertEq(4, n)

	// Read the full contents of the file.
	contents, err := ioutil.ReadAll(f)
	AssertEq(nil, err)
	ExpectEq("\x00\x00taco", string(contents))
}

func (t *PosixTest) WriteStartsAtEndOfFile() {
	var err error
	var n int

	// Create a file.
	f, err := os.Create(path.Join(t.dir, "foo"))
	t.toClose = append(t.toClose, f)
	AssertEq(nil, err)

	// Make it 2 bytes long.
	err = f.Truncate(2)
	AssertEq(nil, err)

	// Write the range [2, 6).
	n, err = f.WriteAt([]byte("taco"), 2)
	AssertEq(nil, err)
	AssertEq(4, n)

	// Read the full contents of the file.
	contents, err := ioutil.ReadAll(f)
	AssertEq(nil, err)
	ExpectEq("\x00\x00taco", string(contents))
}

func (t *PosixTest) WriteStartsPastEndOfFile() {
	var err error
	var n int

	// Create a file.
	f, err := os.Create(path.Join(t.dir, "foo"))
	t.toClose = append(t.toClose, f)
	AssertEq(nil, err)

	// Write the range [2, 6).
	n, err = f.WriteAt([]byte("taco"), 2)
	AssertEq(nil, err)
	AssertEq(4, n)

	// Read the full contents of the file.
	contents, err := ioutil.ReadAll(f)
	AssertEq(nil, err)
	ExpectEq("\x00\x00taco", string(contents))
}

func (t *PosixTest) WriteStartsPastEndOfFile_AppendMode() {
	var err error
	var n int

	// Create a file.
	f, err := os.OpenFile(
		path.Join(t.dir, "foo"),
		os.O_RDWR|os.O_APPEND|os.O_CREATE,
		0600)

	t.toClose = append(t.toClose, f)
	AssertEq(nil, err)

	// Write three bytes.
	n, err = f.Write([]byte("111"))
	AssertEq(nil, err)
	AssertEq(3, n)

	// Write at offset six.
	n, err = f.WriteAt([]byte("222"), 6)
	AssertEq(nil, err)
	AssertEq(3, n)

	// Read the full contents of the file.
	//
	// Linux's support for pwrite is buggy; the pwrite(2) man page says this:
	//
	//     POSIX requires that opening a file with the O_APPEND flag should have
	//     no affect on the location at which pwrite() writes data.  However, on
	//     Linux,  if  a  file  is opened with O_APPEND, pwrite() appends data to
	//     the end of the file, regardless of the value of offset.
	//
	contents, err := ioutil.ReadFile(f.Name())
	AssertEq(nil, err)

	if runtime.GOOS == "linux" {
		ExpectEq("111222", string(contents))
	} else {
		ExpectEq("111\x00\x00\x00222", string(contents))
	}
}

func (t *PosixTest) WriteAtDoesntChangeOffset_NotAppendMode() {
	var err error
	var n int

	// Create a file.
	f, err := os.Create(path.Join(t.dir, "foo"))
	t.toClose = append(t.toClose, f)
	AssertEq(nil, err)

	// Make it 16 bytes long.
	err = f.Truncate(16)
	AssertEq(nil, err)

	// Seek to offset 4.
	_, err = f.Seek(4, 0)
	AssertEq(nil, err)

	// Write the range [10, 14).
	n, err = f.WriteAt([]byte("taco"), 2)
	AssertEq(nil, err)
	AssertEq(4, n)

	// We should still be at offset 4.
	offset, err := getFileOffset(f)
	AssertEq(nil, err)
	ExpectEq(4, offset)
}

func (t *PosixTest) WriteAtDoesntChangeOffset_AppendMode() {
	var err error
	var n int

	// Create a file in append mode.
	f, err := os.OpenFile(
		path.Join(t.dir, "foo"),
		os.O_RDWR|os.O_APPEND|os.O_CREATE,
		0600)

	t.toClose = append(t.toClose, f)
	AssertEq(nil, err)

	// Make it 16 bytes long.
	err = f.Truncate(16)
	AssertEq(nil, err)

	// Seek to offset 4.
	_, err = f.Seek(4, 0)
	AssertEq(nil, err)

	// Write the range [10, 14).
	n, err = f.WriteAt([]byte("taco"), 2)
	AssertEq(nil, err)
	AssertEq(4, n)

	// We should still be at offset 4.
	offset, err := getFileOffset(f)
	AssertEq(nil, err)
	ExpectEq(4, offset)
}

func (t *PosixTest) AppendMode() {
	var err error
	var n int
	var off int64
	buf := make([]byte, 1024)

	// Create a file with some contents.
	fileName := path.Join(t.dir, "foo")
	err = ioutil.WriteFile(fileName, []byte("Jello, "), 0600)
	AssertEq(nil, err)

	// Open the file in append mode.
	f, err := os.OpenFile(fileName, os.O_RDWR|os.O_APPEND, 0600)
	t.toClose = append(t.toClose, f)
	AssertEq(nil, err)

	// Seek to somewhere silly and then write.
	off, err = f.Seek(2, 0)
	AssertEq(nil, err)
	AssertEq(2, off)

	n, err = f.Write([]byte("world!"))
	AssertEq(nil, err)
	AssertEq(6, n)

	// The offset should have been updated to point at the end of the file.
	off, err = getFileOffset(f)
	AssertEq(nil, err)
	ExpectEq(13, off)

	// A random write should still work, without updating the offset.
	n, err = f.WriteAt([]byte("H"), 0)
	AssertEq(nil, err)
	AssertEq(1, n)

	off, err = getFileOffset(f)
	AssertEq(nil, err)
	ExpectEq(13, off)

	// Read back the contents of the file, which should be correct even though we
	// seeked to a silly place before writing the world part.
	//
	// Linux's support for pwrite is buggy; the pwrite(2) man page says this:
	//
	//     POSIX requires that opening a file with the O_APPEND flag should have
	//     no affect on the location at which pwrite() writes data.  However, on
	//     Linux,  if  a  file  is opened with O_APPEND, pwrite() appends data to
	//     the end of the file, regardless of the value of offset.
	//
	// So we allow either the POSIX result or the Linux result.
	n, err = f.ReadAt(buf, 0)
	AssertEq(io.EOF, err)

	if runtime.GOOS == "linux" {
		ExpectEq("Jello, world!H", string(buf[:n]))
	} else {
		ExpectEq("Hello, world!", string(buf[:n]))
	}
}

func (t *PosixTest) ReadsPastEndOfFile() {
	var err error
	var n int
	buf := make([]byte, 1024)

	// Create a file.
	f, err := os.Create(path.Join(t.dir, "foo"))
	t.toClose = append(t.toClose, f)
	AssertEq(nil, err)

	// Give it some contents.
	n, err = f.Write([]byte("taco"))
	AssertEq(nil, err)
	AssertEq(4, n)

	// Read a range overlapping EOF.
	n, err = f.ReadAt(buf[:4], 2)
	AssertEq(io.EOF, err)
	ExpectEq(2, n)
	ExpectEq("co", string(buf[:n]))

	// Read a range starting at EOF.
	n, err = f.ReadAt(buf[:4], 4)
	AssertEq(io.EOF, err)
	ExpectEq(0, n)
	ExpectEq("", string(buf[:n]))

	// Read a range starting past EOF.
	n, err = f.ReadAt(buf[:4], 100)
	AssertEq(io.EOF, err)
	ExpectEq(0, n)
	ExpectEq("", string(buf[:n]))
}

func (t *PosixTest) HardLinkDirectory() {
	dirName := path.Join(t.dir, "dir")

	// Create a directory.
	err := os.Mkdir(dirName, 0700)
	AssertEq(nil, err)

	// Attempt to hard-link it to a new name.
	err = os.Link(dirName, path.Join(t.dir, "other"))

	AssertNe(nil, err)
	ExpectThat(err, Error(HasSubstr("link")))
	ExpectThat(err, Error(HasSubstr("not permitted")))
}

func (t *PosixTest) RmdirWhileOpenedForReading() {
	var err error

	// Create a directory.
	err = os.Mkdir(path.Join(t.dir, "dir"), 0700)
	AssertEq(nil, err)

	// Open the directory for reading.
	f, err := os.Open(path.Join(t.dir, "dir"))
	defer func() {
		if f != nil {
			ExpectEq(nil, f.Close())
		}
	}()

	AssertEq(nil, err)

	// Remove the directory.
	err = os.Remove(path.Join(t.dir, "dir"))
	AssertEq(nil, err)

	// Create a new directory, with the same name even, and add some contents
	// within it.
	err = os.MkdirAll(path.Join(t.dir, "dir/foo"), 0700)
	AssertEq(nil, err)

	err = os.MkdirAll(path.Join(t.dir, "dir/bar"), 0700)
	AssertEq(nil, err)

	err = os.MkdirAll(path.Join(t.dir, "dir/baz"), 0700)
	AssertEq(nil, err)

	// We should still be able to stat the open file handle.
	fi, err := f.Stat()
	ExpectEq("dir", fi.Name())

	// Attempt to read from the directory. This shouldn't see any junk from the
	// new directory. It should either succeed with an empty result or should
	// return ENOENT.
	entries, err := f.Readdir(0)

	if err != nil {
		ExpectThat(err, Error(HasSubstr("no such file")))
	} else {
		ExpectThat(entries, ElementsAre())
	}
}
<|endoftext|>


<commit_before>package util

import (
	"bufio"
	"bytes"
	"compress/zlib"
	"io"
	"io/ioutil"
	"os"
)

// 完整发送所有封包
func WriteFull(writer io.Writer, buf []byte) error {

	total := len(buf)

	for pos := 0; pos < total; {

		n, err := writer.Write(buf[pos:])

		if err != nil {
			return err
		}

		pos += n
	}

	return nil

}

// 读取文本文件的所有行
func ReadFileLines(filename string, callback func(line string) bool) error {

	f, err := os.Open(filename)

	if err != nil {
		return err
	}

	defer f.Close()

	reader := bufio.NewScanner(f)

	reader.Split(bufio.ScanLines)
	for reader.Scan() {

		if !callback(reader.Text()) {
			break
		}
	}

	return nil
}

func CompressBytes(data []byte) ([]byte, error) {

	var buf bytes.Buffer

	writer := zlib.NewWriter(&buf)

	_, err := writer.Write(data)
	if err != nil {
		return nil, err
	}
	writer.Close()

	return buf.Bytes(), nil
}

func DecompressBytes(data []byte) ([]byte, error) {

	reader, err := zlib.NewReader(bytes.NewReader(data))
	if err != nil {
		return nil, err
	}

	defer reader.Close()

	return ioutil.ReadAll(reader)
}
<commit_msg>add 几个文件的函数<commit_after>package util

import (
	"bufio"
	"bytes"
	"compress/zlib"
	"io"
	"io/ioutil"
	"os"
)

// 完整发送所有封包
func WriteFull(writer io.Writer, buf []byte) error {

	total := len(buf)

	for pos := 0; pos < total; {

		n, err := writer.Write(buf[pos:])

		if err != nil {
			return err
		}

		pos += n
	}

	return nil

}

// 读取文本文件的所有行
func ReadFileLines(filename string, callback func(line string) bool) error {

	f, err := os.Open(filename)

	if err != nil {
		return err
	}

	defer f.Close()

	reader := bufio.NewScanner(f)

	reader.Split(bufio.ScanLines)
	for reader.Scan() {

		if !callback(reader.Text()) {
			break
		}
	}

	return nil
}

func FileExists(name string) bool {
	if _, err := os.Stat(name); err != nil {
		if os.IsNotExist(err) {
			return false
		}
	}
	return true
}

func FileSize(name string) int64 {
	if info, err := os.Stat(name); err == nil {
		return info.Size()
	}

	return 0
}

func CompressBytes(data []byte) ([]byte, error) {

	var buf bytes.Buffer

	writer := zlib.NewWriter(&buf)

	_, err := writer.Write(data)
	if err != nil {
		return nil, err
	}
	writer.Close()

	return buf.Bytes(), nil
}

func DecompressBytes(data []byte) ([]byte, error) {

	reader, err := zlib.NewReader(bytes.NewReader(data))
	if err != nil {
		return nil, err
	}

	defer reader.Close()

	return ioutil.ReadAll(reader)
}
<|endoftext|>


<commit_before>package util

import (
	"fmt"
	"github.com/balzaczyy/golucene/codec"
	"math"
)

const (
	PACKED_CODEC_NAME           = "PackedInts"
	PACKED_VERSION_START        = 0
	PACKED_VERSION_BYTE_ALIGNED = 1
	PACKED_VERSION_CURRENT      = PACKED_VERSION_BYTE_ALIGNED
)

func CheckVersion(version int32) {
	if version < PACKED_VERSION_START {
		panic(fmt.Sprintf("Version is too old, should be at least %v (got %v)", PACKED_VERSION_START, version))
	} else if version > PACKED_VERSION_CURRENT {
		panic(fmt.Sprintf("Version is too new, should be at most %v (got %v)", PACKED_VERSION_CURRENT, version))
	}
}

type PackedFormat int

const (
	PACKED              = 0
	PACKED_SINGLE_BLOCK = 1
)

func (f PackedFormat) ByteCount(packedIntsVersion, valueCount int32, bitsPerValue uint32) int64 {
	switch int(f) {
	case PACKED:
		if packedIntsVersion < PACKED_VERSION_BYTE_ALIGNED {
			return 8 * int64(math.Ceil(float64(valueCount)*float64(bitsPerValue)/64))
		}
		return int64(math.Ceil(float64(valueCount) * float64(bitsPerValue) / 8))
	}
	// assert bitsPerValue >= 0 && bitsPerValue <= 64
	// assume long-aligned
	return 8 * int64(f.longCount(packedIntsVersion, valueCount, bitsPerValue))
}

func (f PackedFormat) longCount(packedIntsVersion, valueCount int32, bitsPerValue uint32) int {
	switch int(f) {
	case PACKED_SINGLE_BLOCK:
		valuesPerBlock := 64 / bitsPerValue
		return int(math.Ceil(float64(valueCount) / float64(valuesPerBlock)))
	}
	// assert bitsPerValue >= 0 && bitsPerValue <= 64
	ans := f.ByteCount(packedIntsVersion, valueCount, bitsPerValue)
	// assert ans < 8 * math.MaxInt32()
	if ans%8 == 0 {
		return int(ans / 8)
	}
	return int(ans/8) + 1
}

type PackedIntsEncoder interface {
}

type PackedIntsDecoder interface {
	ByteValueCount() uint32
}

func GetPackedIntsEncoder(format PackedFormat, version int32, bitsPerValue uint32) PackedIntsEncoder {
	CheckVersion(version)
	return newBulkOperation(format, bitsPerValue)
}

func GetPackedIntsDecoder(format PackedFormat, version int32, bitsPerValue uint32) PackedIntsDecoder {
	CheckVersion(version)
	return newBulkOperation(format, bitsPerValue)
}

type PackedIntsReader interface {
	Get(index int32) int64
	Size() int32
}

type PackedIntsMutable interface {
	PackedIntsReader
}

func newPackedReaderNoHeader(in *DataInput, format PackedFormat, version, valueCount int32, bitsPerValue uint32) (r PackedIntsReader, err error) {
	CheckVersion(version)
	switch format {
	case PACKED_SINGLE_BLOCK:
		return newPacked64SingleBlockFromInput(in, valueCount, bitsPerValue)
	case PACKED:
		switch bitsPerValue {
		case 8:
			return newDirect8FromInput(version, in, valueCount)
		case 16:
			return newDirect16FromInput(version, in, valueCount)
		case 32:
			return newDirect32FromInput(version, in, valueCount)
		case 64:
			return newDirect64FromInput(version, in, valueCount)
		case 24:
			if valueCount <= PACKED8_THREE_BLOCKS_MAX_SIZE {
				return newPacked8ThreeBlocksFromInput(version, in, valueCount)
			}
		case 48:
			if valueCount <= PACKED16_THREE_BLOCKS_MAX_SIZE {
				return newPacked16ThreeBlocksFromInput(version, in, valueCount)
			}
		}
		return newPacked64FromInput(version, in, valueCount, bitsPerValue)
	default:
		panic(fmt.Sprintf("Unknown Writer foramt: %v", format))
	}
}

func asUint32(n int32, err error) (n2 uint32, err2 error) {
	return uint32(n), err
}

func newPackedReader(in *DataInput) (r PackedIntsReader, err error) {
	if version, err := codec.CheckHeader(in, PACKED_CODEC_NAME, PACKED_VERSION_START, PACKED_VERSION_CURRENT); err == nil {
		if bitsPerValue, err := asUint32(in.ReadVInt()); err == nil {
			// assert bitsPerValue > 0 && bitsPerValue <= 64
			if valueCount, err := in.ReadVInt(); err == nil {
				if id, err := in.ReadVInt(); err == nil {
					format := PackedFormat(id)
					return newPackedReaderNoHeader(in, format, version, valueCount, bitsPerValue)
				}
			}
		}
	}
	return
}

type PackedIntsReaderImpl struct {
	bitsPerValue uint32
	valueCount   int32
}

func newPackedIntsReaderImpl(valueCount int32, bitsPerValue uint32) PackedIntsReaderImpl {
	// assert bitsPerValue > 0 && bitsPerValue <= 64
	return PackedIntsReaderImpl{bitsPerValue, valueCount}
}

func (p PackedIntsReaderImpl) Size() int32 {
	return p.valueCount
}

type PackedIntsMutableImpl struct {
}

type Direct8 struct {
	PackedIntsReaderImpl
	values []byte
}

func newDirect8(valueCount int32) Direct8 {
	ans := Direct8{values: make([]byte, valueCount)}
	ans.PackedIntsReaderImpl = newPakedIntsReaderImpl(valueCount, 8)
	return ans
}

func newDirect8FromInput(version int32, in *DataInput, valueCount int32) (r PackedIntsReader, err error) {
	r = newDirect8(valueCount)
	if err = in.ReadBytes(values[0:valueCount]); err == nil {
		// because packed ints have not always been byte-aligned
		remaining = PACKED.ByteCount(version, valueCount, 8) - valueCount
		for i := 0; i < remaining; i++ {
			if _, err = in.ReadByte(); err != nil {
				break
			}
		}
	}
	return r, err
}

type Direct16 struct {
	PackedIntsReaderImpl
	values []int16
}

func newDirect16(valueCount int32) Direct16 {
	ans := Direct16{values: make([]int16, valueCount)}
	ans.PackedIntsReaderImpl = newPackedIntsReaderImpl(valueCount, 16)
	return ans
}

func newDirect16FromInput(version int32, in *DataInput, valueCount int32) (r PackedIntsReader, err error) {
	r = newDirect16(valueCount)
	for i, _ := range r.values {
		if r.values[i], err = in.ReadShort(); err != nil {
			break
		}
	}
	if err == nil {
		// because packed ints have not always been byte-aligned
		remaining = PACKED.ByteCount(version, valueCount, 16) - 2*valueCount
		for i := 0; i < remaining; i++ {
			if _, err = in.ReadByte(); err != nil {
				break
			}
		}
	}
	return r, err
}

type Direct32 struct {
	PackedIntsReaderImpl
	values []int32
}

func newDirect32(valueCount int32) Direct32 {
	ans := Direct32{values: make([]int32, valueCount)}
	ans.PackedIntsReaderImpl = newPackedIntsReaderImpl(valueCount, 32)
	return ans
}

func newDirect32FromInput(version int32, in *DataInput, valueCount int32) (r PackedIntsReader, err error) {
	r = newDirect32(valueCount)
	for i, _ := range r.values {
		if r.values[i], err = in.ReadInt(); err != nil {
			break
		}
	}
	if err == nil {
		// because packed ints have not always been byte-aligned
		remaining = PACKED.ByteCount(version, valueCount, 32) - 4*valueCount
		for i := 0; i < remaining; i++ {
			if _, err = in.ReadByte(); err != nil {
				break
			}
		}
	}
	return r, err
}

type Direct64 struct {
	PackedIntsReaderImpl
	values []int64
}

func newDirect64(valueCount int32) Direct32 {
	ans := Direct64{values: make([]int32, valueCount)}
	ans.PackedIntsReaderImpl = newPackedIntsReaderImpl(valueCount, 64)
	return ans
}

func newDirect64FromInput(version int32, in *DataInput, valueCount int32) (r PackedIntsReader, err error) {
	r = newDirect64(valueCount)
	for i, _ := range r.values {
		if r.values[i], err = in.ReadLong(); err != nil {
			break
		}
	}
	return r, err
}

var PACKED8_THREE_BLOCKS_MAX_SIZE = int32(math.MaxInt32 / 3)

type Packed8ThreeBlocks struct {
	PackedIntsReaderImpl
	blocks []byte
}

func newPacked8ThreeBlocks(valueCount int32) Packed8ThreeBlocks {
	if valueCount > PACKED8_THREE_BLOCKS_MAX_SIZE {
		panic("MAX_SIZE exceeded")
	}
	ans := Packed8ThreeBlocks{blocks: make([]byte, valueCount*3)}
	ans.PackedIntsReaderImpl = newPackedIntsReaderImpl(valueCount, 24)
	return ans
}

func newPacked8ThreeBlocksFromInput(version int32, in *DataInput, valueCount int32) (r PackedIntsReader, err error) {
	r = newPacked8ThreeBlocks(valueCount)
	if err = in.ReadBytes(r.blocks); err == nil {
		// because packed ints have not always been byte-aligned
		remaining = PACKED.ByteCount(version, valueCount, 24) - 3*valueCount
		for i := 0; i < remaining; i++ {
			if _, err = in.ReadByte(); err != nil {
				break
			}
		}
	}
	return r, err
}

func (r *Packed8ThreeBlocks) Get(index int32) int64 {
	o := index * 3
	return blocks[o]<<16 | blocks[o+1]<<8 | blocks[o+2]
}

var PACKED16_THREE_BLOCKS_MAX_SIZE = int32(math.MaxInt32 / 3)

type Packed16ThreeBlocks struct {
	PackedIntsReaderImpl
	blocks []int16
}

func newPacked16ThreeBlocks(valueCount int32) Packed16ThreeBlocks {
	if valueCount > PACKED16_THREE_BLOCKS_MAX_SIZE {
		panic("MAX_SIZE exceeded")
	}
	ans := Packed16ThreeBlocks{blocks: make([]int16, valueCount*3)}
	ans.PackedIntsReaderImpl = newPackedIntsReaderImpl(valueCount, 48)
	return ans
}

func newPacked16ThreeBlocksFromInput(version int32, in *DataInput, valueCount int32) (r PackedIntsReader, err error) {
	ans := newPacked16ThreeBlocks(valueCount)
	for i, _ := range ans.blocks {
		if ans.blocks[i], err = in.ReadShort(); err != nil {
			break
		}
	}
	if err == nil {
		// because packed ints have not always been byte-aligned
		remaining = PACKED.ByteCount(version, valueCount, 48) - 3*valueCount*2
		for i := 0; i < remaining; i++ {
			if _, err = in.ReadByte(); err != nil {
				break
			}
		}
	}
	return ans, err
}

const (
	PACKED64_BLOCK_SIZE = 64
)

type Packed64 struct {
	PackedIntsReaderImpl
	blocks            []int64
	maskRight         uint64
	bpvMinusBlockSIze int32
}

func newPacked64(valueCount int32, bitsPerValue uint32) Packed64 {
	longCount := PACKED.LongCount(PACKED_VERSION_CURRENT, valueCount, bitsPerValue)
	ans := Packed64{
		blocks:            make([]int64, longCount),
		maskRight:         uint64(^(int64(0))<<(PACKED64_BLOCK_SIZE-bitsPerValue)) >> (PACKED64_BLOCK_SIZE - bitsPerValue),
		bpvMinusBlockSize: bitsPerValue - PACKED64_BLOCK_SIZE}
	ans.PackedIntsReaderImpl = newPackedIntsReaderImpl(valueCount, bitsPerValue)
	return ans
}

func newPacked64FromInput(version int32, int *DataInput, valueCount int32, bitsPerValue uint32) (r PackedIntsReader, err error) {
	ans := newPacked64(valueCount, bitsPerValue)
	byteCount := PACKED.ByteCount(version, valueCount, bitsPerValue)
	longCount := PACKED.LongCount(PACKED_VERSION_CURRENT, valueCount, bitsPerValue)
	ans.blocks = make([]int64, longCount)
	// read as many longs as we can
	for i := 0; i < byteCount/8; i++ {
		if ans.blocks[i], err = in.ReadLong(); err != nil {
			break
		}
	}
	if err == nil {
		if remaining := byteCount % 8; remaining != 0 {
			// read the last bytes
			var lastLong int64
			for i := 0; i < remaining; i++ {
				b, err := in.ReadByte()
				if err != nil {
					break
				}
				lastLong |= int64(b) << (5 - i*8)
			}
			if err == nil {
				ans.blocks[len(ans.blocks)-1] = lastLong
			}
		}
	}
	return ans, err
}

type GrowableWriter struct {
	current PackedIntsMutable
}

func (w *GrowableWriter) Get(index int32) int64 {
	return w.current.Get(index)
}

func (w *GrowableWriter) Size() int32 {
	return w.current.Size()
}
<commit_msg>add missing methods<commit_after>package util

import (
	"fmt"
	"github.com/balzaczyy/golucene/codec"
	"math"
)

const (
	PACKED_CODEC_NAME           = "PackedInts"
	PACKED_VERSION_START        = 0
	PACKED_VERSION_BYTE_ALIGNED = 1
	PACKED_VERSION_CURRENT      = PACKED_VERSION_BYTE_ALIGNED
)

func CheckVersion(version int32) {
	if version < PACKED_VERSION_START {
		panic(fmt.Sprintf("Version is too old, should be at least %v (got %v)", PACKED_VERSION_START, version))
	} else if version > PACKED_VERSION_CURRENT {
		panic(fmt.Sprintf("Version is too new, should be at most %v (got %v)", PACKED_VERSION_CURRENT, version))
	}
}

type PackedFormat int

const (
	PACKED              = 0
	PACKED_SINGLE_BLOCK = 1
)

func (f PackedFormat) ByteCount(packedIntsVersion, valueCount int32, bitsPerValue uint32) int64 {
	switch int(f) {
	case PACKED:
		if packedIntsVersion < PACKED_VERSION_BYTE_ALIGNED {
			return 8 * int64(math.Ceil(float64(valueCount)*float64(bitsPerValue)/64))
		}
		return int64(math.Ceil(float64(valueCount) * float64(bitsPerValue) / 8))
	}
	// assert bitsPerValue >= 0 && bitsPerValue <= 64
	// assume long-aligned
	return 8 * int64(f.longCount(packedIntsVersion, valueCount, bitsPerValue))
}

func (f PackedFormat) longCount(packedIntsVersion, valueCount int32, bitsPerValue uint32) int {
	switch int(f) {
	case PACKED_SINGLE_BLOCK:
		valuesPerBlock := 64 / bitsPerValue
		return int(math.Ceil(float64(valueCount) / float64(valuesPerBlock)))
	}
	// assert bitsPerValue >= 0 && bitsPerValue <= 64
	ans := f.ByteCount(packedIntsVersion, valueCount, bitsPerValue)
	// assert ans < 8 * math.MaxInt32()
	if ans%8 == 0 {
		return int(ans / 8)
	}
	return int(ans/8) + 1
}

type PackedIntsEncoder interface {
}

type PackedIntsDecoder interface {
	ByteValueCount() uint32
}

func GetPackedIntsEncoder(format PackedFormat, version int32, bitsPerValue uint32) PackedIntsEncoder {
	CheckVersion(version)
	return newBulkOperation(format, bitsPerValue)
}

func GetPackedIntsDecoder(format PackedFormat, version int32, bitsPerValue uint32) PackedIntsDecoder {
	CheckVersion(version)
	return newBulkOperation(format, bitsPerValue)
}

type PackedIntsReader interface {
	Get(index int32) int64
	Size() int32
}

type PackedIntsMutable interface {
	PackedIntsReader
}

func newPackedReaderNoHeader(in *DataInput, format PackedFormat, version, valueCount int32, bitsPerValue uint32) (r PackedIntsReader, err error) {
	CheckVersion(version)
	switch format {
	case PACKED_SINGLE_BLOCK:
		return newPacked64SingleBlockFromInput(in, valueCount, bitsPerValue)
	case PACKED:
		switch bitsPerValue {
		case 8:
			return newDirect8FromInput(version, in, valueCount)
		case 16:
			return newDirect16FromInput(version, in, valueCount)
		case 32:
			return newDirect32FromInput(version, in, valueCount)
		case 64:
			return newDirect64FromInput(version, in, valueCount)
		case 24:
			if valueCount <= PACKED8_THREE_BLOCKS_MAX_SIZE {
				return newPacked8ThreeBlocksFromInput(version, in, valueCount)
			}
		case 48:
			if valueCount <= PACKED16_THREE_BLOCKS_MAX_SIZE {
				return newPacked16ThreeBlocksFromInput(version, in, valueCount)
			}
		}
		return newPacked64FromInput(version, in, valueCount, bitsPerValue)
	default:
		panic(fmt.Sprintf("Unknown Writer foramt: %v", format))
	}
}

func asUint32(n int32, err error) (n2 uint32, err2 error) {
	return uint32(n), err
}

func newPackedReader(in *DataInput) (r PackedIntsReader, err error) {
	if version, err := codec.CheckHeader(in, PACKED_CODEC_NAME, PACKED_VERSION_START, PACKED_VERSION_CURRENT); err == nil {
		if bitsPerValue, err := asUint32(in.ReadVInt()); err == nil {
			// assert bitsPerValue > 0 && bitsPerValue <= 64
			if valueCount, err := in.ReadVInt(); err == nil {
				if id, err := in.ReadVInt(); err == nil {
					format := PackedFormat(id)
					return newPackedReaderNoHeader(in, format, version, valueCount, bitsPerValue)
				}
			}
		}
	}
	return
}

type PackedIntsReaderImpl struct {
	bitsPerValue uint32
	valueCount   int32
}

func newPackedIntsReaderImpl(valueCount int32, bitsPerValue uint32) PackedIntsReaderImpl {
	// assert bitsPerValue > 0 && bitsPerValue <= 64
	return PackedIntsReaderImpl{bitsPerValue, valueCount}
}

func (p PackedIntsReaderImpl) Size() int32 {
	return p.valueCount
}

type PackedIntsMutableImpl struct {
}

type Direct8 struct {
	PackedIntsReaderImpl
	values []byte
}

func newDirect8(valueCount int32) Direct8 {
	ans := Direct8{values: make([]byte, valueCount)}
	ans.PackedIntsReaderImpl = newPackedIntsReaderImpl(valueCount, 8)
	return ans
}

func newDirect8FromInput(version int32, in *DataInput, valueCount int32) (r PackedIntsReader, err error) {
	ans := newDirect8(valueCount)
	if err = in.ReadBytes(ans.values[0:valueCount]); err == nil {
		// because packed ints have not always been byte-aligned
		remaining := PackedFormat(PACKED).ByteCount(version, valueCount, 8) - int64(valueCount)
		for i := int64(0); i < remaining; i++ {
			if _, err = in.ReadByte(); err != nil {
				break
			}
		}
	}
	return &ans, err
}

func (d *Direct8) Get(index int32) int64 {
	return int64(d.values[index])
}

type Direct16 struct {
	PackedIntsReaderImpl
	values []int16
}

func newDirect16(valueCount int32) Direct16 {
	ans := Direct16{values: make([]int16, valueCount)}
	ans.PackedIntsReaderImpl = newPackedIntsReaderImpl(valueCount, 16)
	return ans
}

func newDirect16FromInput(version int32, in *DataInput, valueCount int32) (r PackedIntsReader, err error) {
	ans := newDirect16(valueCount)
	for i, _ := range ans.values {
		if ans.values[i], err = in.ReadShort(); err != nil {
			break
		}
	}
	if err == nil {
		// because packed ints have not always been byte-aligned
		remaining := PackedFormat(PACKED).ByteCount(version, valueCount, 16) - 2*int64(valueCount)
		for i := int64(0); i < remaining; i++ {
			if _, err = in.ReadByte(); err != nil {
				break
			}
		}
	}
	return &ans, err
}

func (d *Direct16) Get(index int32) int64 {
	return int64(d.values[index])
}

type Direct32 struct {
	PackedIntsReaderImpl
	values []int32
}

func newDirect32(valueCount int32) Direct32 {
	ans := Direct32{values: make([]int32, valueCount)}
	ans.PackedIntsReaderImpl = newPackedIntsReaderImpl(valueCount, 32)
	return ans
}

func newDirect32FromInput(version int32, in *DataInput, valueCount int32) (r PackedIntsReader, err error) {
	ans := newDirect32(valueCount)
	for i, _ := range ans.values {
		if ans.values[i], err = in.ReadInt(); err != nil {
			break
		}
	}
	if err == nil {
		// because packed ints have not always been byte-aligned
		remaining := PackedFormat(PACKED).ByteCount(version, valueCount, 32) - 4*int64(valueCount)
		for i := int64(0); i < remaining; i++ {
			if _, err = in.ReadByte(); err != nil {
				break
			}
		}
	}
	return &ans, err
}

func (d *Direct32) Get(index int32) int64 {
	return int64(d.values[index])
}

type Direct64 struct {
	PackedIntsReaderImpl
	values []int64
}

func newDirect64(valueCount int32) Direct64 {
	ans := Direct64{values: make([]int64, valueCount)}
	ans.PackedIntsReaderImpl = newPackedIntsReaderImpl(valueCount, 64)
	return ans
}

func newDirect64FromInput(version int32, in *DataInput, valueCount int32) (r PackedIntsReader, err error) {
	ans := newDirect64(valueCount)
	for i, _ := range ans.values {
		if ans.values[i], err = in.ReadLong(); err != nil {
			break
		}
	}
	return &ans, err
}

func (d *Direct64) Get(index int32) int64 {
	return d.values[index]
}

var PACKED8_THREE_BLOCKS_MAX_SIZE = int32(math.MaxInt32 / 3)

type Packed8ThreeBlocks struct {
	PackedIntsReaderImpl
	blocks []byte
}

func newPacked8ThreeBlocks(valueCount int32) Packed8ThreeBlocks {
	if valueCount > PACKED8_THREE_BLOCKS_MAX_SIZE {
		panic("MAX_SIZE exceeded")
	}
	ans := Packed8ThreeBlocks{blocks: make([]byte, valueCount*3)}
	ans.PackedIntsReaderImpl = newPackedIntsReaderImpl(valueCount, 24)
	return ans
}

func newPacked8ThreeBlocksFromInput(version int32, in *DataInput, valueCount int32) (r PackedIntsReader, err error) {
	r = newPacked8ThreeBlocks(valueCount)
	if err = in.ReadBytes(r.blocks); err == nil {
		// because packed ints have not always been byte-aligned
		remaining = PACKED.ByteCount(version, valueCount, 24) - 3*valueCount
		for i := 0; i < remaining; i++ {
			if _, err = in.ReadByte(); err != nil {
				break
			}
		}
	}
	return r, err
}

func (r *Packed8ThreeBlocks) Get(index int32) int64 {
	o := index * 3
	return blocks[o]<<16 | blocks[o+1]<<8 | blocks[o+2]
}

var PACKED16_THREE_BLOCKS_MAX_SIZE = int32(math.MaxInt32 / 3)

type Packed16ThreeBlocks struct {
	PackedIntsReaderImpl
	blocks []int16
}

func newPacked16ThreeBlocks(valueCount int32) Packed16ThreeBlocks {
	if valueCount > PACKED16_THREE_BLOCKS_MAX_SIZE {
		panic("MAX_SIZE exceeded")
	}
	ans := Packed16ThreeBlocks{blocks: make([]int16, valueCount*3)}
	ans.PackedIntsReaderImpl = newPackedIntsReaderImpl(valueCount, 48)
	return ans
}

func newPacked16ThreeBlocksFromInput(version int32, in *DataInput, valueCount int32) (r PackedIntsReader, err error) {
	ans := newPacked16ThreeBlocks(valueCount)
	for i, _ := range ans.blocks {
		if ans.blocks[i], err = in.ReadShort(); err != nil {
			break
		}
	}
	if err == nil {
		// because packed ints have not always been byte-aligned
		remaining = PACKED.ByteCount(version, valueCount, 48) - 3*valueCount*2
		for i := 0; i < remaining; i++ {
			if _, err = in.ReadByte(); err != nil {
				break
			}
		}
	}
	return ans, err
}

const (
	PACKED64_BLOCK_SIZE = 64
)

type Packed64 struct {
	PackedIntsReaderImpl
	blocks            []int64
	maskRight         uint64
	bpvMinusBlockSIze int32
}

func newPacked64(valueCount int32, bitsPerValue uint32) Packed64 {
	longCount := PACKED.LongCount(PACKED_VERSION_CURRENT, valueCount, bitsPerValue)
	ans := Packed64{
		blocks:            make([]int64, longCount),
		maskRight:         uint64(^(int64(0))<<(PACKED64_BLOCK_SIZE-bitsPerValue)) >> (PACKED64_BLOCK_SIZE - bitsPerValue),
		bpvMinusBlockSize: bitsPerValue - PACKED64_BLOCK_SIZE}
	ans.PackedIntsReaderImpl = newPackedIntsReaderImpl(valueCount, bitsPerValue)
	return ans
}

func newPacked64FromInput(version int32, int *DataInput, valueCount int32, bitsPerValue uint32) (r PackedIntsReader, err error) {
	ans := newPacked64(valueCount, bitsPerValue)
	byteCount := PACKED.ByteCount(version, valueCount, bitsPerValue)
	longCount := PACKED.LongCount(PACKED_VERSION_CURRENT, valueCount, bitsPerValue)
	ans.blocks = make([]int64, longCount)
	// read as many longs as we can
	for i := 0; i < byteCount/8; i++ {
		if ans.blocks[i], err = in.ReadLong(); err != nil {
			break
		}
	}
	if err == nil {
		if remaining := byteCount % 8; remaining != 0 {
			// read the last bytes
			var lastLong int64
			for i := 0; i < remaining; i++ {
				b, err := in.ReadByte()
				if err != nil {
					break
				}
				lastLong |= int64(b) << (5 - i*8)
			}
			if err == nil {
				ans.blocks[len(ans.blocks)-1] = lastLong
			}
		}
	}
	return ans, err
}

type GrowableWriter struct {
	current PackedIntsMutable
}

func (w *GrowableWriter) Get(index int32) int64 {
	return w.current.Get(index)
}

func (w *GrowableWriter) Size() int32 {
	return w.current.Size()
}
<|endoftext|>


<commit_before>package fontmaker

import (
	"encoding/binary"
	"errors"
	"fmt"
	"os"
)

type TTFParser struct {
}

func (me *TTFParser) Parse(fontpath string) error {
	fmt.Printf("start parse\n")
	fd, err := os.Open(fontpath)
	if err != nil {
		return err
	}
	defer fd.Close()
	version, err := me.Read(fd, 4)
	if err != nil {
		return err
	}

	if !me.CompareBytes(version, []byte{0x00, 0x01, 0x00, 0x00}) {
		return errors.New("Unrecognized file (font) format")
	}

	i := uint64(0)
	numTables, err := me.ReadUShort(fd)
	if err != nil {
		return err
	}

	for i < numTables {

		i++
	}
	return nil
}

func (me *TTFParser) ReadUShort(fd *os.File) (uint64, error) {
	buff, err := me.Read(fd, 2)
	if err != nil {
		return 0, err
	}
	//fmt.Printf("%#v\n", buff)
	num, length := binary.Uvarint(buff)
	if length == 0 {
		return 0, errors.New("buf too small")
	} else if length < 0 {
		return 0, errors.New("value larger than 64 bits (overflow)")
	}
	return num, nil
}

func (me *TTFParser) Read(fd *os.File, length int) ([]byte, error) {
	buff := make([]byte, length)
	readlength, err := fd.Read(buff)
	if err != nil {
		return nil, err
	}
	if readlength != length {
		return nil, errors.New("file out of length")
	}
	//fmt.Printf("%d,%s\n", readlength, string(buff))
	return buff, nil
}

func (me *TTFParser) CompareBytes(a []byte, b []byte) bool {

	if a == nil && b == nil {
		return true
	} else if a == nil && b != nil {
		return false
	} else if a != nil && b == nil {
		return false
	}

	if len(a) != len(b) {
		return false
	}

	i := 0
	length := len(a)
	for i < length {
		if a[i] != b[i] {
			return false
		}
		i++
	}
	return true
}
<commit_msg>start ParseHead<commit_after>package fontmaker

import (
	//"encoding/binary"
	//"encoding/hex"
	"errors"
	"fmt"
	"math/big"
	"os"
)

type TTFParser struct {
	tables map[string]uint64
}

func (me *TTFParser) Parse(fontpath string) error {
	fmt.Printf("start parse\n")
	fd, err := os.Open(fontpath)
	if err != nil {
		return err
	}
	defer fd.Close()
	version, err := me.Read(fd, 4)
	if err != nil {
		return err
	}

	if !me.CompareBytes(version, []byte{0x00, 0x01, 0x00, 0x00}) {
		return errors.New("Unrecognized file (font) format")
	}

	i := uint64(0)
	numTables, err := me.ReadUShort(fd)
	if err != nil {
		return err
	}
	me.Skip(fd, 3*2) //searchRange, entrySelector, rangeShift
	me.tables = make(map[string]uint64)
	for i < numTables {

		tag, err := me.Read(fd, 4)
		if err != nil {
			return err
		}

		err = me.Skip(fd, 4)
		if err != nil {
			return err
		}

		offset, err := me.ReadULong(fd)
		if err != nil {
			return err
		}

		err = me.Skip(fd, 4)
		if err != nil {
			return err
		}
		//fmt.Printf("%s\n", me.BytesToString(tag))
		me.tables[me.BytesToString(tag)] = offset
		i++
	}

	fmt.Printf("%+v\n", me.tables)

	me.ParseHead(fd)

	return nil
}

func (me *TTFParser) ParseHead(fd *os.File) error {
	me.Seek(fd, "head")
	me.Skip(fd, 3*4) // version, fontRevision, checkSumAdjustment
	magicNumber, err := me.ReadULong(fd)
	if err != nil {
		return err
	}
	fmt.Printf("%d", magicNumber)
	return nil
}

func (me *TTFParser) Seek(fd *os.File, tag string) error {
	val, ok := me.tables[tag]
	if !ok {
		return errors.New("me.tables not contain key=" + tag)
	}
	_, err := fd.Seek(int64(val), 1)
	if err != nil {
		return err
	}
	return nil
}

func (me *TTFParser) BytesToString(b []byte) string {
	return string(b)
}

func (me *TTFParser) ReadUShort(fd *os.File) (uint64, error) {
	buff, err := me.Read(fd, 2)
	if err != nil {
		return 0, err
	}
	num := big.NewInt(0)
	num.SetBytes(buff)
	return num.Uint64(), nil
}

func (me *TTFParser) ReadULong(fd *os.File) (uint64, error) {
	buff, err := me.Read(fd, 4)
	if err != nil {
		return 0, err
	}
	num := big.NewInt(0)
	num.SetBytes(buff)
	return num.Uint64(), nil
}

func (me *TTFParser) Skip(fd *os.File, length int64) error {
	_, err := fd.Seek(int64(length), 1)
	if err != nil {
		return err
	}
	return nil
}

func (me *TTFParser) Read(fd *os.File, length int) ([]byte, error) {
	buff := make([]byte, length)
	readlength, err := fd.Read(buff)
	if err != nil {
		return nil, err
	}
	if readlength != length {
		return nil, errors.New("file out of length")
	}
	//fmt.Printf("%d,%s\n", readlength, string(buff))
	return buff, nil
}

func (me *TTFParser) CompareBytes(a []byte, b []byte) bool {

	if a == nil && b == nil {
		return true
	} else if a == nil && b != nil {
		return false
	} else if a != nil && b == nil {
		return false
	}

	if len(a) != len(b) {
		return false
	}

	i := 0
	length := len(a)
	for i < length {
		if a[i] != b[i] {
			return false
		}
		i++
	}
	return true
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"log"
	"math/big"
	"os"
	"sort"
	"strings"
	"text/tabwriter"

	"github.com/bgentry/heroku-go"
)

var cmdAddons = &Command{
	Run:      runAddons,
	Usage:    "addons [<service>:<plan>...]",
	NeedsApp: true,
	Category: "add-on",
	Short:    "list addons",
	Long: `
Lists addons.

Examples:

    $ hk addons
    heroku-postgresql-blue  heroku-postgresql:crane  Nov 19 12:40
    pgbackups               pgbackups:plus           Sep 30 15:43

    $ hk addons pgbackups
    pgbackups  pgbackups:plus  Sep 30 15:43
`,
}

func runAddons(cmd *Command, names []string) {
	appname := mustApp()
	addons, err := client.AddonList(appname, nil)
	must(err)

	w := tabwriter.NewWriter(os.Stdout, 1, 2, 2, ' ', 0)
	defer w.Flush()

	for i, s := range names {
		names[i] = strings.ToLower(s)
	}
	for _, a := range addons {
		if len(names) == 0 || addonMatch(a, names) {
			listAddon(w, a)
		}
	}
}

func addonMatch(a heroku.Addon, names []string) bool {
	for _, name := range names {
		if name == strings.ToLower(a.Name) {
			return true
		}
		if name == strings.ToLower(a.Plan.Name) {
			return true
		}
		if name == strings.ToLower(a.Id) {
			return true
		}
	}
	return false
}

func listAddon(w io.Writer, a heroku.Addon) {
	name := a.Name
	if name == "" {
		name = "[unnamed]"
	}
	listRec(w,
		name,
		a.Plan.Name,
		prettyTime{a.CreatedAt},
	)
}

var cmdAddonAdd = &Command{
	Run:      runAddonAdd,
	Usage:    "addon-add <service>[:<plan>] [<config>=<value>...]",
	NeedsApp: true,
	Category: "add-on",
	Short:    "add an addon",
	Long: `
Adds an addon to an app.

Examples:

    $ hk addon-add heroku-postgresql
    Added heroku-postgresql:hobby-dev to myapp as heroku-postgresql-yellow.

    $ hk addon-add heroku-postgresql:standard-tengu
    Added heroku-postgresql:standard-tengu to myapp as heroku-postgresql-orange.
`,
}

func runAddonAdd(cmd *Command, args []string) {
	appname := mustApp()
	if len(args) == 0 {
		cmd.printUsage()
		os.Exit(2)
	}
	plan := args[0]
	var opts heroku.AddonCreateOpts
	if len(args) > 1 {
		config, err := parseAddonAddConfig(args[1:])
		if err != nil {
			log.Println(err)
			os.Exit(2)
		}
		// if this is a postgres addon, resolve fork/follow/rollback args
		provider, _ := splitProviderAndPlan(plan)
		if provider == hpgAddonName() && config != nil {
			for k, _ := range *config {
				if i := stringsIndex(hpgOptNames, k); i != -1 {
					// contains an hpgOptNames key, we need to resolve these against envs
					appEnv, err := client.ConfigVarInfo(appname)
					must(err)
					must(hpgAddonOptResolve(config, appEnv))
					break
				}
			}
		}
		opts = heroku.AddonCreateOpts{Config: config}
	}
	addon, err := client.AddonCreate(appname, plan, &opts)
	must(err)
	log.Printf("Added %s to %s as %s.", addon.Plan.Name, appname, addon.Name)
}

func splitProviderAndPlan(providerAndPlan string) (provider string, plan string) {
	parts := strings.Split(providerAndPlan, ":")
	if len(parts) > 0 {
		provider = parts[0]
	}
	if len(parts) > 1 {
		plan = parts[1]
	}
	return
}

func parseAddonAddConfig(config []string) (*map[string]string, error) {
	conf := make(map[string]string, len(config))
	for _, kv := range config {
		iEq := strings.IndexRune(kv, '=')
		if iEq < 1 || len(kv) < iEq+2 {
			return nil, fmt.Errorf("Invalid option '%s', must be of form 'key=value'", kv)
		}
		val := kv[iEq+1:]
		if val[0] == '\'' {
			val = strings.Trim(val, "'")
		} else if val[0] == '"' {
			val = strings.Trim(val, "\"")
		}
		conf[kv[:iEq]] = val
	}
	return &conf, nil
}

var cmdAddonDestroy = &Command{
	Run:      runAddonDestroy,
	Usage:    "addon-destroy <name>",
	NeedsApp: true,
	Category: "add-on",
	Short:    "destroy an addon",
	Long: `
Removes an addon from an app, permanently destroying any data
stored by that addon. The command will prompt for confirmation,
or accept confirmation via stdin.

Examples:

    $ hk addon-destroy heroku-postgresql-blue
    warning: This will destroy heroku-postgresql-blue on myapp. Please type "myapp" to continue:
    > myapp
    Destroyed heroku-postgresql-blue on myapp.

    $ echo myapp | hk addon-destroy redistogo
    Destroyed redistogo on myapp.
`,
}

func runAddonDestroy(cmd *Command, args []string) {
	appname := mustApp()
	if len(args) != 1 {
		cmd.printUsage()
		os.Exit(2)
	}
	name := args[0]
	if strings.IndexRune(name, ':') != -1 {
		// specified an addon with plan name, unsupported in v3
		log.Println("Please specify an addon name, not a plan name.")
		cmd.printUsage()
		os.Exit(2)
	}

	warning := fmt.Sprintf("This will destroy %s on %s. Please type %q to continue:", name, appname, appname)
	mustConfirm(warning, appname)

	checkAddonError(client.AddonDelete(appname, name))
	log.Printf("Destroyed %s on %s.", name, appname)
}

var cmdAddonOpen = &Command{
	Run:      runAddonOpen,
	Usage:    "addon-open <name>",
	NeedsApp: true,
	Category: "add-on",
	Short:    "open an addon" + extra,
	Long: `
Open the addon's management page in your default web browser.

Examples:

    $ hk addon-open heroku-postgresql-blue

    $ hk addon-open redistogo
`,
}

func runAddonOpen(cmd *Command, args []string) {
	appname := mustApp()
	if len(args) != 1 {
		cmd.printUsage()
		os.Exit(2)
	}
	name := args[0]
	// look up addon to make sure it exists and to get plan name
	a, err := client.AddonInfo(appname, name)
	checkAddonError(err)
	must(openURL("https://addons-sso.heroku.com/apps/" + appname + "/addons/" + a.Plan.Name))
}

func checkAddonError(err error) {
	if err != nil {
		if hkerr, ok := err.(heroku.Error); ok && hkerr.Id == "not_found" {
			printFatal(err.Error() + " Choose an addon name from `hk addons`.")
		} else {
			printFatal(err.Error())
		}
		os.Exit(2)
	}
}

var cmdAddonServices = &Command{
	Run:      runAddonServices,
	Usage:    "addon-services",
	Category: "add-on",
	Short:    "list addon services",
	Long: `
Lists available addon services.

Examples:

    $ hk addon-services
    heroku-postgresql
    newrelic
    redisgreen
    ...
`,
}

func runAddonServices(cmd *Command, args []string) {
	if len(args) != 0 {
		cmd.printUsage()
		os.Exit(2)
	}
	services, err := client.AddonServiceList(nil)
	must(err)

	for _, s := range services {
		fmt.Println(s.Name)
	}
}

var cmdAddonPlans = &Command{
	Run:      runAddonPlans,
	Usage:    "addon-plans <service>",
	Category: "add-on",
	Short:    "list addon plans",
	Long: `
Lists available addon plans for an addon provider.

Examples:

    $ hk addon-plans heroku-postgresql
    hobby-dev        $0/mo
    hobby-basic      $9/mo
    standard-yanari  $50/mo
    standard-tengu   $200/mo
    premium-yanari   $200/mo
    premium-tengu    $350/mo
    standard-ika     $750/mo
    premium-ika      $1200/mo
    ...
`,
}

func runAddonPlans(cmd *Command, args []string) {
	if len(args) != 1 {
		cmd.printUsage()
		os.Exit(2)
	}
	service := args[0]
	plans, err := client.PlanList(service, nil)
	must(err)

	w := tabwriter.NewWriter(os.Stdout, 1, 2, 2, ' ', 0)
	defer w.Flush()

	sort.Sort(addonPlansByPrice(plans))
	for _, p := range plans {
		listRec(w,
			strings.TrimPrefix(p.Name, service+":"),
			addonPlanPriceString(p),
		)
	}
}

type addonPlansByPrice []heroku.Plan

func (a addonPlansByPrice) Len() int           { return len(a) }
func (a addonPlansByPrice) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a addonPlansByPrice) Less(i, j int) bool { return a[i].Price.Cents < a[j].Price.Cents }

func addonPlanPriceString(p heroku.Plan) string {
	r := big.NewRat(int64(p.Price.Cents), 100)
	decimals := 2
	if p.Price.Cents%100 == 0 {
		decimals = 0
	}
	return "$" + r.FloatString(decimals) + "/" + shortenPriceUnit(p.Price.Unit)
}

func shortenPriceUnit(unit string) string {
	switch unit {
	case "month":
		return "mo"
	default:
		return unit
	}
}
<commit_msg>put addon-services and addon-plans in extra help<commit_after>package main

import (
	"fmt"
	"io"
	"log"
	"math/big"
	"os"
	"sort"
	"strings"
	"text/tabwriter"

	"github.com/bgentry/heroku-go"
)

var cmdAddons = &Command{
	Run:      runAddons,
	Usage:    "addons [<service>:<plan>...]",
	NeedsApp: true,
	Category: "add-on",
	Short:    "list addons",
	Long: `
Lists addons.

Examples:

    $ hk addons
    heroku-postgresql-blue  heroku-postgresql:crane  Nov 19 12:40
    pgbackups               pgbackups:plus           Sep 30 15:43

    $ hk addons pgbackups
    pgbackups  pgbackups:plus  Sep 30 15:43
`,
}

func runAddons(cmd *Command, names []string) {
	appname := mustApp()
	addons, err := client.AddonList(appname, nil)
	must(err)

	w := tabwriter.NewWriter(os.Stdout, 1, 2, 2, ' ', 0)
	defer w.Flush()

	for i, s := range names {
		names[i] = strings.ToLower(s)
	}
	for _, a := range addons {
		if len(names) == 0 || addonMatch(a, names) {
			listAddon(w, a)
		}
	}
}

func addonMatch(a heroku.Addon, names []string) bool {
	for _, name := range names {
		if name == strings.ToLower(a.Name) {
			return true
		}
		if name == strings.ToLower(a.Plan.Name) {
			return true
		}
		if name == strings.ToLower(a.Id) {
			return true
		}
	}
	return false
}

func listAddon(w io.Writer, a heroku.Addon) {
	name := a.Name
	if name == "" {
		name = "[unnamed]"
	}
	listRec(w,
		name,
		a.Plan.Name,
		prettyTime{a.CreatedAt},
	)
}

var cmdAddonAdd = &Command{
	Run:      runAddonAdd,
	Usage:    "addon-add <service>[:<plan>] [<config>=<value>...]",
	NeedsApp: true,
	Category: "add-on",
	Short:    "add an addon",
	Long: `
Adds an addon to an app.

Examples:

    $ hk addon-add heroku-postgresql
    Added heroku-postgresql:hobby-dev to myapp as heroku-postgresql-yellow.

    $ hk addon-add heroku-postgresql:standard-tengu
    Added heroku-postgresql:standard-tengu to myapp as heroku-postgresql-orange.
`,
}

func runAddonAdd(cmd *Command, args []string) {
	appname := mustApp()
	if len(args) == 0 {
		cmd.printUsage()
		os.Exit(2)
	}
	plan := args[0]
	var opts heroku.AddonCreateOpts
	if len(args) > 1 {
		config, err := parseAddonAddConfig(args[1:])
		if err != nil {
			log.Println(err)
			os.Exit(2)
		}
		// if this is a postgres addon, resolve fork/follow/rollback args
		provider, _ := splitProviderAndPlan(plan)
		if provider == hpgAddonName() && config != nil {
			for k, _ := range *config {
				if i := stringsIndex(hpgOptNames, k); i != -1 {
					// contains an hpgOptNames key, we need to resolve these against envs
					appEnv, err := client.ConfigVarInfo(appname)
					must(err)
					must(hpgAddonOptResolve(config, appEnv))
					break
				}
			}
		}
		opts = heroku.AddonCreateOpts{Config: config}
	}
	addon, err := client.AddonCreate(appname, plan, &opts)
	must(err)
	log.Printf("Added %s to %s as %s.", addon.Plan.Name, appname, addon.Name)
}

func splitProviderAndPlan(providerAndPlan string) (provider string, plan string) {
	parts := strings.Split(providerAndPlan, ":")
	if len(parts) > 0 {
		provider = parts[0]
	}
	if len(parts) > 1 {
		plan = parts[1]
	}
	return
}

func parseAddonAddConfig(config []string) (*map[string]string, error) {
	conf := make(map[string]string, len(config))
	for _, kv := range config {
		iEq := strings.IndexRune(kv, '=')
		if iEq < 1 || len(kv) < iEq+2 {
			return nil, fmt.Errorf("Invalid option '%s', must be of form 'key=value'", kv)
		}
		val := kv[iEq+1:]
		if val[0] == '\'' {
			val = strings.Trim(val, "'")
		} else if val[0] == '"' {
			val = strings.Trim(val, "\"")
		}
		conf[kv[:iEq]] = val
	}
	return &conf, nil
}

var cmdAddonDestroy = &Command{
	Run:      runAddonDestroy,
	Usage:    "addon-destroy <name>",
	NeedsApp: true,
	Category: "add-on",
	Short:    "destroy an addon",
	Long: `
Removes an addon from an app, permanently destroying any data
stored by that addon. The command will prompt for confirmation,
or accept confirmation via stdin.

Examples:

    $ hk addon-destroy heroku-postgresql-blue
    warning: This will destroy heroku-postgresql-blue on myapp. Please type "myapp" to continue:
    > myapp
    Destroyed heroku-postgresql-blue on myapp.

    $ echo myapp | hk addon-destroy redistogo
    Destroyed redistogo on myapp.
`,
}

func runAddonDestroy(cmd *Command, args []string) {
	appname := mustApp()
	if len(args) != 1 {
		cmd.printUsage()
		os.Exit(2)
	}
	name := args[0]
	if strings.IndexRune(name, ':') != -1 {
		// specified an addon with plan name, unsupported in v3
		log.Println("Please specify an addon name, not a plan name.")
		cmd.printUsage()
		os.Exit(2)
	}

	warning := fmt.Sprintf("This will destroy %s on %s. Please type %q to continue:", name, appname, appname)
	mustConfirm(warning, appname)

	checkAddonError(client.AddonDelete(appname, name))
	log.Printf("Destroyed %s on %s.", name, appname)
}

var cmdAddonOpen = &Command{
	Run:      runAddonOpen,
	Usage:    "addon-open <name>",
	NeedsApp: true,
	Category: "add-on",
	Short:    "open an addon" + extra,
	Long: `
Open the addon's management page in your default web browser.

Examples:

    $ hk addon-open heroku-postgresql-blue

    $ hk addon-open redistogo
`,
}

func runAddonOpen(cmd *Command, args []string) {
	appname := mustApp()
	if len(args) != 1 {
		cmd.printUsage()
		os.Exit(2)
	}
	name := args[0]
	// look up addon to make sure it exists and to get plan name
	a, err := client.AddonInfo(appname, name)
	checkAddonError(err)
	must(openURL("https://addons-sso.heroku.com/apps/" + appname + "/addons/" + a.Plan.Name))
}

func checkAddonError(err error) {
	if err != nil {
		if hkerr, ok := err.(heroku.Error); ok && hkerr.Id == "not_found" {
			printFatal(err.Error() + " Choose an addon name from `hk addons`.")
		} else {
			printFatal(err.Error())
		}
		os.Exit(2)
	}
}

var cmdAddonServices = &Command{
	Run:      runAddonServices,
	Usage:    "addon-services",
	Category: "add-on",
	Short:    "list addon services" + extra,
	Long: `
Lists available addon services.

Examples:

    $ hk addon-services
    heroku-postgresql
    newrelic
    redisgreen
    ...
`,
}

func runAddonServices(cmd *Command, args []string) {
	if len(args) != 0 {
		cmd.printUsage()
		os.Exit(2)
	}
	services, err := client.AddonServiceList(nil)
	must(err)

	for _, s := range services {
		fmt.Println(s.Name)
	}
}

var cmdAddonPlans = &Command{
	Run:      runAddonPlans,
	Usage:    "addon-plans <service>",
	Category: "add-on",
	Short:    "list addon plans" + extra,
	Long: `
Lists available addon plans for an addon provider.

Examples:

    $ hk addon-plans heroku-postgresql
    hobby-dev        $0/mo
    hobby-basic      $9/mo
    standard-yanari  $50/mo
    standard-tengu   $200/mo
    premium-yanari   $200/mo
    premium-tengu    $350/mo
    standard-ika     $750/mo
    premium-ika      $1200/mo
    ...
`,
}

func runAddonPlans(cmd *Command, args []string) {
	if len(args) != 1 {
		cmd.printUsage()
		os.Exit(2)
	}
	service := args[0]
	plans, err := client.PlanList(service, nil)
	must(err)

	w := tabwriter.NewWriter(os.Stdout, 1, 2, 2, ' ', 0)
	defer w.Flush()

	sort.Sort(addonPlansByPrice(plans))
	for _, p := range plans {
		listRec(w,
			strings.TrimPrefix(p.Name, service+":"),
			addonPlanPriceString(p),
		)
	}
}

type addonPlansByPrice []heroku.Plan

func (a addonPlansByPrice) Len() int           { return len(a) }
func (a addonPlansByPrice) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a addonPlansByPrice) Less(i, j int) bool { return a[i].Price.Cents < a[j].Price.Cents }

func addonPlanPriceString(p heroku.Plan) string {
	r := big.NewRat(int64(p.Price.Cents), 100)
	decimals := 2
	if p.Price.Cents%100 == 0 {
		decimals = 0
	}
	return "$" + r.FloatString(decimals) + "/" + shortenPriceUnit(p.Price.Unit)
}

func shortenPriceUnit(unit string) string {
	switch unit {
	case "month":
		return "mo"
	default:
		return unit
	}
}
<|endoftext|>


<commit_before>package saxReader

import (
	"testing"
	"bytes"
	"github.com/zacg/testify/assert"
)

func newTestSaxReader(emitterTestFn func(string)) SaxReader {
	return SaxReader{ElementBufferSize:10,
		ContentBufferSize:1024,
		ReaderBufferSize:10,
		PathDepthSize:10,
		EmitterFn : emitterTestFn,
		IsInnerXml:false,
		FilterEscapeSigns:false,
	}
}

func TestParseXmlOneNode(t *testing.T) {
	res := ""
	emitter := func(element string) {
		res = element
	};
	reader := bytes.NewReader([]byte("<hello>test</hello>"))
	saxReader := newTestSaxReader(emitter)
	err := saxReader.Read(reader, "hello")
	assert.Nil(t, err)
	assert.Equal(t, res, "<hello>test</hello>")
}

func TestParseXmlOneNodeEmptySearch(t *testing.T) {
	res := ""
	emitter := func(element string) {
		res = element
	};
	reader := bytes.NewReader([]byte("<hello>test</hello>"))
	saxReader := newTestSaxReader(emitter)
	err := saxReader.Read(reader, "")
	assert.Nil(t, err)
	assert.Equal(t, res, "")
}

func TestParseInnerXmlOneNode(t *testing.T) {
	res := ""
	emitter := func(element string) {
		res = element
	};
	reader := bytes.NewReader([]byte("<hello>test</hello>"))
	saxReader := newTestSaxReader(emitter)
	saxReader.IsInnerXml = true
	err := saxReader.Read(reader, "hello")
	assert.Nil(t, err)
	assert.Equal(t, res, "test")
}

func TestParseXmlNodeConstrainedBuffer(t *testing.T) {
	res := ""
	emitter := func(element string) {
		res = element
	};
	reader := bytes.NewReader([]byte("<hello>test</hello>"))
	saxReader := newTestSaxReader(emitter)
	saxReader.ReaderBufferSize = 1
	err := saxReader.Read(reader, "hello")
	assert.Nil(t, err)
	assert.Equal(t, res, "<hello>test</hello>")
}

func TestParseXmlNodesConstrainedBuffer(t *testing.T) {
	var actuals []string = make([]string, 10)
	var actualsPos int = 0
	emitter := func(element string) {
		actuals[actualsPos] = element
		actualsPos++
	};
	reader := bytes.NewReader([]byte("<helloA><helloB><helloC>C1</helloC><helloC>C2</helloC></helloB></helloA>"))
	saxReader := newTestSaxReader(emitter)
	saxReader.ReaderBufferSize = 1
	err := saxReader.Read(reader, "helloA/helloB/helloC")
	assert.Nil(t, err)
	assert.Equal(t, actuals[0], "<helloC>C1</helloC>")
	assert.Equal(t, actuals[1], "<helloC>C2</helloC>")
}

func TestParseXmlNodesWithComments(t *testing.T) {
	var actuals []string = make([]string, 10)
	var actualsPos int = 0
	emitter := func(element string) {
		actuals[actualsPos] = element
		actualsPos++
	};
	reader := bytes.NewReader([]byte("<helloA><helloB><!-- test<>--<><--><helloC>C1</helloC><helloC>C2</helloC></helloB></helloA>"))
	saxReader := newTestSaxReader(emitter)
	saxReader.ReaderBufferSize = 1
	err := saxReader.Read(reader, "helloA/helloB/helloC")
	assert.Nil(t, err)
	assert.Equal(t, actuals[0], "<helloC>C1</helloC>")
	assert.Equal(t, actuals[1], "<helloC>C2</helloC>")
}

func TestParseXmlNodesWithCdata(t *testing.T) {
	var actuals []string = make([]string, 10)
	var actualsPos int = 0
	emitter := func(element string) {
		actuals[actualsPos] = element
		actualsPos++
	};
	reader := bytes.NewReader([]byte("<helloA><helloB><helloC><![CDATA[Hello<! World!]]></helloC><helloC>C2</helloC></helloB></helloA>"))
	saxReader := newTestSaxReader(emitter)
	err := saxReader.Read(reader, "helloA/helloB/helloC")
	assert.Nil(t, err)
	assert.Equal(t, actuals[0], "<helloC><![CDATA[Hello<! World!]]></helloC>")
	assert.Equal(t, actuals[1], "<helloC>C2</helloC>")
}

func TestParseXmlNodesWithCdataAndComment(t *testing.T) {
	var actuals []string = make([]string, 10)
	var actualsPos int = 0
	emitter := func(element string) {
		actuals[actualsPos] = element
		actualsPos++
	};
	reader := bytes.NewReader([]byte("<helloA><!-- test<>--<><--><helloB><helloC><![CDATA[Hello<! World!]]></helloC><helloC>C2</helloC></helloB></helloA>"))
	saxReader := newTestSaxReader(emitter)
	err := saxReader.Read(reader, "helloA/helloB/helloC")
	assert.Nil(t, err)
	assert.Equal(t, actuals[0], "<helloC><![CDATA[Hello<! World!]]></helloC>")
	assert.Equal(t, actuals[1], "<helloC>C2</helloC>")
}

func TestParseXmlNodesWithCdataAndCommentConstrainedBuffer(t *testing.T) {
	var actuals []string = make([]string, 10)
	var actualsPos int = 0
	emitter := func(element string) {
		actuals[actualsPos] = element
		actualsPos++
	};
	reader := bytes.NewReader([]byte("<helloA><!-- test<>--<><--><helloB><helloC><![CDATA[Hello<! World!]]></helloC><helloC>C2</helloC></helloB></helloA>"))
	saxReader := newTestSaxReader(emitter)
	saxReader.ReaderBufferSize = 1
	err := saxReader.Read(reader, "helloA/helloB/helloC")
	assert.Nil(t, err)
	assert.Equal(t, actuals[0], "<helloC><![CDATA[Hello<! World!]]></helloC>")
	assert.Equal(t, actuals[1], "<helloC>C2</helloC>")
}

func TestParseXmlNodesWithEscape(t *testing.T) {
	var actuals []string = make([]string, 10)
	var actualsPos int = 0
	emitter := func(element string) {
		actuals[actualsPos] = element
		actualsPos++
	};
	reader := bytes.NewReader([]byte("<helloA><!-- test<>--<><--><helloB><helloC><![CDATA[Hello<! World!]]></helloC><helloC>C2</helloC></helloB></helloA>"))
	saxReader := newTestSaxReader(emitter)
	saxReader.FilterEscapeSigns = true
	err := saxReader.Read(reader, "helloA/helloB/helloC")
	assert.Nil(t, err)
	assert.Equal(t, actuals[0], "<helloC><![CDATA[Hello<! World!]]></helloC>")
	assert.Equal(t, actuals[1], "<helloC>C2</helloC>")
}

func TestParseXmlNodesWithEscapeTag(t *testing.T) {
	res := ""
	emitter := func(element string) {
		res = element
	};
	reader := bytes.NewReader([]byte("<helloA><helloB><helloC></helloC></helloB></helloA>"))
	saxReader := newTestSaxReader(emitter)
	err := saxReader.Read(reader, "helloA/helloB")
	assert.Nil(t, err)
	assert.Equal(t, res, "<helloB><helloC></helloC></helloB>")
}

func TestParseXmlOneNodeWithLtError(t *testing.T) {
	res := ""
	emitter := func(element string) {
		res = element
	};
	reader := bytes.NewReader([]byte("<he<llo>test</hello>"))
	saxReader := newTestSaxReader(emitter)
	err := saxReader.Read(reader, "hello")
	assert.NotNil(t, err)
}<commit_msg>gt tag improvment<commit_after>package saxReader

import (
	"testing"
	"bytes"
	"github.com/zacg/testify/assert"
)

func newTestSaxReader(emitterTestFn func(string)) SaxReader {
	return SaxReader{ElementBufferSize:10,
		ContentBufferSize:1024,
		ReaderBufferSize:10,
		PathDepthSize:10,
		EmitterFn : emitterTestFn,
		IsInnerXml:false,
		FilterEscapeSigns:false,
	}
}

func TestParseXmlOneNode(t *testing.T) {
	res := ""
	emitter := func(element string) {
		res = element
	};
	reader := bytes.NewReader([]byte("<hello>test</hello>"))
	saxReader := newTestSaxReader(emitter)
	err := saxReader.Read(reader, "hello")
	assert.Nil(t, err)
	assert.Equal(t, res, "<hello>test</hello>")
}

func TestParseXmlOneNodeEmptySearch(t *testing.T) {
	res := ""
	emitter := func(element string) {
		res = element
	};
	reader := bytes.NewReader([]byte("<hello>test</hello>"))
	saxReader := newTestSaxReader(emitter)
	err := saxReader.Read(reader, "")
	assert.Nil(t, err)
	assert.Equal(t, res, "")
}

func TestParseInnerXmlOneNode(t *testing.T) {
	res := ""
	emitter := func(element string) {
		res = element
	};
	reader := bytes.NewReader([]byte("<hello>test</hello>"))
	saxReader := newTestSaxReader(emitter)
	saxReader.IsInnerXml = true
	err := saxReader.Read(reader, "hello")
	assert.Nil(t, err)
	assert.Equal(t, res, "test")
}

func TestParseXmlNodeConstrainedBuffer(t *testing.T) {
	res := ""
	emitter := func(element string) {
		res = element
	};
	reader := bytes.NewReader([]byte("<hello>test</hello>"))
	saxReader := newTestSaxReader(emitter)
	saxReader.ReaderBufferSize = 1
	err := saxReader.Read(reader, "hello")
	assert.Nil(t, err)
	assert.Equal(t, res, "<hello>test</hello>")
}

func TestParseXmlNodesConstrainedBuffer(t *testing.T) {
	var actuals []string = make([]string, 10)
	var actualsPos int = 0
	emitter := func(element string) {
		actuals[actualsPos] = element
		actualsPos++
	};
	reader := bytes.NewReader([]byte("<helloA><helloB><helloC>C1</helloC><helloC>C2</helloC></helloB></helloA>"))
	saxReader := newTestSaxReader(emitter)
	saxReader.ReaderBufferSize = 1
	err := saxReader.Read(reader, "helloA/helloB/helloC")
	assert.Nil(t, err)
	assert.Equal(t, actuals[0], "<helloC>C1</helloC>")
	assert.Equal(t, actuals[1], "<helloC>C2</helloC>")
}

func TestParseXmlNodesWithComments(t *testing.T) {
	var actuals []string = make([]string, 10)
	var actualsPos int = 0
	emitter := func(element string) {
		actuals[actualsPos] = element
		actualsPos++
	};
	reader := bytes.NewReader([]byte("<helloA><helloB><!-- test<>--<><--><helloC>C1</helloC><helloC>C2</helloC></helloB></helloA>"))
	saxReader := newTestSaxReader(emitter)
	saxReader.ReaderBufferSize = 1
	err := saxReader.Read(reader, "helloA/helloB/helloC")
	assert.Nil(t, err)
	assert.Equal(t, actuals[0], "<helloC>C1</helloC>")
	assert.Equal(t, actuals[1], "<helloC>C2</helloC>")
}

func TestParseXmlNodesWithCdata(t *testing.T) {
	var actuals []string = make([]string, 10)
	var actualsPos int = 0
	emitter := func(element string) {
		actuals[actualsPos] = element
		actualsPos++
	};
	reader := bytes.NewReader([]byte("<helloA><helloB><helloC><![CDATA[Hello<! World!]]></helloC><helloC>C2</helloC></helloB></helloA>"))
	saxReader := newTestSaxReader(emitter)
	err := saxReader.Read(reader, "helloA/helloB/helloC")
	assert.Nil(t, err)
	assert.Equal(t, actuals[0], "<helloC><![CDATA[Hello<! World!]]></helloC>")
	assert.Equal(t, actuals[1], "<helloC>C2</helloC>")
}

func TestParseXmlNodesWithCdataAndComment(t *testing.T) {
	var actuals []string = make([]string, 10)
	var actualsPos int = 0
	emitter := func(element string) {
		actuals[actualsPos] = element
		actualsPos++
	};
	reader := bytes.NewReader([]byte("<helloA><!-- test<>--<><--><helloB><helloC><![CDATA[Hello<! World!]]></helloC><helloC>C2</helloC></helloB></helloA>"))
	saxReader := newTestSaxReader(emitter)
	err := saxReader.Read(reader, "helloA/helloB/helloC")
	assert.Nil(t, err)
	assert.Equal(t, actuals[0], "<helloC><![CDATA[Hello<! World!]]></helloC>")
	assert.Equal(t, actuals[1], "<helloC>C2</helloC>")
}

func TestParseXmlNodesWithCdataAndCommentConstrainedBuffer(t *testing.T) {
	var actuals []string = make([]string, 10)
	var actualsPos int = 0
	emitter := func(element string) {
		actuals[actualsPos] = element
		actualsPos++
	};
	reader := bytes.NewReader([]byte("<helloA><!-- test<>--<><--><helloB><helloC><![CDATA[Hello<! World!]]></helloC><helloC>C2</helloC></helloB></helloA>"))
	saxReader := newTestSaxReader(emitter)
	saxReader.ReaderBufferSize = 1
	err := saxReader.Read(reader, "helloA/helloB/helloC")
	assert.Nil(t, err)
	assert.Equal(t, actuals[0], "<helloC><![CDATA[Hello<! World!]]></helloC>")
	assert.Equal(t, actuals[1], "<helloC>C2</helloC>")
}

func TestParseXmlNodesWithEscape(t *testing.T) {
	var actuals []string = make([]string, 10)
	var actualsPos int = 0
	emitter := func(element string) {
		actuals[actualsPos] = element
		actualsPos++
	};
	reader := bytes.NewReader([]byte("<helloA><!-- test<>--<><--><helloB><helloC><![CDATA[Hello<! World!]]></helloC><helloC>C2</helloC></helloB></helloA>"))
	saxReader := newTestSaxReader(emitter)
	saxReader.FilterEscapeSigns = true
	err := saxReader.Read(reader, "helloA/helloB/helloC")
	assert.Nil(t, err)
	assert.Equal(t, actuals[0], "<helloC><![CDATA[Hello<! World!]]></helloC>")
	assert.Equal(t, actuals[1], "<helloC>C2</helloC>")
}

func TestParseXmlNodesWithLtEscapeTag(t *testing.T) {
	res := ""
	emitter := func(element string) {
		res = element
	};
	reader := bytes.NewReader([]byte("<helloA><helloB><helloC></helloC></helloB></helloA>"))
	saxReader := newTestSaxReader(emitter)
	err := saxReader.Read(reader, "helloA/helloB")
	assert.Nil(t, err)
	assert.Equal(t, res, "<helloB><helloC></helloC></helloB>")
}

func TestParseXmlOneNodeWithLtError(t *testing.T) {
	res := ""
	emitter := func(element string) {
		res = element
	};
	reader := bytes.NewReader([]byte("<he<llo>test</hello>"))
	saxReader := newTestSaxReader(emitter)
	err := saxReader.Read(reader, "hello")
	assert.NotNil(t, err)
}<|endoftext|>