예제 #1
0
        /// <summary>
        /// Initializing the object based upon what we find in the specified file
        /// </summary>
        /// <param name="fileName"></param>
        private void getFromFiles(Stream stream)
        {
            // Assume a failure, so we can simply return.
            status = false;

            Buffer_sidtt  fileBuf1 = new Buffer_sidtt(), fileBuf2 = new Buffer_sidtt();
            StringBuilder fileName2 = new StringBuilder();

            // Try to load the single specified file. The original method didn't
            // quite work that well, so instead we now let the support files take
            // ownership of a known file and don't assume we should just
            // continue searching when an error is found.
            if (loadFile(stream, fileBuf1))
            {
                LoadStatus ret;

                // File loaded. Now check if it is in a valid single-file-format.
                ret = PSID_fileSupport(fileBuf1);
                if (ret != LoadStatus.LOAD_NOT_MINE)
                {
                    if (ret == LoadStatus.LOAD_OK)
                    {
                        status = acceptSidTune(fileBuf1);
                    }
                }
            }
        }
예제 #2
0
        /// <summary>
        /// Does not affect status of object, and therefore can be used to load
        /// files. Error string is put into info.statusstring, though
        /// </summary>
        /// <param name="fileName"></param>
        /// <param name="bufferRef"></param>
        /// <returns></returns>
        public bool loadFile(Stream stream, Buffer_sidtt bufferRef)
        {
            Buffer_sidtt fileBuf = new Buffer_sidtt();
            int          fileLen = 0;

            try
            {
                using (BinaryReader myIn = new BinaryReader(stream))
                {
                    fileLen = (int)stream.Length;
                    if (!fileBuf.assign(new short[fileLen], fileLen))
                    {
                        //info.statusstring = txt_notEnoughMemory;
                        return(false);
                    }
                    int restFileLen = fileLen;
                    if (restFileLen > 0)
                    {
                        for (int i = 0; i < fileLen; i++)
                        {
                            fileBuf.buf[i] = (short)myIn.ReadByte();
                        }
                    }
                }
            }
            catch
            {
                //info.statusstring = txt_cantLoadFile;
                return(false);
            }

            if (fileLen == 0)
            {
                //info.statusstring = txt_empty;
                return(false);
            }

            if (decompressPP20(fileBuf) < 0)
            {
                return(false);
            }

            bufferRef.assign(fileBuf.xferPtr(), fileBuf.xferLen());
            return(true);
        }
예제 #3
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="buf"></param>
        /// <returns>0 for no decompression (buf unchanged), 1 for decompression and -1 for error</returns>
        private int decompressPP20(Buffer_sidtt buf)
        {
            // Check for PowerPacker compression: load and decompress, if PP20 file.
            PP20 myPP = new PP20();
            int  fileLen;

            if (myPP.isCompressed(buf.buf, buf.bufLen))
            {
                PP20.Decompressed decomp = new PP20.Decompressed();
                if (0 == (fileLen = myPP.decompress(buf.buf, buf.bufLen, decomp)))
                {
                    //info.statusstring = myPP.getStatusstring();
                    return(-1);
                }
                else
                {
                    //info.statusstring = myPP.getStatusstring();
                    // Replace compressed buffer with uncompressed buffer.
                    buf.assign(decomp.destBufRef, fileLen);
                }
                return(1);
            }
            return(0);
        }
예제 #4
0
        internal SidTune.LoadStatus PSID_fileSupport(Buffer_sidtt dataBuf)
        {
            short clock, compatibility;
            long  speed;
            int   bufLen = dataBuf.bufLen;

#if SIDTUNE_PSID2NG
            clock = SidTune.SIDTUNE_CLOCK_UNKNOWN;
#else
            clock = info.clockSpeed;
#endif
            compatibility = SidTune.SIDTUNE_COMPATIBILITY_C64;

            // Require minimum size to allow access to the first few bytes.
            // Require a valid ID and version number.
            PHeader pHeader = new PHeader(dataBuf.buf, 0);

            // File format check
            if (bufLen < 6)
            {
                return(SidTune.LoadStatus.LOAD_NOT_MINE);
            }
            if (SIDEndian.endian_big32((short[])pHeader.id, 0) == PSID_ID)
            {
                switch (SIDEndian.endian_big16(pHeader.version, 0))
                {
                case 1:
                    compatibility = SidTune.SIDTUNE_COMPATIBILITY_PSID;
                    // Deliberate run on
                    break;

                case 2:
                    break;

                default:
                    //info.formatstring = _sidtune_unknown_psid;
                    return(SidTune.LoadStatus.LOAD_ERROR);
                }
                //info.formatstring = _sidtune_format_psid;
            }
            else if (SIDEndian.endian_big32((short[])pHeader.id, 0) == RSID_ID)
            {
                if (SIDEndian.endian_big16(pHeader.version, 0) != 2)
                {
                    //info.formatstring = _sidtune_unknown_rsid;
                    return(SidTune.LoadStatus.LOAD_ERROR);
                }
                //info.formatstring = _sidtune_format_rsid;
                compatibility = SidTune.SIDTUNE_COMPATIBILITY_R64;
            }
            else
            {
                return(SidTune.LoadStatus.LOAD_NOT_MINE);
            }

            // Due to security concerns, input must be at least as long as version 1
            // header plus 16-bit C64 load address. That is the area which will be
            // accessed.
            if (bufLen < (PHeader.SIZE + 2))
            {
                //info.formatstring = _sidtune_truncated;
                return(SidTune.LoadStatus.LOAD_ERROR);
            }

            sidtune.fileOffset = SIDEndian.endian_big16(pHeader.data, 0);
            info.loadAddr      = SIDEndian.endian_big16(pHeader.load, 0);
            info.initAddr      = SIDEndian.endian_big16(pHeader.init, 0);
            info.playAddr      = SIDEndian.endian_big16(pHeader.play, 0);
            info.songs         = SIDEndian.endian_big16(pHeader.songs, 0);
            info.startSong     = SIDEndian.endian_big16(pHeader.start, 0);
            info.sidChipBase1  = 0xd400;
            info.sidChipBase2  = 0;
            info.compatibility = compatibility;
            speed = SIDEndian.endian_big32(pHeader.speed, 0);

            if (info.songs > SidTune.SIDTUNE_MAX_SONGS)
            {
                info.songs = SidTune.SIDTUNE_MAX_SONGS;
            }

            info.musPlayer      = false;
            info.sidModel       = SidTune.SIDTUNE_SIDMODEL_UNKNOWN;
            info.relocPages     = 0;
            info.relocStartPage = 0;
            if (SIDEndian.endian_big16(pHeader.version, 0) >= 2)
            {
                int flags = SIDEndian.endian_big16(pHeader.flags, 0);
                if ((flags & PSID_MUS) != 0)
                {
                    // MUS tunes run at any speed
                    clock          = SidTune.SIDTUNE_CLOCK_ANY;
                    info.musPlayer = true;
                }

#if SIDTUNE_PSID2NG
                // This flags is only available for the appropriate file formats
                switch (compatibility)
                {
                case SidTune.SIDTUNE_COMPATIBILITY_C64:
                    if ((flags & PSID_SPECIFIC) != 0)
                    {
                        info.compatibility = SidTune.SIDTUNE_COMPATIBILITY_PSID;
                    }
                    break;

                case SidTune.SIDTUNE_COMPATIBILITY_R64:
                    if ((flags & PSID_BASIC) != 0)
                    {
                        info.compatibility = SidTune.SIDTUNE_COMPATIBILITY_BASIC;
                    }
                    break;
                }

                if ((flags & PSID_CLOCK_PAL) != 0)
                {
                    clock |= SidTune.SIDTUNE_CLOCK_PAL;
                }
                if ((flags & PSID_CLOCK_NTSC) != 0)
                {
                    clock |= SidTune.SIDTUNE_CLOCK_NTSC;
                }
                info.clockSpeed = clock;

                info.sidModel = SidTune.SIDTUNE_SIDMODEL_UNKNOWN;
                if ((flags & PSID_SIDMODEL_6581) != 0)
                {
                    info.sidModel |= SidTune.SIDTUNE_SIDMODEL_6581;
                }
                if ((flags & PSID_SIDMODEL_8580) != 0)
                {
                    info.sidModel |= SidTune.SIDTUNE_SIDMODEL_8580;
                }

                info.relocStartPage = pHeader.relocStartPage;
                info.relocPages     = pHeader.relocPages;
#endif
            }

            // Check reserved fields to force real c64 compliance
            // as required by the RSID specification
            if (compatibility == SidTune.SIDTUNE_COMPATIBILITY_R64)
            {
                if ((info.loadAddr != 0) || (info.playAddr != 0) || (speed != 0))
                {
                    //info.formatstring = _sidtune_invalid;
                    return(SidTune.LoadStatus.LOAD_ERROR);
                }
                // Real C64 tunes appear as CIA
                speed = ~0;
            }
            // Create the speed/clock setting table.
            sidtune.convertOldStyleSpeedToTables(speed, clock);

            // Copy info strings, so they will not get lost.
            info.numberOfInfostrings = 3;

            // Name
            int i;
            for (i = 0; i < pHeader.name.Length; i++)
            {
                if (pHeader.name[i] == 0)
                {
                    break;
                }
            }
            info.infostring[0] = sidtune.infostring[0] = new string(pHeader.name, 0, Math.Min(i, _sidtune_psid_maxStrLen));

            // Author
            for (i = 0; i < pHeader.author.Length; i++)
            {
                if (pHeader.author[i] == 0)
                {
                    break;
                }
            }
            info.infostring[1] = sidtune.infostring[1] = new string(pHeader.author, 0, Math.Min(i, _sidtune_psid_maxStrLen));

            // Released
            for (i = 0; i < pHeader.released.Length; i++)
            {
                if (pHeader.released[i] == 0)
                {
                    break;
                }
            }
            info.infostring[2] = sidtune.infostring[2] = new string(pHeader.released, 0, Math.Min(i, _sidtune_psid_maxStrLen));

            return(SidTune.LoadStatus.LOAD_OK);
        }
예제 #5
0
        /// <summary>
        /// Cache the data of a single-file or two-file sidtune and its corresponding file names
        /// </summary>
        /// <param name="buf"></param>
        /// <returns></returns>
        private bool acceptSidTune(Buffer_sidtt buf)
        {
            // @FIXME@ - MUS
            if (info.numberOfInfostrings == 3)
            {
                // Add <?> (HVSC standard) to
                // missing title, author,
                // release fields
                for (int i = 0; i < 3; i++)
                {
                    if (infostring[i].Length == 0)
                    {
                        infostring[i]      = "<?>";
                        info.infostring[i] = infostring[i];
                    }
                }
            }

            // Fix bad sidtune set up.
            if (info.songs > SIDTUNE_MAX_SONGS)
            {
                info.songs = SIDTUNE_MAX_SONGS;
            }
            else if (info.songs == 0)
            {
                info.songs++;
            }
            if (info.startSong > info.songs)
            {
                info.startSong = 1;
            }
            else if (info.startSong == 0)
            {
                info.startSong++;
            }

            info.dataFileLen = buf.bufLen;
            info.c64dataLen  = buf.bufLen - fileOffset;

            // Calculate any remaining addresses and then
            // confirm all the file details are correct
            if (resolveAddrs(buf.buf, fileOffset) == false)
            {
                return(false);
            }
            if (!checkRelocInfo())
            {
                return(false);
            }
            if (!checkCompatibility())
            {
                return(false);
            }

            if (info.dataFileLen >= 2)
            {
                // We only detect an offset of two. Some position independent
                // sidtunes contain a load address of 0xE000, but are loaded
                // to 0x0FFE and call player at 0x1000.
                info.fixLoad = (SIDEndian.endian_little16(buf.buf, fileOffset) == (info.loadAddr + 2));
            }

            // Check the size of the data.
            if (info.c64dataLen > SIDTUNE_MAX_MEMORY)
            {
                //info.statusstring = txt_dataTooLong;
                return(false);
            }
            else if (info.c64dataLen == 0)
            {
                //info.statusstring = txt_empty;
                return(false);
            }

            cache.assign(buf.xferPtr(), buf.xferLen());

            //info.statusstring = txt_noErrors;
            return(true);
        }
예제 #6
0
 protected LoadStatus SID_fileSupport(Buffer_sidtt dataBuf, Buffer_sidtt sidBuf)
 {
     return(LoadStatus.LOAD_NOT_MINE);
 }
예제 #7
0
 protected LoadStatus PSID_fileSupport(Buffer_sidtt dataBuf)
 {
     return(psid.PSID_fileSupport(dataBuf));
 }