From 1f23e7217fe27454a3944735b0b8d9ec24d17282 Mon Sep 17 00:00:00 2001 From: JetSetIlly Date: Sun, 14 Apr 2024 08:35:02 +0100 Subject: [PATCH] simplified cartridge loader package loader is opened at creation time which allows us to remove the needlessly complicated pointer-to-pointer mechanism --- cartridgeloader/loader.go | 161 +++++++----------- gui/sdlimgui/win_rom_select.go | 4 +- hardware/memory/cartridge/cartridge.go | 68 ++++---- hardware/memory/cartridge/fingerprint.go | 56 +++--- .../memory/cartridge/supercharger/fastload.go | 8 +- hardware/peripherals/fingerprint.go | 14 +- hardware/vcs.go | 2 +- recorder/fileformat.go | 4 +- resources/fs/fs.go | 6 - 9 files changed, 129 insertions(+), 194 deletions(-) diff --git a/cartridgeloader/loader.go b/cartridgeloader/loader.go index 5e3bafc4..b4183756 100644 --- a/cartridgeloader/loader.go +++ b/cartridgeloader/loader.go @@ -28,67 +28,45 @@ import ( "path/filepath" "slices" "strings" - - "github.com/jetsetilly/gopher2600/hardware/television/specification" - "github.com/jetsetilly/gopher2600/logger" - "github.com/jetsetilly/gopher2600/resources/fs" ) // Loader abstracts all the ways data can be loaded into the emulation. type Loader struct { io.ReadSeeker - // the name to use for the cartridge represented by Loader + // the name to use for the cartridge. in the case of embedded data the name + // will be the name provided to the NewLoaderFromData() function Name string - // filename of cartridge being loaded. In the case of embedded data, this - // field will contain the name of the data provided to the the - // NewLoaderFromEmbed() function. + // filename of cartridge being loaded. this is the absolute path that was + // used to load the cartridge + // + // in the case of embedded data the filename will be the name provided to + // the NewLoaderFromData() function + // + // use of the Filename can be useful, for example, for checking if the TV + // specification is indicated Filename string // empty string or "AUTO" indicates automatic fingerprinting Mapping string - // any detected TV spec in the filename. will be the empty string if - // nothing is found. note that the empty string is treated like "AUTO" by - // television.SetSpec(). - TelevisionSpec string - - // expected hash of the loaded cartridge. empty string indicates that the - // hash is unknown and need not be validated. after a load operation the - // value will be the hash of the loaded data - // - // in the case of sound data (IsSoundData is true) then the hash is of the - // original binary file not he decoded PCM data - // - // the value of HashSHA1 will be checked on a call to Loader.Load(). if the - // string is empty then that check passes. + // hashes of data. will be empty if data is being streamed HashSHA1 string - - // HashMD5 is an alternative to hash for use with the properties package - HashMD5 string + HashMD5 string // does the Data field consist of sound (PCM) data IsSoundData bool - // cartridge data. empty until Load() is called unless the loader was - // created by NewLoaderFromEmbed() - // - // the pointer-to-a-slice construct allows the cartridge to be - // loaded/changed by a Loader instance that has been passed by value. - Data *[]byte + // cartridge data + Data []byte data *bytes.Buffer - // if stream is nil then the data will not be streamed. if *stream is nil - // then the stream is not open - // - // (this is a tricky construct but it allows an instance of Loader to be - // passed by value but still be able to close an opened stream at an - // "earlier" point in the code) - stream **os.File + // if stream is nil then the data is not streamed + stream *os.File - // whether the Loader was created with NewLoaderFromData() + // data was supplied through NewLoaderFromData() embedded bool } @@ -112,20 +90,20 @@ var NoFilename = errors.New("no filename") // mixture of both. // // Filenames can contain whitespace, including leading and trailing whitespace, -// but cannot consists only of whitespace. +// but cannot consist only of whitespace. func NewLoaderFromFilename(filename string, mapping string) (Loader, error) { // check filename but don't change it. we don't want to allow the empty // string or a string only consisting of whitespace, but we *do* want to // allow filenames with leading/trailing spaces if strings.TrimSpace(filename) == "" { - return Loader{}, fmt.Errorf("catridgeloader: %w", NoFilename) + return Loader{}, fmt.Errorf("loader: %w", NoFilename) } // absolute path of filename var err error - filename, err = fs.Abs(filename) + filename, err = filepath.Abs(filename) if err != nil { - return Loader{}, fmt.Errorf("catridgeloader: %w", err) + return Loader{}, fmt.Errorf("loader: %w", err) } mapping = strings.TrimSpace(strings.ToUpper(mapping)) @@ -138,10 +116,6 @@ func NewLoaderFromFilename(filename string, mapping string) (Loader, error) { Mapping: mapping, } - // create an empty slice for the Data field to refer to - data := make([]byte, 0) - ld.Data = &data - // decide what mapping to use if the requested mapping is AUTO if mapping == "AUTO" { extension := strings.ToUpper(filepath.Ext(filename)) @@ -160,7 +134,7 @@ func NewLoaderFromFilename(filename string, mapping string) (Loader, error) { if ld.Mapping == "AUTO" { ok, err := miniFingerprintMovieCart(filename) if err != nil { - return Loader{}, fmt.Errorf("catridgeloader: %w", err) + return Loader{}, fmt.Errorf("loader: %w", err) } if ok { ld.Mapping = "MVC" @@ -170,11 +144,13 @@ func NewLoaderFromFilename(filename string, mapping string) (Loader, error) { // create stream pointer only for streaming sources. these file formats are // likely to be very large by comparison to regular cartridge files. if ld.Mapping == "MVC" || (ld.Mapping == "AR" && ld.IsSoundData) { - ld.stream = new(*os.File) + err = ld.openStream() + } else { + err = ld.open() + } + if err != nil { + return Loader{}, fmt.Errorf("loader: %w", err) } - - // check filename for information about the TV specifction - ld.TelevisionSpec = specification.SearchSpec(filename) // decide on the name for this cartridge ld.Name = decideOnName(ld) @@ -193,12 +169,12 @@ func NewLoaderFromFilename(filename string, mapping string) (Loader, error) { // used. func NewLoaderFromData(name string, data []byte, mapping string) (Loader, error) { if len(data) == 0 { - return Loader{}, fmt.Errorf("catridgeloader: emebedded data is empty") + return Loader{}, fmt.Errorf("loader: emebedded data is empty") } name = strings.TrimSpace(name) if name == "" { - return Loader{}, fmt.Errorf("catridgeloader: no name for embedded data") + return Loader{}, fmt.Errorf("loader: no name for embedded data") } mapping = strings.TrimSpace(strings.ToUpper(mapping)) @@ -209,11 +185,11 @@ func NewLoaderFromData(name string, data []byte, mapping string) (Loader, error) ld := Loader{ Filename: name, Mapping: mapping, - Data: &data, + Data: data, data: bytes.NewBuffer(data), - embedded: true, HashSHA1: fmt.Sprintf("%x", sha1.Sum(data)), HashMD5: fmt.Sprintf("%x", md5.Sum(data)), + embedded: true, } // decide on the name for this cartridge @@ -226,16 +202,15 @@ func NewLoaderFromData(name string, data []byte, mapping string) (Loader, error) // // Implements the io.Closer interface. func (ld Loader) Close() error { - if ld.stream == nil || *ld.stream == nil { + if ld.stream == nil { return nil } - err := (**ld.stream).Close() - *ld.stream = nil + err := ld.stream.Close() + ld.stream = nil if err != nil { return fmt.Errorf("loader: %w", err) } - logger.Logf("loader", "stream closed (%s)", ld.Filename) return nil } @@ -245,49 +220,36 @@ func (ld Loader) Read(p []byte) (int, error) { if ld.stream == nil { return ld.data.Read(p) } - - if *ld.stream == nil { - return 0, nil - } - return (*ld.stream).Read(p) } // Implements the io.Seeker interface. func (ld Loader) Seek(offset int64, whence int) (int64, error) { - if ld.stream == nil || *ld.stream == nil { + if ld.stream == nil { return 0, nil } return (*ld.stream).Seek(offset, whence) } -// Open the cartridge data. Loader filenames with a valid schema will use that -// method to load the data. Currently supported schemes are HTTP and local -// files. -func (ld *Loader) Open() error { - // data is already "opened" when using embedded data - if ld.embedded { - return nil +// open the cartridge data for streaming +func (ld *Loader) openStream() error { + err := ld.Close() + if err != nil { + return fmt.Errorf("loader: %w", err) } - if ld.stream != nil { - err := ld.Close() - if err != nil { - return fmt.Errorf("loader: %w", err) - } - - *ld.stream, err = os.Open(ld.Filename) - if err != nil { - return fmt.Errorf("loader: %w", err) - } - logger.Logf("loader", "stream open (%s)", ld.Filename) - - return nil + ld.stream, err = os.Open(ld.Filename) + if err != nil { + return fmt.Errorf("loader: %w", err) } - if ld.Data != nil && len(*ld.Data) > 0 { - return nil - } + return nil +} + +// open the cartridge data. filenames with a valid schema will use that method +// to load the data. currently supported schemes are HTTP and local files. +func (ld *Loader) open() error { + ld.Data = make([]byte, 0) scheme := "file" @@ -306,7 +268,7 @@ func (ld *Loader) Open() error { } defer resp.Body.Close() - *ld.Data, err = io.ReadAll(resp.Body) + ld.Data, err = io.ReadAll(resp.Body) if err != nil { return fmt.Errorf("loader: %w", err) } @@ -324,26 +286,17 @@ func (ld *Loader) Open() error { } defer f.Close() - *ld.Data, err = io.ReadAll(f) + ld.Data, err = io.ReadAll(f) if err != nil { return fmt.Errorf("loader: %w", err) } } - ld.data = bytes.NewBuffer(*ld.Data) + ld.data = bytes.NewBuffer(ld.Data) - // generate hashes and check for consistency - hash := fmt.Sprintf("%x", sha1.Sum(*ld.Data)) - if ld.HashSHA1 != "" && ld.HashSHA1 != hash { - return fmt.Errorf("loader: unexpected SHA1 hash value") - } - ld.HashSHA1 = hash - - hash = fmt.Sprintf("%x", md5.Sum(*ld.Data)) - if ld.HashMD5 != "" && ld.HashMD5 != hash { - return fmt.Errorf("loader: unexpected MD5 hash value") - } - ld.HashMD5 = hash + // generate hashes + ld.HashSHA1 = fmt.Sprintf("%x", sha1.Sum(ld.Data)) + ld.HashMD5 = fmt.Sprintf("%x", md5.Sum(ld.Data)) return nil } diff --git a/gui/sdlimgui/win_rom_select.go b/gui/sdlimgui/win_rom_select.go index e15ef763..b1389614 100644 --- a/gui/sdlimgui/win_rom_select.go +++ b/gui/sdlimgui/win_rom_select.go @@ -666,9 +666,7 @@ func (win *winSelectROM) setSelectedFile(filename string) { // push function to emulation goroutine. result will be checked for in // draw() function - if err := loader.Open(); err == nil { - win.img.dbg.PushPropertyLookup(loader.HashMD5, win.propertyResult) - } + win.img.dbg.PushPropertyLookup(loader.HashMD5, win.propertyResult) // create thumbnail animation win.thmb.Create(loader, thumbnailer.UndefinedNumFrames, true) diff --git a/hardware/memory/cartridge/cartridge.go b/hardware/memory/cartridge/cartridge.go index df9fc548..83a0f8c0 100644 --- a/hardware/memory/cartridge/cartridge.go +++ b/hardware/memory/cartridge/cartridge.go @@ -182,10 +182,7 @@ func (cart *Cartridge) IsEjected() bool { // "Cart Information" document [sizes.txt]. Other sources of information noted // as appropriate. func (cart *Cartridge) Attach(cartload cartridgeloader.Loader) error { - err := cartload.Open() - if err != nil { - return err - } + var err error cart.Filename = cartload.Filename cart.ShortName = cartload.Name @@ -257,50 +254,50 @@ func (cart *Cartridge) Attach(cartload cartridgeloader.Loader) error { mapping := strings.ToUpper(cartload.Mapping) switch mapping { case "2K": - cart.mapper, err = newAtari2k(cart.env, *cartload.Data) + cart.mapper, err = newAtari2k(cart.env, cartload.Data) case "4K": - cart.mapper, err = newAtari4k(cart.env, *cartload.Data) + cart.mapper, err = newAtari4k(cart.env, cartload.Data) case "F8": - cart.mapper, err = newAtari8k(cart.env, *cartload.Data) + cart.mapper, err = newAtari8k(cart.env, cartload.Data) case "F6": - cart.mapper, err = newAtari16k(cart.env, *cartload.Data) + cart.mapper, err = newAtari16k(cart.env, cartload.Data) case "F4": - cart.mapper, err = newAtari32k(cart.env, *cartload.Data) + cart.mapper, err = newAtari32k(cart.env, cartload.Data) case "2KSC": - cart.mapper, err = newAtari2k(cart.env, *cartload.Data) + cart.mapper, err = newAtari2k(cart.env, cartload.Data) forceSuperchip = true case "4KSC": - cart.mapper, err = newAtari4k(cart.env, *cartload.Data) + cart.mapper, err = newAtari4k(cart.env, cartload.Data) forceSuperchip = true case "F8SC": - cart.mapper, err = newAtari8k(cart.env, *cartload.Data) + cart.mapper, err = newAtari8k(cart.env, cartload.Data) forceSuperchip = true case "F6SC": - cart.mapper, err = newAtari16k(cart.env, *cartload.Data) + cart.mapper, err = newAtari16k(cart.env, cartload.Data) forceSuperchip = true case "F4SC": - cart.mapper, err = newAtari32k(cart.env, *cartload.Data) + cart.mapper, err = newAtari32k(cart.env, cartload.Data) forceSuperchip = true case "CV": - cart.mapper, err = newCommaVid(cart.env, *cartload.Data) + cart.mapper, err = newCommaVid(cart.env, cartload.Data) case "FA": - cart.mapper, err = newCBS(cart.env, *cartload.Data) + cart.mapper, err = newCBS(cart.env, cartload.Data) case "FE": - cart.mapper, err = newSCABS(cart.env, *cartload.Data) + cart.mapper, err = newSCABS(cart.env, cartload.Data) case "E0": - cart.mapper, err = newParkerBros(cart.env, *cartload.Data) + cart.mapper, err = newParkerBros(cart.env, cartload.Data) case "E7": - cart.mapper, err = newMnetwork(cart.env, *cartload.Data) + cart.mapper, err = newMnetwork(cart.env, cartload.Data) case "3F": - cart.mapper, err = newTigervision(cart.env, *cartload.Data) + cart.mapper, err = newTigervision(cart.env, cartload.Data) case "UA": - cart.mapper, err = newUA(cart.env, *cartload.Data) + cart.mapper, err = newUA(cart.env, cartload.Data) case "AR": cart.mapper, err = supercharger.NewSupercharger(cart.env, cartload) case "DF": - cart.mapper, err = newDF(cart.env, *cartload.Data) + cart.mapper, err = newDF(cart.env, cartload.Data) case "3E": - cart.mapper, err = new3e(cart.env, *cartload.Data) + cart.mapper, err = new3e(cart.env, cartload.Data) case "E3P": // synonym for 3E+ fallthrough @@ -308,22 +305,22 @@ func (cart *Cartridge) Attach(cartload cartridgeloader.Loader) error { // synonym for 3E+ fallthrough case "3E+": - cart.mapper, err = new3ePlus(cart.env, *cartload.Data) + cart.mapper, err = new3ePlus(cart.env, cartload.Data) case "EF": - cart.mapper, err = newEF(cart.env, *cartload.Data) + cart.mapper, err = newEF(cart.env, cartload.Data) case "EFSC": - cart.mapper, err = newEF(cart.env, *cartload.Data) + cart.mapper, err = newEF(cart.env, cartload.Data) forceSuperchip = true case "SB": - cart.mapper, err = newSuperbank(cart.env, *cartload.Data) + cart.mapper, err = newSuperbank(cart.env, cartload.Data) case "WD": - cart.mapper, err = newWicksteadDesign(cart.env, *cartload.Data) + cart.mapper, err = newWicksteadDesign(cart.env, cartload.Data) case "ACE": - cart.mapper, err = ace.NewAce(cart.env, *cartload.Data) + cart.mapper, err = ace.NewAce(cart.env, cartload.Data) case "DPC": - cart.mapper, err = newDPC(cart.env, *cartload.Data) + cart.mapper, err = newDPC(cart.env, cartload.Data) case "DPC+": - cart.mapper, err = dpcplus.NewDPCplus(cart.env, *cartload.Data) + cart.mapper, err = dpcplus.NewDPCplus(cart.env, cartload.Data) case "CDF": // CDF defaults to CDFJ @@ -336,7 +333,7 @@ func (cart *Cartridge) Attach(cartload cartridgeloader.Loader) error { case "CDFJ": fallthrough case "CDFJ+": - cart.mapper, err = cdf.NewCDF(cart.env, mapping, *cartload.Data) + cart.mapper, err = cdf.NewCDF(cart.env, mapping, cartload.Data) case "MVC": cart.mapper, err = moviecart.NewMoviecart(cart.env, cartload) @@ -401,14 +398,9 @@ func (cart *Cartridge) Step(clock float32) { // emulation. func (cart *Cartridge) HotLoad(cartload cartridgeloader.Loader) error { if hl, ok := cart.mapper.(mapper.CartHotLoader); ok { - err := cartload.Open() - if err != nil { - return err - } - cart.Hash = cartload.HashSHA1 - err = hl.HotLoad(*cartload.Data) + err := hl.HotLoad(cartload.Data) if err != nil { return err } diff --git a/hardware/memory/cartridge/fingerprint.go b/hardware/memory/cartridge/fingerprint.go index 252c660b..4b106c6d 100644 --- a/hardware/memory/cartridge/fingerprint.go +++ b/hardware/memory/cartridge/fingerprint.go @@ -277,7 +277,7 @@ func fingerprintCDF(b []byte) (bool, string) { } func fingerprintSuperchargerFastLoad(cartload cartridgeloader.Loader) bool { - return len(*cartload.Data) > 0 && len(*cartload.Data)%8448 == 0 + return len(cartload.Data) > 0 && len(cartload.Data)%8448 == 0 } func fingerprintTigervision(b []byte) bool { @@ -369,32 +369,32 @@ func (cart *Cartridge) fingerprint(cartload cartridgeloader.Loader) error { // loading the entire file into memory, which we definitely don't want to do // with moviecart files due to the large size - if ok := fingerprintElf(*cartload.Data, false); ok { + if ok := fingerprintElf(cartload.Data, false); ok { cart.mapper, err = elf.NewElf(cart.env, cart.Filename, false) return err } - if ok, wrappedElf := fingerprintAce(*cartload.Data); ok { + if ok, wrappedElf := fingerprintAce(cartload.Data); ok { if wrappedElf { cart.mapper, err = elf.NewElf(cart.env, cart.Filename, true) return err } - cart.mapper, err = ace.NewAce(cart.env, *cartload.Data) + cart.mapper, err = ace.NewAce(cart.env, cartload.Data) return err } - if ok, version := fingerprintCDFJplus(*cartload.Data); ok { - cart.mapper, err = cdf.NewCDF(cart.env, version, *cartload.Data) + if ok, version := fingerprintCDFJplus(cartload.Data); ok { + cart.mapper, err = cdf.NewCDF(cart.env, version, cartload.Data) return err } - if ok, version := fingerprintCDF(*cartload.Data); ok { - cart.mapper, err = cdf.NewCDF(cart.env, version, *cartload.Data) + if ok, version := fingerprintCDF(cartload.Data); ok { + cart.mapper, err = cdf.NewCDF(cart.env, version, cartload.Data) return err } - if fingerprintDPCplus(*cartload.Data) { - cart.mapper, err = dpcplus.NewDPCplus(cart.env, *cartload.Data) + if fingerprintDPCplus(cartload.Data) { + cart.mapper, err = dpcplus.NewDPCplus(cart.env, cartload.Data) return err } @@ -403,20 +403,20 @@ func (cart *Cartridge) fingerprint(cartload cartridgeloader.Loader) error { return err } - if fingerprint3ePlus(*cartload.Data) { - cart.mapper, err = new3ePlus(cart.env, *cartload.Data) + if fingerprint3ePlus(cartload.Data) { + cart.mapper, err = new3ePlus(cart.env, cartload.Data) return err } - if fingerprint3e(*cartload.Data) { - cart.mapper, err = new3e(cart.env, *cartload.Data) + if fingerprint3e(cartload.Data) { + cart.mapper, err = new3e(cart.env, cartload.Data) return err } - sz := len(*cartload.Data) + sz := len(cartload.Data) switch sz { case 4096: - cart.mapper, err = newAtari4k(cart.env, *cartload.Data) + cart.mapper, err = newAtari4k(cart.env, cartload.Data) if err != nil { return err } @@ -429,7 +429,7 @@ func (cart *Cartridge) fingerprint(cartload cartridgeloader.Loader) error { fallthrough case 8192: - cart.mapper, err = fingerprint8k(*cartload.Data)(cart.env, *cartload.Data) + cart.mapper, err = fingerprint8k(cartload.Data)(cart.env, cartload.Data) if err != nil { return err } @@ -438,53 +438,53 @@ func (cart *Cartridge) fingerprint(cartload cartridgeloader.Loader) error { fallthrough case 10495: - cart.mapper, err = newDPC(cart.env, *cartload.Data) + cart.mapper, err = newDPC(cart.env, cartload.Data) if err != nil { return err } case 12288: - cart.mapper, err = newCBS(cart.env, *cartload.Data) + cart.mapper, err = newCBS(cart.env, cartload.Data) if err != nil { return err } case 16384: - cart.mapper, err = fingerprint16k(*cartload.Data)(cart.env, *cartload.Data) + cart.mapper, err = fingerprint16k(cartload.Data)(cart.env, cartload.Data) if err != nil { return err } case 32768: - cart.mapper, err = fingerprint32k(*cartload.Data)(cart.env, *cartload.Data) + cart.mapper, err = fingerprint32k(cartload.Data)(cart.env, cartload.Data) if err != nil { return err } case 65536: - cart.mapper, err = fingerprint64k(*cartload.Data)(cart.env, *cartload.Data) + cart.mapper, err = fingerprint64k(cartload.Data)(cart.env, cartload.Data) if err != nil { return err } case 131072: - cart.mapper, err = fingerprint128k(*cartload.Data)(cart.env, *cartload.Data) + cart.mapper, err = fingerprint128k(cartload.Data)(cart.env, cartload.Data) if err != nil { return err } case 262144: - cart.mapper, err = fingerprint256k(*cartload.Data)(cart.env, *cartload.Data) + cart.mapper, err = fingerprint256k(cartload.Data)(cart.env, cartload.Data) if err != nil { return err } default: if sz >= 4096 { - return fmt.Errorf("unrecognised size (%d bytes)", len(*cartload.Data)) + return fmt.Errorf("unrecognised size (%d bytes)", len(cartload.Data)) } - cart.mapper, err = newAtari2k(cart.env, *cartload.Data) + cart.mapper, err = newAtari2k(cart.env, cartload.Data) if err != nil { return err } @@ -510,8 +510,8 @@ func (cart *Cartridge) fingerprint(cartload cartridgeloader.Loader) error { // process occurs in that function. if that fails then we can say that the true // result from this function was a false positive. func (cart *Cartridge) fingerprintPlusROM(cartload cartridgeloader.Loader) bool { - for i := 0; i < len(*cartload.Data)-2; i++ { - if (*cartload.Data)[i] == 0x8d && (*cartload.Data)[i+1] == 0xf1 && ((*cartload.Data)[i+2]&0x10) == 0x10 { + for i := 0; i < len(cartload.Data)-2; i++ { + if (cartload.Data)[i] == 0x8d && (cartload.Data)[i+1] == 0xf1 && ((cartload.Data)[i+2]&0x10) == 0x10 { return true } } diff --git a/hardware/memory/cartridge/supercharger/fastload.go b/hardware/memory/cartridge/supercharger/fastload.go index 8d2ea84c..bd2de77a 100644 --- a/hardware/memory/cartridge/supercharger/fastload.go +++ b/hardware/memory/cartridge/supercharger/fastload.go @@ -83,21 +83,19 @@ type fastloadBlock struct { // newFastLoad is the preferred method of initialisation for the FastLoad type. func newFastLoad(cart *Supercharger, loader cartridgeloader.Loader) (tape, error) { - if len(*loader.Data)%fastLoadBlockLen != 0 { + if len(loader.Data)%fastLoadBlockLen != 0 { return nil, fmt.Errorf("fastload: wrong number of bytes in cartridge data") } - data := *loader.Data - fl := &FastLoad{ cart: cart, } - fl.blocks = make([]fastloadBlock, len(data)/fastLoadBlockLen) + fl.blocks = make([]fastloadBlock, len(loader.Data)/fastLoadBlockLen) for i := range fl.blocks { offset := i * fastLoadBlockLen - fl.blocks[i].data = data[offset : offset+fastLoadHeaderOffset] + fl.blocks[i].data = loader.Data[offset : offset+fastLoadHeaderOffset] // game header appears after main data gameHeader := fl.blocks[i].data[fastLoadHeaderOffset : fastLoadHeaderOffset+fastLoadHeaderLen] diff --git a/hardware/peripherals/fingerprint.go b/hardware/peripherals/fingerprint.go index 7182fb07..93fc2325 100644 --- a/hardware/peripherals/fingerprint.go +++ b/hardware/peripherals/fingerprint.go @@ -37,7 +37,7 @@ import ( // Free Software Foundation, version 2 or any later version. // // https://github.com/stella-emu/stella/blob/76914ded629db887ef612b1e5c9889220808191a/Copyright.txt -func Fingerprint(port plugging.PortID, data *[]byte) ports.NewPeripheral { +func Fingerprint(port plugging.PortID, data []byte) ports.NewPeripheral { // default to joystick if there is not data to fingerprint if data == nil { return controllers.NewStick @@ -49,26 +49,26 @@ func Fingerprint(port plugging.PortID, data *[]byte) ports.NewPeripheral { // atarivox and savekey are the most specific peripheral. because atarivox // includes the functionality of savekey we need to check atarivox first - if fingerprintAtariVox(port, *data) { + if fingerprintAtariVox(port, data) { return atarivox.NewAtariVox } - if fingerprintSaveKey(port, *data) { + if fingerprintSaveKey(port, data) { return savekey.NewSaveKey } // the other peripherals require a process of differentiation. the order is // important. - if fingerprintStick(port, *data) { - if fingerprintKeypad(port, *data) { + if fingerprintStick(port, data) { + if fingerprintKeypad(port, data) { return controllers.NewKeypad } - if fingerprintGamepad(port, *data) { + if fingerprintGamepad(port, data) { return controllers.NewGamepad } } else { - if fingerprintPaddle(port, *data) { + if fingerprintPaddle(port, data) { return controllers.NewPaddlePair } } diff --git a/hardware/vcs.go b/hardware/vcs.go index 60b5eae3..e33cdb03 100644 --- a/hardware/vcs.go +++ b/hardware/vcs.go @@ -141,7 +141,7 @@ func (vcs *VCS) End() { // but some applications might need to prepare the emulation further before // that happens. func (vcs *VCS) AttachCartridge(cartload cartridgeloader.Loader, reset bool) error { - err := vcs.TV.SetSpecConditional(cartload.TelevisionSpec) + err := vcs.TV.SetSpecConditional(specification.SearchSpec(cartload.Filename)) if err != nil { return err } diff --git a/recorder/fileformat.go b/recorder/fileformat.go index e69b1ca6..7ff2c701 100644 --- a/recorder/fileformat.go +++ b/recorder/fileformat.go @@ -117,8 +117,8 @@ func (plb *Playback) readHeader(lines []string, checkROM bool) error { return fmt.Errorf("playback: %w", err) } - if checkROM { - plb.CartLoad.HashSHA1 = lines[lineCartHash] + if checkROM && plb.CartLoad.HashSHA1 != lines[lineCartHash] { + return fmt.Errorf("playback: unexpected hash") } plb.TVSpec = lines[lineTVSpec] diff --git a/resources/fs/fs.go b/resources/fs/fs.go index 9fd62c58..af969119 100644 --- a/resources/fs/fs.go +++ b/resources/fs/fs.go @@ -20,7 +20,6 @@ package fs import ( "os" - "path/filepath" ) // MkdirAll is an abstraction of os.MkdirAll(). @@ -66,8 +65,3 @@ func Create(pth string) (*File, error) { f.f, err = os.Create(pth) return f, err } - -// Abs is an abstraction of filepath.Abs(). -func Abs(pth string) (string, error) { - return filepath.Abs(pth) -}