2022-01-28 18:25:52 +00:00
|
|
|
package izapple2
|
2019-06-01 18:06:44 +00:00
|
|
|
|
|
|
|
import (
|
2020-11-02 18:14:14 +00:00
|
|
|
"archive/zip"
|
|
|
|
"bytes"
|
|
|
|
"compress/gzip"
|
2022-01-28 18:25:52 +00:00
|
|
|
"embed"
|
2019-06-01 18:06:44 +00:00
|
|
|
"io"
|
|
|
|
"io/ioutil"
|
2019-07-07 15:40:29 +00:00
|
|
|
"net/http"
|
2019-06-01 18:06:44 +00:00
|
|
|
"os"
|
|
|
|
"strings"
|
|
|
|
|
2022-01-28 18:25:52 +00:00
|
|
|
"github.com/ivanizag/izapple2/storage"
|
2019-06-01 18:06:44 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
internalPrefix = "<internal>/"
|
2022-01-28 18:25:52 +00:00
|
|
|
embedPrefix = "resources/"
|
2019-07-07 15:40:29 +00:00
|
|
|
httpPrefix = "http://"
|
|
|
|
httpsPrefix = "https://"
|
2019-06-01 18:06:44 +00:00
|
|
|
)
|
|
|
|
|
2022-01-28 18:25:52 +00:00
|
|
|
//go:embed resources
|
|
|
|
var internalFiles embed.FS
|
|
|
|
|
2019-06-09 21:54:27 +00:00
|
|
|
func isInternalResource(filename string) bool {
|
|
|
|
return strings.HasPrefix(filename, internalPrefix)
|
|
|
|
}
|
|
|
|
|
2019-07-07 15:40:29 +00:00
|
|
|
func isHTTPResource(filename string) bool {
|
|
|
|
return strings.HasPrefix(filename, httpPrefix) ||
|
|
|
|
strings.HasPrefix(filename, httpsPrefix)
|
|
|
|
}
|
|
|
|
|
2020-10-17 18:10:48 +00:00
|
|
|
// LoadResource loads in memory a file from the filesystem, http or embedded
|
2020-11-03 16:51:12 +00:00
|
|
|
func LoadResource(filename string) ([]uint8, bool, error) {
|
|
|
|
var writeable bool
|
2019-06-01 18:06:44 +00:00
|
|
|
var file io.Reader
|
2019-06-09 21:54:27 +00:00
|
|
|
if isInternalResource(filename) {
|
2019-06-01 18:06:44 +00:00
|
|
|
// load from embedded resource
|
2022-01-28 18:25:52 +00:00
|
|
|
resource := embedPrefix + strings.TrimPrefix(filename, internalPrefix)
|
|
|
|
resourceFile, err := internalFiles.Open(resource)
|
2019-06-01 18:06:44 +00:00
|
|
|
if err != nil {
|
2020-11-03 16:51:12 +00:00
|
|
|
return nil, false, err
|
2019-06-01 18:06:44 +00:00
|
|
|
}
|
|
|
|
defer resourceFile.Close()
|
|
|
|
file = resourceFile
|
2020-11-03 16:51:12 +00:00
|
|
|
writeable = false
|
2019-07-07 15:40:29 +00:00
|
|
|
|
|
|
|
} else if isHTTPResource(filename) {
|
|
|
|
response, err := http.Get(filename)
|
|
|
|
if err != nil {
|
2020-11-03 16:51:12 +00:00
|
|
|
return nil, false, err
|
2019-07-07 15:40:29 +00:00
|
|
|
}
|
|
|
|
defer response.Body.Close()
|
|
|
|
file = response.Body
|
2020-11-03 16:51:12 +00:00
|
|
|
writeable = false
|
2019-07-07 15:40:29 +00:00
|
|
|
|
2019-06-01 18:06:44 +00:00
|
|
|
} else {
|
|
|
|
diskFile, err := os.Open(filename)
|
|
|
|
if err != nil {
|
2020-11-03 16:51:12 +00:00
|
|
|
return nil, false, err
|
2019-06-01 18:06:44 +00:00
|
|
|
}
|
|
|
|
defer diskFile.Close()
|
|
|
|
file = diskFile
|
2020-11-03 16:51:12 +00:00
|
|
|
writeable = true
|
2019-06-01 18:06:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
data, err := ioutil.ReadAll(file)
|
|
|
|
if err != nil {
|
2020-11-03 16:51:12 +00:00
|
|
|
return nil, false, err
|
2019-06-01 18:06:44 +00:00
|
|
|
}
|
2020-11-02 18:14:14 +00:00
|
|
|
|
|
|
|
contentType := http.DetectContentType(data)
|
|
|
|
if contentType == "application/x-gzip" {
|
2020-11-03 16:51:12 +00:00
|
|
|
writeable = false
|
2020-11-02 18:14:14 +00:00
|
|
|
gz, err := gzip.NewReader(bytes.NewReader(data))
|
|
|
|
if err != nil {
|
2020-11-03 16:51:12 +00:00
|
|
|
return nil, false, err
|
2020-11-02 18:14:14 +00:00
|
|
|
}
|
|
|
|
defer gz.Close()
|
|
|
|
data, err = ioutil.ReadAll(gz)
|
|
|
|
if err != nil {
|
2020-11-03 16:51:12 +00:00
|
|
|
return nil, false, err
|
2020-11-02 18:14:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} else if contentType == "application/zip" {
|
2020-11-03 16:51:12 +00:00
|
|
|
writeable = false
|
2020-11-02 18:14:14 +00:00
|
|
|
z, err := zip.NewReader(bytes.NewReader(data), int64(len(data)))
|
|
|
|
if err != nil {
|
2020-11-03 16:51:12 +00:00
|
|
|
return nil, false, err
|
2020-11-02 18:14:14 +00:00
|
|
|
}
|
|
|
|
for _, zf := range z.File {
|
|
|
|
f, err := zf.Open()
|
|
|
|
if err != nil {
|
2020-11-03 16:51:12 +00:00
|
|
|
return nil, false, err
|
2020-11-02 18:14:14 +00:00
|
|
|
}
|
|
|
|
defer f.Close()
|
|
|
|
bytes, err := ioutil.ReadAll(f)
|
|
|
|
if err != nil {
|
2020-11-03 16:51:12 +00:00
|
|
|
return nil, false, err
|
2020-11-02 18:14:14 +00:00
|
|
|
}
|
2022-01-28 18:25:52 +00:00
|
|
|
if storage.IsDiskette(bytes) {
|
2020-11-02 18:14:14 +00:00
|
|
|
data = bytes
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-03 16:51:12 +00:00
|
|
|
return data, writeable, nil
|
2019-06-01 18:06:44 +00:00
|
|
|
}
|
2022-01-28 18:25:52 +00:00
|
|
|
|
|
|
|
// LoadDiskette returns a Diskette by detecting the format
|
|
|
|
func LoadDiskette(filename string) (storage.Diskette, error) {
|
|
|
|
data, writeable, err := LoadResource(filename)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return storage.MakeDiskette(data, filename, writeable)
|
|
|
|
}
|