v3 candidate
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
package binsnoop
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"hash/crc32"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
const MaxFileReadBytes int64 = 64 << 20
|
||||
|
||||
// CRC32 calculates the CRC32 checksum using the IEEE polynomial.
|
||||
func CRC32(data []byte) uint32 {
|
||||
return crc32.ChecksumIEEE(data)
|
||||
}
|
||||
|
||||
// EpochToString converts a Unix timestamp to a formatted time string.
|
||||
func EpochToString(epoch uint32) string {
|
||||
t := time.Unix(int64(epoch), 0).UTC()
|
||||
return t.Format("2006-01-02 15:04:05")
|
||||
}
|
||||
|
||||
// GetCString extracts a NULL-terminated C string from raw bytes.
|
||||
func GetCString(data []byte) string {
|
||||
for i, b := range data {
|
||||
if b == 0 {
|
||||
s := string(data[:i])
|
||||
// Validate UTF-8 printability
|
||||
for _, c := range s {
|
||||
if c == 0 {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
return s
|
||||
}
|
||||
}
|
||||
return string(data)
|
||||
}
|
||||
|
||||
// IsASCIINumber returns true if the byte is an ASCII digit (0-9).
|
||||
func IsASCIINumber(b byte) bool {
|
||||
return b >= '0' && b <= '9'
|
||||
}
|
||||
|
||||
// IsPrintableASCII returns true if the byte is a printable ASCII character.
|
||||
func IsPrintableASCII(b byte) bool {
|
||||
return b >= 0x0A && b <= 0x7E
|
||||
}
|
||||
|
||||
// IsOffsetSafe validates that the next offset is within bounds and progressing forward.
|
||||
func IsOffsetSafe(availableData, nextOffset int, lastOffset *int) bool {
|
||||
if lastOffset != nil {
|
||||
if *lastOffset >= nextOffset {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return nextOffset < availableData
|
||||
}
|
||||
|
||||
// ReadFile reads a bounded file into memory for scanner APIs that require a
|
||||
// byte slice. Larger callers should use a streaming document path.
|
||||
func ReadFile(path string) ([]byte, error) {
|
||||
return ReadFileLimited(path, MaxFileReadBytes)
|
||||
}
|
||||
|
||||
func ReadFileLimited(path string, maxBytes int64) ([]byte, error) {
|
||||
info, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if info.IsDir() {
|
||||
return nil, fmt.Errorf("binsnoop: path is a directory")
|
||||
}
|
||||
if maxBytes > 0 && info.Size() > maxBytes {
|
||||
return nil, fmt.Errorf("binsnoop: file is too large: %d bytes exceeds %d bytes", info.Size(), maxBytes)
|
||||
}
|
||||
return os.ReadFile(path)
|
||||
}
|
||||
|
||||
// LE16 reads a little-endian uint16 from data at the given offset.
|
||||
func LE16(data []byte, offset int) uint16 {
|
||||
if offset+2 > len(data) {
|
||||
return 0
|
||||
}
|
||||
return binary.LittleEndian.Uint16(data[offset:])
|
||||
}
|
||||
|
||||
// BE16 reads a big-endian uint16 from data at the given offset.
|
||||
func BE16(data []byte, offset int) uint16 {
|
||||
if offset+2 > len(data) {
|
||||
return 0
|
||||
}
|
||||
return binary.BigEndian.Uint16(data[offset:])
|
||||
}
|
||||
|
||||
// LE32 reads a little-endian uint32 from data at the given offset.
|
||||
func LE32(data []byte, offset int) uint32 {
|
||||
if offset+4 > len(data) {
|
||||
return 0
|
||||
}
|
||||
return binary.LittleEndian.Uint32(data[offset:])
|
||||
}
|
||||
|
||||
// BE32 reads a big-endian uint32 from data at the given offset.
|
||||
func BE32(data []byte, offset int) uint32 {
|
||||
if offset+4 > len(data) {
|
||||
return 0
|
||||
}
|
||||
return binary.BigEndian.Uint32(data[offset:])
|
||||
}
|
||||
|
||||
// LE64 reads a little-endian uint64 from data at the given offset.
|
||||
func LE64(data []byte, offset int) uint64 {
|
||||
if offset+8 > len(data) {
|
||||
return 0
|
||||
}
|
||||
return binary.LittleEndian.Uint64(data[offset:])
|
||||
}
|
||||
|
||||
// BE64 reads a big-endian uint64 from data at the given offset.
|
||||
func BE64(data []byte, offset int) uint64 {
|
||||
if offset+8 > len(data) {
|
||||
return 0
|
||||
}
|
||||
return binary.BigEndian.Uint64(data[offset:])
|
||||
}
|
||||
Reference in New Issue
Block a user