mirror of
https://github.com/garraflavatra/go-fmp.git
synced 2025-06-27 20:15:11 +00:00
Initial commit
This commit is contained in:
9
.editorconfig
Normal file
9
.editorconfig
Normal file
@ -0,0 +1,9 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
.DS_Store
|
||||
private
|
BIN
files/Untitled.fmp12
Normal file
BIN
files/Untitled.fmp12
Normal file
Binary file not shown.
63
fmp/fmp.go
Normal file
63
fmp/fmp.go
Normal file
@ -0,0 +1,63 @@
|
||||
package fmp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
magicSequence = "\x00\x01\x00\x00\x00\x02\x00\x01\x00\x05\x00\x02\x00\x02\xC0"
|
||||
hbamSequence = "HBAM7"
|
||||
|
||||
magicSize = len(magicSequence)
|
||||
hbamSize = len(hbamSequence)
|
||||
sectorSize = 4096
|
||||
)
|
||||
|
||||
type FmpFile struct {
|
||||
Stream io.ReadSeeker
|
||||
VersionDate time.Time
|
||||
ApplicationName string
|
||||
}
|
||||
|
||||
func OpenFile(path string) (*FmpFile, error) {
|
||||
stream, err := os.Open(path)
|
||||
if err != nil {
|
||||
if stream != nil {
|
||||
stream.Close()
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
ctx := &FmpFile{Stream: stream}
|
||||
if err := ctx.readHeader(); err != nil {
|
||||
stream.Close()
|
||||
return nil, err
|
||||
}
|
||||
return ctx, nil
|
||||
}
|
||||
|
||||
func (ctx *FmpFile) readHeader() error {
|
||||
buf := make([]byte, sectorSize)
|
||||
_, err := ctx.Stream.Read(buf)
|
||||
if err != nil {
|
||||
return ErrRead
|
||||
}
|
||||
if !bytes.Equal(buf[:magicSize], []byte(magicSequence)) {
|
||||
return ErrBadMagic
|
||||
}
|
||||
if !bytes.Equal(buf[magicSize:magicSize+hbamSize], []byte(hbamSequence)) {
|
||||
return ErrBadMagic
|
||||
}
|
||||
|
||||
ctx.VersionDate, err = time.Parse("06JAN02", string(buf[531:538]))
|
||||
if err != nil {
|
||||
return ErrBadHeader
|
||||
}
|
||||
|
||||
appNameLength := int(buf[541])
|
||||
ctx.ApplicationName = string(buf[542 : 542+appNameLength])
|
||||
|
||||
return nil
|
||||
}
|
18
fmp/fmp_error.go
Normal file
18
fmp/fmp_error.go
Normal file
@ -0,0 +1,18 @@
|
||||
package fmp
|
||||
|
||||
type FmpError string
|
||||
|
||||
func (e FmpError) Error() string { return string(e) }
|
||||
|
||||
var (
|
||||
ErrRead = FmpError("read error")
|
||||
ErrBadMagic = FmpError("bad magic number")
|
||||
ErrBadHeader = FmpError("bad header")
|
||||
ErrUnsupportedCharset = FmpError("unsupported character set")
|
||||
ErrBadSectorCount = FmpError("bad sector count")
|
||||
ErrNoFmemopen = FmpError("no fmemopen")
|
||||
ErrOpen = FmpError("could not open file")
|
||||
ErrSeek = FmpError("seek failed")
|
||||
ErrMalloc = FmpError("malloc failed")
|
||||
ErrUserAborted = FmpError("user aborted")
|
||||
)
|
16
fmp/fmp_test.go
Normal file
16
fmp/fmp_test.go
Normal file
@ -0,0 +1,16 @@
|
||||
package fmp
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestOpenFile(t *testing.T) {
|
||||
f, err := OpenFile("../files/Untitled.fmp12")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if f.ApplicationName != "Pro 12.0" {
|
||||
t.Errorf("expected application name to be 'Pro 12.0', got '%s'", f.ApplicationName)
|
||||
}
|
||||
if f.VersionDate.Format("2006-01-02") != "2025-01-11" {
|
||||
t.Errorf("expected version date to be '2025-01-11', got '%s'", f.VersionDate.Format("2006-01-02"))
|
||||
}
|
||||
}
|
7
go.mod
Normal file
7
go.mod
Normal file
@ -0,0 +1,7 @@
|
||||
module fmp
|
||||
|
||||
go 1.23.0
|
||||
|
||||
toolchain go1.23.10
|
||||
|
||||
require golang.org/x/text v0.26.0
|
Reference in New Issue
Block a user