/// <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); } } } }
/// <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); }
/// <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); }
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); }
/// <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); }
protected LoadStatus SID_fileSupport(Buffer_sidtt dataBuf, Buffer_sidtt sidBuf) { return(LoadStatus.LOAD_NOT_MINE); }
protected LoadStatus PSID_fileSupport(Buffer_sidtt dataBuf) { return(psid.PSID_fileSupport(dataBuf)); }