summaryrefslogtreecommitdiff
path: root/pkg/midipak/midipak.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/midipak/midipak.go')
-rw-r--r--pkg/midipak/midipak.go55
1 files changed, 55 insertions, 0 deletions
diff --git a/pkg/midipak/midipak.go b/pkg/midipak/midipak.go
new file mode 100644
index 0000000..19ccde3
--- /dev/null
+++ b/pkg/midipak/midipak.go
@@ -0,0 +1,55 @@
+// midipak implements compressing and appending MIDI flles
+// to a midipak file.
+package midipak
+
+import (
+ "context"
+ "database/sql"
+)
+
+// Encoder compresses each of the input files,
+// and is expected to be goroutine safe.
+type Encoder interface {
+ EncodeAll(src, dst []byte) []byte
+}
+
+// File stores the name and data of a file.
+type File struct {
+ Name string
+ Data []byte
+}
+
+// Create initializes a new midipak.
+func Create(ctx context.Context, db *sql.DB) error {
+ sqlStmt := "CREATE TABLE files (name TEXT PRIMARY KEY, sz INTEGER NOT NULL, data BLOB);"
+
+ _, err := db.ExecContext(ctx, sqlStmt)
+ return err
+}
+
+// Pack appends the files to the midipak, after being compressed
+// with the provided encoder. Attempting to pack files that already
+// exist is an error.
+func Pack(ctx context.Context, db *sql.DB, enc Encoder, files []File) error {
+ tx, err := db.BeginTx(ctx, nil)
+ if err != nil {
+ return err
+ }
+
+ stmt, err := tx.Prepare("INSERT INTO files(name, sz, data) VALUES (?, ?, ?)")
+ if err != nil {
+ return err
+ }
+ defer stmt.Close()
+
+ for _, file := range files {
+ sz := len(file.Data)
+
+ _, err = stmt.Exec(file.Name, sz, enc.EncodeAll(file.Data, make([]byte, 0, sz)))
+ if err != nil {
+ return err
+ }
+ }
+
+ return tx.Commit()
+}