2022-12-24 17:48:08 +02:00
|
|
|
|
package bin
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"errors"
|
|
|
|
|
|
"fmt"
|
|
|
|
|
|
"io"
|
|
|
|
|
|
"math"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// ByteOrder - порядок байт
|
|
|
|
|
|
type ByteOrder string
|
|
|
|
|
|
|
|
|
|
|
|
const (
|
2026-07-19 06:29:35 +03:00
|
|
|
|
|
2022-12-24 17:48:08 +02:00
|
|
|
|
// LH - low to high byte order
|
|
|
|
|
|
LH ByteOrder = "LH"
|
|
|
|
|
|
// HL - high to low byte order
|
|
|
|
|
|
HL ByteOrder = "HL"
|
|
|
|
|
|
|
2026-07-19 06:29:35 +03:00
|
|
|
|
// Int32SignBit uint32 = 1 << 31
|
|
|
|
|
|
// Int64SignBit uint64 = 1 << 63
|
|
|
|
|
|
maxReadAttempts = 5
|
2022-12-24 17:48:08 +02:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
var (
|
|
|
|
|
|
// ErrReadOverflow shows 100% bug in the source reader
|
|
|
|
|
|
ErrReadOverflow = errors.New("bin: reader returned 'n' > bufsize")
|
|
|
|
|
|
// ErrNegativeReadCount shows 100% bug in the source reader
|
|
|
|
|
|
ErrNegativeReadCount = errors.New("bin: reader returned negative 'n'")
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// ReadN - безопасно читаем n байт. Обрабатывает все возможные ситуации, в том числе
|
|
|
|
|
|
// баги Reader
|
|
|
|
|
|
func ReadN(r io.Reader, n int) (_ []byte, err error) {
|
|
|
|
|
|
if n < 0 {
|
2024-10-31 03:55:08 +02:00
|
|
|
|
err = fmt.Errorf("wrong n=%d", n)
|
|
|
|
|
|
return
|
2022-12-24 17:48:08 +02:00
|
|
|
|
}
|
|
|
|
|
|
buf := make([]byte, n)
|
2024-10-31 03:55:08 +02:00
|
|
|
|
err = ReadNInto(r, buf)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
return buf, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func ReadNInto(r io.Reader, buf []byte) (err error) {
|
|
|
|
|
|
if len(buf) == 0 {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
2022-12-24 17:48:08 +02:00
|
|
|
|
|
|
|
|
|
|
var q, total, readAttempts int
|
|
|
|
|
|
|
|
|
|
|
|
// Избегаем вечного цикла из-за неправильной реализации ридера
|
|
|
|
|
|
for readAttempts < maxReadAttempts {
|
2024-10-31 03:55:08 +02:00
|
|
|
|
bufsize := len(buf) - total
|
2022-12-24 17:48:08 +02:00
|
|
|
|
q, err = r.Read(buf[total:])
|
2024-10-31 03:55:08 +02:00
|
|
|
|
// Если буфер заполнен - успех, err игнорируем
|
2022-12-24 17:48:08 +02:00
|
|
|
|
if q == bufsize {
|
2024-10-31 03:55:08 +02:00
|
|
|
|
return nil
|
2022-12-24 17:48:08 +02:00
|
|
|
|
}
|
|
|
|
|
|
// Если ошибка - выходим с ошибкой
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
// Если прочитали больше чем размер буфера. Баг в Reader
|
|
|
|
|
|
if q > bufsize {
|
|
|
|
|
|
err = ErrReadOverflow
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
// Если прочитали < 0. Баг в Reader
|
|
|
|
|
|
if q < 0 {
|
|
|
|
|
|
err = ErrNegativeReadCount
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
// Если ошибки нет, а прочитали 0 байт - чтобы не войти в бесконечный цикл
|
|
|
|
|
|
// увеличиваем readAttempts
|
|
|
|
|
|
if q == 0 {
|
|
|
|
|
|
readAttempts++
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// Что-то прочитали, но меньше чем нужно - увеличиваем счетчик
|
|
|
|
|
|
// суммарно прочитанного
|
|
|
|
|
|
total += q
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
err = io.ErrNoProgress
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-07-19 06:29:35 +03:00
|
|
|
|
// var zeroUnixTime = []byte{0, 0, 0, 0, 0, 0}
|
|
|
|
|
|
|
|
|
|
|
|
// func Read6bDateTime(r io.ByteReader) (_ time.Time, err error) {
|
|
|
|
|
|
// var arr []byte
|
|
|
|
|
|
|
|
|
|
|
|
// for i := 0; i < 6; i++ {
|
|
|
|
|
|
// var b byte
|
|
|
|
|
|
// b, err = r.ReadByte()
|
|
|
|
|
|
// if err != nil {
|
|
|
|
|
|
// return
|
|
|
|
|
|
// }
|
|
|
|
|
|
// arr = append(arr, b)
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
// if bytes.Equal(arr, zeroUnixTime) {
|
|
|
|
|
|
// return time.Unix(0, 0), nil
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
// tm := time.Date(
|
|
|
|
|
|
// int(arr[0])+2000,
|
|
|
|
|
|
// time.Month(arr[1]),
|
|
|
|
|
|
// int(arr[2]),
|
|
|
|
|
|
// int(arr[3]),
|
|
|
|
|
|
// int(arr[4]),
|
|
|
|
|
|
// int(arr[5]),
|
|
|
|
|
|
// 0,
|
|
|
|
|
|
// time.UTC,
|
|
|
|
|
|
// )
|
|
|
|
|
|
// return tm, nil
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
// func Write6bDateTime(w io.Writer, tm time.Time) (err error) {
|
|
|
|
|
|
// var arr []byte
|
|
|
|
|
|
|
|
|
|
|
|
// // ВАЖНО!
|
|
|
|
|
|
// tm = tm.In(time.UTC)
|
|
|
|
|
|
|
|
|
|
|
|
// if tm.Unix() == 0 {
|
|
|
|
|
|
// arr = zeroUnixTime
|
|
|
|
|
|
// } else {
|
|
|
|
|
|
// arr = []byte{
|
|
|
|
|
|
// byte(tm.Year() - 2000),
|
|
|
|
|
|
// byte(tm.Month()),
|
|
|
|
|
|
// byte(tm.Day()),
|
|
|
|
|
|
// byte(tm.Hour()),
|
|
|
|
|
|
// byte(tm.Minute()),
|
|
|
|
|
|
// byte(tm.Second()),
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
|
|
|
|
|
// _, err = w.Write(arr)
|
|
|
|
|
|
// return
|
|
|
|
|
|
// }
|
2022-12-24 17:48:08 +02:00
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
|
MaxUint8 uint64 = 1<<8 - 1
|
|
|
|
|
|
MaxUint16 uint64 = 1<<16 - 1
|
|
|
|
|
|
MaxUint24 uint64 = 1<<24 - 1
|
|
|
|
|
|
MaxUint32 uint64 = 1<<32 - 1
|
|
|
|
|
|
MaxUint40 uint64 = 1<<40 - 1
|
|
|
|
|
|
MaxUint48 uint64 = 1<<48 - 1
|
|
|
|
|
|
MaxUint56 uint64 = 1<<56 - 1
|
|
|
|
|
|
MaxUint64 uint64 = 18446744073709551615
|
|
|
|
|
|
|
|
|
|
|
|
// MaxSafeInt - максимальное целое, которое можно сохранить в переменной
|
|
|
|
|
|
// типа float64 без потери точности
|
|
|
|
|
|
MinSafeInt int64 = -(1 << 53)
|
|
|
|
|
|
MaxSafeInt int64 = 1<<53 - 1
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// WriteMaxSafeUint - кодирует 2**53-1 // LH
|
|
|
|
|
|
func WriteMaxSafeUint(w io.Writer, num uint64, byteOrder ByteOrder) (n int, err error) {
|
|
|
|
|
|
var arr []byte
|
|
|
|
|
|
|
|
|
|
|
|
if num <= MaxUint8 {
|
|
|
|
|
|
arr = []byte{
|
|
|
|
|
|
byte(num),
|
|
|
|
|
|
}
|
|
|
|
|
|
} else if num <= MaxUint16 {
|
|
|
|
|
|
if byteOrder == LH {
|
|
|
|
|
|
arr = []byte{
|
|
|
|
|
|
byte(num),
|
|
|
|
|
|
byte(num >> 8),
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
arr = []byte{
|
|
|
|
|
|
byte(num >> 8),
|
|
|
|
|
|
byte(num),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
} else if num <= MaxUint24 {
|
|
|
|
|
|
if byteOrder == LH {
|
|
|
|
|
|
arr = []byte{
|
|
|
|
|
|
byte(num),
|
|
|
|
|
|
byte(num >> 8),
|
|
|
|
|
|
byte(num >> 16),
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
arr = []byte{
|
|
|
|
|
|
byte(num >> 16),
|
|
|
|
|
|
byte(num >> 8),
|
|
|
|
|
|
byte(num),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
} else if num <= MaxUint32 {
|
|
|
|
|
|
if byteOrder == LH {
|
|
|
|
|
|
arr = []byte{
|
|
|
|
|
|
byte(num),
|
|
|
|
|
|
byte(num >> 8),
|
|
|
|
|
|
byte(num >> 16),
|
|
|
|
|
|
byte(num >> 24),
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
arr = []byte{
|
|
|
|
|
|
byte(num >> 24),
|
|
|
|
|
|
byte(num >> 16),
|
|
|
|
|
|
byte(num >> 8),
|
|
|
|
|
|
byte(num),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
} else if num <= MaxUint40 {
|
|
|
|
|
|
if byteOrder == LH {
|
|
|
|
|
|
arr = []byte{
|
|
|
|
|
|
byte(num),
|
|
|
|
|
|
byte(num >> 8),
|
|
|
|
|
|
byte(num >> 16),
|
|
|
|
|
|
byte(num >> 24),
|
|
|
|
|
|
byte(num >> 32),
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
arr = []byte{
|
|
|
|
|
|
byte(num >> 32),
|
|
|
|
|
|
byte(num >> 24),
|
|
|
|
|
|
byte(num >> 16),
|
|
|
|
|
|
byte(num >> 8),
|
|
|
|
|
|
byte(num),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
} else if num <= MaxUint48 {
|
|
|
|
|
|
if byteOrder == LH {
|
|
|
|
|
|
arr = []byte{
|
|
|
|
|
|
byte(num),
|
|
|
|
|
|
byte(num >> 8),
|
|
|
|
|
|
byte(num >> 16),
|
|
|
|
|
|
byte(num >> 24),
|
|
|
|
|
|
byte(num >> 32),
|
|
|
|
|
|
byte(num >> 40),
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
arr = []byte{
|
|
|
|
|
|
byte(num >> 40),
|
|
|
|
|
|
byte(num >> 32),
|
|
|
|
|
|
byte(num >> 24),
|
|
|
|
|
|
byte(num >> 16),
|
|
|
|
|
|
byte(num >> 8),
|
|
|
|
|
|
byte(num),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
} else if num <= uint64(MaxSafeInt) {
|
|
|
|
|
|
if byteOrder == LH {
|
|
|
|
|
|
arr = []byte{
|
|
|
|
|
|
byte(num),
|
|
|
|
|
|
byte(num >> 8),
|
|
|
|
|
|
byte(num >> 16),
|
|
|
|
|
|
byte(num >> 24),
|
|
|
|
|
|
byte(num >> 32),
|
|
|
|
|
|
byte(num >> 40),
|
|
|
|
|
|
byte(num >> 48),
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
arr = []byte{
|
|
|
|
|
|
byte(num >> 48),
|
|
|
|
|
|
byte(num >> 40),
|
|
|
|
|
|
byte(num >> 32),
|
|
|
|
|
|
byte(num >> 24),
|
|
|
|
|
|
byte(num >> 16),
|
|
|
|
|
|
byte(num >> 8),
|
|
|
|
|
|
byte(num),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
err = fmt.Errorf("num %d > MaxSafeInt %d", num, MaxSafeInt)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return w.Write(arr)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
type SplittedFloat struct {
|
|
|
|
|
|
Int int64 // bin.MaxSafeInt
|
|
|
|
|
|
Frac int64 // до 7 разрядов
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (s SplittedFloat) AsFloat64(fracDigits int) float64 {
|
|
|
|
|
|
//return float64(s.Int) + float64(s.Frac)/ fracMultipliers[fracDigits]
|
|
|
|
|
|
return float64(s.Int) + float64(s.Frac)/math.Pow10(fracDigits)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
var fracMultipliers = []float64{
|
|
|
|
|
|
0,
|
|
|
|
|
|
10,
|
|
|
|
|
|
100,
|
|
|
|
|
|
1000,
|
|
|
|
|
|
10000,
|
|
|
|
|
|
100000,
|
|
|
|
|
|
1000000,
|
|
|
|
|
|
10000000,
|
|
|
|
|
|
100000000,
|
|
|
|
|
|
1000000000,
|
|
|
|
|
|
10000000000,
|
|
|
|
|
|
}
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
var prec = []float64{
|
|
|
|
|
|
0.999999999, // 0
|
|
|
|
|
|
0.99999999, // 1
|
|
|
|
|
|
0.9999999, // 2
|
|
|
|
|
|
0.999999, // 3
|
|
|
|
|
|
0.99999, // 4
|
|
|
|
|
|
0.9999, // 5
|
|
|
|
|
|
0.999, // 6
|
|
|
|
|
|
0.99, // 7
|
|
|
|
|
|
//0.99, // 8
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func SplitFloat(num float64, fracDigits int) SplittedFloat {
|
|
|
|
|
|
var isNegative bool
|
|
|
|
|
|
if num < 0 {
|
|
|
|
|
|
isNegative = true
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
num = math.Abs(num)
|
|
|
|
|
|
//if fracDigits >= len(fracMultipliers) {
|
|
|
|
|
|
// panic(fmt.Sprintf("max fracDigits is %d, not %d\n",
|
|
|
|
|
|
// len(fracMultipliers), fracDigits))
|
|
|
|
|
|
//}
|
|
|
|
|
|
i, f := math.Modf(num)
|
|
|
|
|
|
|
|
|
|
|
|
poweredFrac := f * math.Pow10(fracDigits)
|
|
|
|
|
|
// В этот момент может произойти потеря точности, когда 0.55 превратится
|
|
|
|
|
|
// в 0.5499999999 (в меньшую сторону)
|
|
|
|
|
|
fracAsInt := int64(poweredFrac)
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
dif := poweredFrac - float64(fracAsInt)
|
|
|
|
|
|
//fmt.Printf("DIF %.10f\n\n", dif)
|
|
|
|
|
|
|
|
|
|
|
|
var eps float64
|
|
|
|
|
|
|
|
|
|
|
|
if fracDigits >= len(prec) {
|
|
|
|
|
|
eps = 0.99
|
|
|
|
|
|
} else {
|
|
|
|
|
|
eps = prec[fracDigits]
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if dif > eps {
|
|
|
|
|
|
fracAsInt++
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//fmt.Printf("\nSPLIT: %.10f, int = %d, frac = %v, %v, %d\n\n", num, int(i), f, f*fracMultipliers[fracDigits], int(f*fracMultipliers[fracDigits]))
|
|
|
|
|
|
if isNegative {
|
|
|
|
|
|
i *= -1
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return SplittedFloat{
|
|
|
|
|
|
Int: int64(i),
|
|
|
|
|
|
Frac: fracAsInt,
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
// Round a float to a specific decimal place or precision
|
|
|
|
|
|
func Round(input float64, places int) (rounded float64, err error) {
|
|
|
|
|
|
|
|
|
|
|
|
// If the float is not a number
|
|
|
|
|
|
if math.IsNaN(input) {
|
|
|
|
|
|
return math.NaN(), fmt.Errorf("fuck")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Find out the actual sign and correct the input for later
|
|
|
|
|
|
sign := 1.0
|
|
|
|
|
|
if input < 0 {
|
|
|
|
|
|
sign = -1
|
|
|
|
|
|
input *= -1
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Use the places arg to get the amount of precision wanted
|
|
|
|
|
|
precision := math.Pow(10, float64(places))
|
|
|
|
|
|
|
|
|
|
|
|
// Find the decimal place we are looking to round
|
|
|
|
|
|
digit := input * precision
|
|
|
|
|
|
|
|
|
|
|
|
// Get the actual decimal number as a fraction to be compared
|
|
|
|
|
|
_, decimal := math.Modf(digit)
|
|
|
|
|
|
|
|
|
|
|
|
// If the decimal is less than .5 we round down otherwise up
|
|
|
|
|
|
if decimal >= 0.5 {
|
|
|
|
|
|
rounded = math.Ceil(digit)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
rounded = math.Floor(digit)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Finally we do the math to actually create a rounded number
|
|
|
|
|
|
return rounded / precision * sign, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
2026-07-19 06:29:35 +03:00
|
|
|
|
// FLAGS
|
|
|
|
|
|
|
|
|
|
|
|
func IsSetFlag(flags byte, flag byte) bool {
|
|
|
|
|
|
return (flags & flag) == flag
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func SetFlag(flags byte, flag byte) byte {
|
|
|
|
|
|
return flags | flag
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func UnsetFlag(flags byte, flag byte) byte {
|
|
|
|
|
|
return flags & ^flag
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-12-24 17:48:08 +02:00
|
|
|
|
func UnsetBit(b byte, idx byte) byte {
|
|
|
|
|
|
if ((b >> idx) & 1) == 1 {
|
|
|
|
|
|
// сбрасываем
|
|
|
|
|
|
var mask byte = ^(1 << idx)
|
|
|
|
|
|
return b & mask
|
|
|
|
|
|
}
|
|
|
|
|
|
return b
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func SetBit(b byte, idx byte) byte {
|
|
|
|
|
|
if ((b >> idx) & 1) == 0 {
|
|
|
|
|
|
// устанавливаем
|
|
|
|
|
|
return b | (1 << idx)
|
|
|
|
|
|
}
|
|
|
|
|
|
return b
|
|
|
|
|
|
}
|