167 lines
4 KiB
Go
167 lines
4 KiB
Go
package image
|
|
|
|
import (
|
|
"bufio"
|
|
"compress/gzip"
|
|
"encoding/binary"
|
|
"encoding/hex"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"io/fs"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/codingsince1985/checksum"
|
|
)
|
|
|
|
type ImageReader struct {
|
|
Path string
|
|
Stat fs.FileInfo
|
|
Name string
|
|
Version string
|
|
CheckSum string
|
|
ImgSize uint64
|
|
Reader *gzip.Reader
|
|
HeaderLen uint16
|
|
}
|
|
|
|
type ImageWriter struct {
|
|
Path string
|
|
RawImagePath string
|
|
Name string
|
|
Version string
|
|
CheckSum string
|
|
ImgSize uint64
|
|
Writer *gzip.Writer
|
|
HeaderLen uint16
|
|
file *os.File
|
|
}
|
|
|
|
func CreateImage(path string, rawImgPath string, name string, version string) (ImageWriter, func() error, error) {
|
|
var image ImageWriter
|
|
stat, err := os.Stat(rawImgPath)
|
|
if err != nil {
|
|
return image, func() error { return nil }, err
|
|
}
|
|
rawImgPath, _ = filepath.Abs(rawImgPath)
|
|
file, err := os.Create(path)
|
|
if err != nil {
|
|
return image, func() error { return nil }, err
|
|
}
|
|
path, _ = filepath.Abs(path)
|
|
|
|
checkSum, err := checksum.MD5sum(rawImgPath)
|
|
if err != nil {
|
|
return image, func() error { return nil }, err
|
|
}
|
|
headerLen := uint16(len(name)+len(version)) + 36
|
|
gzWriter := gzip.NewWriter(file)
|
|
|
|
return ImageWriter{
|
|
Path: path,
|
|
RawImagePath: rawImgPath,
|
|
Name: strings.TrimSuffix(name, "\n"),
|
|
Version: strings.TrimSuffix(version, "\n"),
|
|
CheckSum: strings.TrimSuffix(checkSum, "\n"),
|
|
ImgSize: uint64(stat.Size()),
|
|
Writer: gzWriter,
|
|
HeaderLen: headerLen,
|
|
file: file,
|
|
}, file.Close, nil
|
|
}
|
|
|
|
func (i *ImageWriter) WriteMetadata() {
|
|
i.file.Seek(0, io.SeekEnd)
|
|
writer := bufio.NewWriter(i.file)
|
|
|
|
writer.WriteString(fmt.Sprintf("%s\n", strings.ReplaceAll(i.Name, "\n", "")))
|
|
|
|
writer.WriteString(fmt.Sprintf("%s\n", strings.ReplaceAll(i.Version, "\n", "")))
|
|
|
|
checkSumBytes, _ := hex.DecodeString(i.CheckSum)
|
|
writer.Write(checkSumBytes)
|
|
|
|
imgSizeBytes := make([]byte, 8)
|
|
binary.LittleEndian.PutUint64(imgSizeBytes, uint64(i.ImgSize))
|
|
writer.Write(imgSizeBytes)
|
|
|
|
headerLenBytes := make([]byte, 2)
|
|
binary.LittleEndian.PutUint16(headerLenBytes, i.HeaderLen)
|
|
writer.Write(headerLenBytes)
|
|
|
|
writer.Write([]byte{0x4C, 0x4F, 0x4E, 0x49, 0x4D, 0x41, 0x47, 0x45})
|
|
writer.Flush()
|
|
}
|
|
|
|
func ReadImage(path string) (ImageReader, func() error, error) {
|
|
var image ImageReader
|
|
stat, err := os.Stat(path)
|
|
if errors.Is(err, os.ErrNotExist) {
|
|
return image, func() error { return nil }, err
|
|
}
|
|
path, _ = filepath.Abs(path)
|
|
file, err := os.Open(path)
|
|
if err != nil {
|
|
return image, func() error { return nil }, err
|
|
}
|
|
|
|
file.Seek(-8, io.SeekEnd)
|
|
|
|
signatureBytes := make([]byte, 8)
|
|
file.Read(signatureBytes)
|
|
if string(signatureBytes) != "LONIMAGE" {
|
|
return image, func() error { return nil }, errors.New("not a LoN Image")
|
|
}
|
|
|
|
file.Seek(-10, io.SeekEnd)
|
|
offsetBytes := make([]byte, 2)
|
|
file.Read(offsetBytes)
|
|
headerLen := binary.LittleEndian.Uint16(offsetBytes)
|
|
file.Seek(-int64(headerLen), io.SeekEnd)
|
|
|
|
reader := bufio.NewReader(file)
|
|
|
|
name, err := reader.ReadString('\n')
|
|
if err != nil {
|
|
return image, func() error { return nil }, err
|
|
}
|
|
|
|
version, err := reader.ReadString('\n')
|
|
if err != nil {
|
|
return image, func() error { return nil }, err
|
|
}
|
|
|
|
checkSumBytes := make([]byte, 16)
|
|
_, err = reader.Read(checkSumBytes)
|
|
checkSum := hex.EncodeToString(checkSumBytes)
|
|
if err != nil {
|
|
return image, func() error { return nil }, err
|
|
}
|
|
|
|
imgSizeBytes := make([]byte, 8)
|
|
_, err = reader.Read(imgSizeBytes)
|
|
if err != nil {
|
|
return image, func() error { return nil }, err
|
|
}
|
|
imgSize := binary.LittleEndian.Uint64(imgSizeBytes)
|
|
|
|
file.Seek(0, io.SeekStart)
|
|
gzReader, err := gzip.NewReader(file)
|
|
if err != nil {
|
|
return image, func() error { return nil }, err
|
|
}
|
|
|
|
return ImageReader{
|
|
Path: path,
|
|
Stat: stat,
|
|
Name: strings.TrimSuffix(name, "\n"),
|
|
Version: strings.TrimSuffix(version, "\n"),
|
|
CheckSum: strings.TrimSuffix(checkSum, "\n"),
|
|
ImgSize: imgSize,
|
|
Reader: gzReader,
|
|
HeaderLen: headerLen,
|
|
}, file.Close, nil
|
|
}
|