Example #1
0
		void LoadFromString(ParseCueJob job)
		{
			string cueString = job.IN_CueString;
			TextReader tr = new StringReader(cueString);

			for (; ; )
			{
				job.CurrentLine++;
				string line = tr.ReadLine();
				if (line == null) break;
				line = line.Trim();
				if (line == "") continue;
				var clp = new CueLineParser(line);

				string key = clp.ReadToken().ToUpperInvariant();
				if (key.StartsWith(";"))
				{
					clp.EOF = true;
					OUT_CueFile.Commands.Add(new CUE_File.Command.COMMENT() { Value = line });
				}
				else switch (key)
				{
					default:
						job.Warn("Unknown command: " + key);
						break;

					case "CATALOG":
						if (OUT_CueFile.GlobalDiscInfo.Catalog != null)
							job.Warn("Multiple CATALOG commands detected. Subsequent ones are ignored.");
						else if (clp.EOF)
							job.Warn("Ignoring empty CATALOG command");
						else OUT_CueFile.Commands.Add(OUT_CueFile.GlobalDiscInfo.Catalog = new CUE_File.Command.CATALOG() { Value = clp.ReadToken() });
						break;

					case "CDTEXTFILE":
						if (OUT_CueFile.GlobalDiscInfo.CDTextFile != null)
							job.Warn("Multiple CDTEXTFILE commands detected. Subsequent ones are ignored.");
						else if (clp.EOF)
							job.Warn("Ignoring empty CDTEXTFILE command");
						else OUT_CueFile.Commands.Add(OUT_CueFile.GlobalDiscInfo.CDTextFile = new CUE_File.Command.CDTEXTFILE() { Path = clp.ReadPath() });
						break;

					case "FILE":
						{
							var path = clp.ReadPath();
							CueFileType ft;
							if (clp.EOF)
							{
								job.Error("FILE command is missing file type.");
								ft = CueFileType.Unspecified;
							}
							else
							{
								var strType = clp.ReadToken().ToUpperInvariant();
								switch (strType)
								{
									default:
										job.Error("Unknown FILE type: " + strType);
										ft = CueFileType.Unspecified;
										break;
									case "BINARY": ft = CueFileType.BINARY; break;
									case "MOTOROLA": ft = CueFileType.MOTOROLA; break;
									case "BINARAIFF": ft = CueFileType.AIFF; break;
									case "WAVE": ft = CueFileType.WAVE; break;
									case "MP3": ft = CueFileType.MP3; break;
								}
							}
							OUT_CueFile.Commands.Add(new CUE_File.Command.FILE() { Path = path, Type = ft });
						}
						break;

					case "FLAGS":
						{
							var cmd = new CUE_File.Command.FLAGS();
							OUT_CueFile.Commands.Add(cmd);
							while (!clp.EOF)
							{
								var flag = clp.ReadToken().ToUpperInvariant();
								switch (flag)
								{
									case "DATA":
									default:
										job.Warn("Unknown FLAG: " + flag);
										break;
									case "DCP": cmd.Flags |= CueTrackFlags.DCP; break;
									case "4CH": cmd.Flags |= CueTrackFlags._4CH; break;
									case "PRE": cmd.Flags |= CueTrackFlags.PRE; break;
									case "SCMS": cmd.Flags |= CueTrackFlags.SCMS; break;
								}
							}
							if (cmd.Flags == CueTrackFlags.None)
								job.Warn("Empty FLAG command");
						}
						break;

					case "INDEX":
						{
							if (clp.EOF)
							{
								job.Error("Incomplete INDEX command");
								break;
							}
							string strindexnum = clp.ReadToken();
							int indexnum;
							if (!int.TryParse(strindexnum, out indexnum) || indexnum < 0 || indexnum > 99)
							{
								job.Error("Invalid INDEX number: " + strindexnum);
								break;
							}
							string str_timestamp = clp.ReadToken();
							var ts = new Timestamp(str_timestamp);
							if (!ts.Valid)
							{
								job.Error("Invalid INDEX timestamp: " + str_timestamp);
								break;
							}
							OUT_CueFile.Commands.Add(new CUE_File.Command.INDEX() { Number = indexnum, Timestamp = ts });
						}
						break;

					case "ISRC":
						if (OUT_CueFile.GlobalDiscInfo.ISRC != null)
							job.Warn("Multiple ISRC commands detected. Subsequent ones are ignored.");
						else if (clp.EOF)
							job.Warn("Ignoring empty ISRC command");
						else
						{
							var isrc = clp.ReadToken();
							if (isrc.Length != 12)
								job.Warn("Invalid ISRC code ignored: " + isrc);
							else
							{
								OUT_CueFile.Commands.Add(OUT_CueFile.GlobalDiscInfo.ISRC = new CUE_File.Command.ISRC() { Value = isrc });
							}
						}
						break;

					case "PERFORMER":
						OUT_CueFile.Commands.Add(new CUE_File.Command.PERFORMER() { Value = clp.ReadPath() ?? "" });
						break;

					case "POSTGAP":
					case "PREGAP":
						{
							var str_msf = clp.ReadToken();
							var msf = new Timestamp(str_msf);
							if (!msf.Valid)
								job.Error("Ignoring {0} with invalid length MSF: " + str_msf, key);
							else
							{
								if (key == "POSTGAP")
									OUT_CueFile.Commands.Add(new CUE_File.Command.POSTGAP() { Length = msf });
								else
									OUT_CueFile.Commands.Add(new CUE_File.Command.PREGAP() { Length = msf });
							}
						}
						break;

					case "REM":
						OUT_CueFile.Commands.Add(new CUE_File.Command.REM() { Value = clp.ReadLine() });
						break;

					case "SONGWRITER":
						OUT_CueFile.Commands.Add(new CUE_File.Command.SONGWRITER() { Value = clp.ReadPath() ?? "" });
						break;

					case "TITLE":
						OUT_CueFile.Commands.Add(new CUE_File.Command.TITLE() { Value = clp.ReadPath() ?? "" });
						break;

					case "TRACK":
						{
							if (clp.EOF)
							{
								job.Error("Incomplete TRACK command");
								break;
							}
							string str_tracknum = clp.ReadToken();
							int tracknum;
							if (!int.TryParse(str_tracknum, out tracknum) || tracknum < 1 || tracknum > 99)
							{
								job.Error("Invalid TRACK number: " + str_tracknum);
								break;
							}

							//TODO - check sequentiality? maybe as a warning

							CueTrackType tt;
							var str_trackType = clp.ReadToken();
							switch (str_trackType.ToUpperInvariant())
							{
								default:
									job.Error("Unknown TRACK type: " + str_trackType);
									tt = CueTrackType.Unknown;
									break;
								case "AUDIO": tt = CueTrackType.Audio; break;
								case "CDG": tt = CueTrackType.CDG; break;
								case "MODE1/2048": tt = CueTrackType.Mode1_2048; break;
								case "MODE1/2352": tt = CueTrackType.Mode1_2352; break;
								case "MODE2/2336": tt = CueTrackType.Mode2_2336; break;
								case "MODE2/2352": tt = CueTrackType.Mode2_2352; break;
								case "CDI/2336": tt = CueTrackType.CDI_2336; break;
								case "CDI/2352": tt = CueTrackType.CDI_2352; break;
							}

							OUT_CueFile.Commands.Add(new CUE_File.Command.TRACK() { Number = tracknum, Type = tt });
						}
						break;
				}

				if (!clp.EOF)
				{
					var remainder = clp.ReadLine();
					if (remainder.TrimStart().StartsWith(";"))
					{
						//add a comment
						OUT_CueFile.Commands.Add(new CUE_File.Command.COMMENT() { Value = remainder });
					}
					else job.Warn("Unknown text at end of line after processing command: " + key);
				}

			} //end cue parsing loop

			job.FinishLog();
		} //LoadFromString
Example #2
0
		} //LoadFromString

		public void Run(ParseCueJob job)
		{
			job.OUT_CueFile = new CUE_File();
			job.LoadFromString(job);
		}
Example #3
0
		} //LoadFromString

		public void Run(ParseCueJob job)
		{
			job.OUT_CueFile = new CUE_File();
			job.LoadFromString(job);
		}
Example #4
0
		void LoadFromString(ParseCueJob job)
		{
			string cueString = job.IN_CueString;
			TextReader tr = new StringReader(cueString);

			for (; ; )
			{
				job.CurrentLine++;
				string line = tr.ReadLine();
				if (line == null) break;
				line = line.Trim();
				if (line == "") continue;
				var clp = new CueLineParser(line);

				string key = clp.ReadToken().ToUpperInvariant();
				
				//remove nonsense at beginning
				if (!IN_Strict)
				{
					while (key.Length > 0)
					{
						char c = key[0];
						if(c == ';') break;
						if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) break;
						key = key.Substring(1);
					}
				}

				bool startsWithSemicolon = key.StartsWith(";");

				if (startsWithSemicolon)
				{
					clp.EOF = true;
					OUT_CueFile.Commands.Add(new CUE_File.Command.COMMENT() { Value = line });
				}
				else switch (key)
				{
					default:
						job.Warn("Unknown command: " + key);
						break;

					case "CATALOG":
						if (OUT_CueFile.GlobalDiscInfo.Catalog != null)
							job.Warn("Multiple CATALOG commands detected. Subsequent ones are ignored.");
						else if (clp.EOF)
							job.Warn("Ignoring empty CATALOG command");
						else OUT_CueFile.Commands.Add(OUT_CueFile.GlobalDiscInfo.Catalog = new CUE_File.Command.CATALOG() { Value = clp.ReadToken() });
						break;

					case "CDTEXTFILE":
						if (OUT_CueFile.GlobalDiscInfo.CDTextFile != null)
							job.Warn("Multiple CDTEXTFILE commands detected. Subsequent ones are ignored.");
						else if (clp.EOF)
							job.Warn("Ignoring empty CDTEXTFILE command");
						else OUT_CueFile.Commands.Add(OUT_CueFile.GlobalDiscInfo.CDTextFile = new CUE_File.Command.CDTEXTFILE() { Path = clp.ReadPath() });
						break;

					case "FILE":
						{
							var path = clp.ReadPath();
							CueFileType ft;
							if (clp.EOF)
							{
								job.Error("FILE command is missing file type.");
								ft = CueFileType.Unspecified;
							}
							else
							{
								var strType = clp.ReadToken().ToUpperInvariant();
								switch (strType)
								{
									default:
										job.Error("Unknown FILE type: " + strType);
										ft = CueFileType.Unspecified;
										break;
									case "BINARY": ft = CueFileType.BINARY; break;
									case "MOTOROLA": ft = CueFileType.MOTOROLA; break;
									case "BINARAIFF": ft = CueFileType.AIFF; break;
									case "WAVE": ft = CueFileType.WAVE; break;
									case "MP3": ft = CueFileType.MP3; break;
								}
							}
							OUT_CueFile.Commands.Add(new CUE_File.Command.FILE() { Path = path, Type = ft });
						}
						break;

					case "FLAGS":
						{
							var cmd = new CUE_File.Command.FLAGS();
							OUT_CueFile.Commands.Add(cmd);
							while (!clp.EOF)
							{
								var flag = clp.ReadToken().ToUpperInvariant();
								switch (flag)
								{
									case "DATA":
									default:
										job.Warn("Unknown FLAG: " + flag);
										break;
									case "DCP": cmd.Flags |= CueTrackFlags.DCP; break;
									case "4CH": cmd.Flags |= CueTrackFlags._4CH; break;
									case "PRE": cmd.Flags |= CueTrackFlags.PRE; break;
									case "SCMS": cmd.Flags |= CueTrackFlags.SCMS; break;
								}
							}
							if (cmd.Flags == CueTrackFlags.None)
								job.Warn("Empty FLAG command");
						}
						break;

					case "INDEX":
						{
							if (clp.EOF)
							{
								job.Error("Incomplete INDEX command");
								break;
							}
							string strindexnum = clp.ReadToken();
							int indexnum;
							if (!int.TryParse(strindexnum, out indexnum) || indexnum < 0 || indexnum > 99)
							{
								job.Error("Invalid INDEX number: " + strindexnum);
								break;
							}
							string str_timestamp = clp.ReadToken();
							var ts = new Timestamp(str_timestamp);
							if (!ts.Valid && !IN_Strict)
							{
								//try cleaning it up
								str_timestamp = Regex.Replace(str_timestamp, "[^0-9:]", "");
								ts = new Timestamp(str_timestamp);
							}
							if (!ts.Valid)
							{
								if (IN_Strict)
									job.Error("Invalid INDEX timestamp: " + str_timestamp);
								break;
							}
							OUT_CueFile.Commands.Add(new CUE_File.Command.INDEX() { Number = indexnum, Timestamp = ts });
						}
						break;

					case "ISRC":
						if (OUT_CueFile.GlobalDiscInfo.ISRC != null)
							job.Warn("Multiple ISRC commands detected. Subsequent ones are ignored.");
						else if (clp.EOF)
							job.Warn("Ignoring empty ISRC command");
						else
						{
							var isrc = clp.ReadToken();
							if (isrc.Length != 12)
								job.Warn("Invalid ISRC code ignored: " + isrc);
							else
							{
								OUT_CueFile.Commands.Add(OUT_CueFile.GlobalDiscInfo.ISRC = new CUE_File.Command.ISRC() { Value = isrc });
							}
						}
						break;

					case "PERFORMER":
						OUT_CueFile.Commands.Add(new CUE_File.Command.PERFORMER() { Value = clp.ReadPath() ?? "" });
						break;

					case "POSTGAP":
					case "PREGAP":
						{
							var str_msf = clp.ReadToken();
							var msf = new Timestamp(str_msf);
							if (!msf.Valid)
								job.Error("Ignoring {0} with invalid length MSF: " + str_msf, key);
							else
							{
								if (key == "POSTGAP")
									OUT_CueFile.Commands.Add(new CUE_File.Command.POSTGAP() { Length = msf });
								else
									OUT_CueFile.Commands.Add(new CUE_File.Command.PREGAP() { Length = msf });
							}
						}
						break;

					case "REM":
						OUT_CueFile.Commands.Add(new CUE_File.Command.REM() { Value = clp.ReadLine() });
						break;

					case "SONGWRITER":
						OUT_CueFile.Commands.Add(new CUE_File.Command.SONGWRITER() { Value = clp.ReadPath() ?? "" });
						break;

					case "TITLE":
						OUT_CueFile.Commands.Add(new CUE_File.Command.TITLE() { Value = clp.ReadPath() ?? "" });
						break;

					case "TRACK":
						{
							if (clp.EOF)
							{
								job.Error("Incomplete TRACK command");
								break;
							}
							string str_tracknum = clp.ReadToken();
							int tracknum;
							if (!int.TryParse(str_tracknum, out tracknum) || tracknum < 1 || tracknum > 99)
							{
								job.Error("Invalid TRACK number: " + str_tracknum);
								break;
							}

							//TODO - check sequentiality? maybe as a warning

							CueTrackType tt;
							var str_trackType = clp.ReadToken();
							switch (str_trackType.ToUpperInvariant())
							{
								default:
									job.Error("Unknown TRACK type: " + str_trackType);
									tt = CueTrackType.Unknown;
									break;
								case "AUDIO": tt = CueTrackType.Audio; break;
								case "CDG": tt = CueTrackType.CDG; break;
								case "MODE1/2048": tt = CueTrackType.Mode1_2048; break;
								case "MODE1/2352": tt = CueTrackType.Mode1_2352; break;
								case "MODE2/2336": tt = CueTrackType.Mode2_2336; break;
								case "MODE2/2352": tt = CueTrackType.Mode2_2352; break;
								case "CDI/2336": tt = CueTrackType.CDI_2336; break;
								case "CDI/2352": tt = CueTrackType.CDI_2352; break;
							}

							OUT_CueFile.Commands.Add(new CUE_File.Command.TRACK() { Number = tracknum, Type = tt });
						}
						break;
				}

				if (!clp.EOF)
				{
					var remainder = clp.ReadLine();
					if (remainder.TrimStart().StartsWith(";"))
					{
						//add a comment
						OUT_CueFile.Commands.Add(new CUE_File.Command.COMMENT() { Value = remainder });
					}
					else job.Warn("Unknown text at end of line after processing command: " + key);
				}

			} //end cue parsing loop

			job.FinishLog();
		} //LoadFromString
Example #5
0
        void RunBizHawk()
        {
            string infile = IN_FromPath;
            string cue_content = null;

            var cfr = new CueFileResolver();

            RERUN:
            var ext = Path.GetExtension(infile).ToLowerInvariant();

            if (ext == ".iso")
            {
                //make a fake cue file to represent this iso file and rerun it as a cue
                string filebase = Path.GetFileName(infile);
                cue_content = string.Format(@"
                        FILE ""{0}"" BINARY
                            TRACK 01 MODE1/2048
                                INDEX 01 00:00:00",
                    filebase);
                infile = Path.ChangeExtension(infile, ".cue");
                goto RERUN;
            }
            if (ext == ".cue")
            {
                //TODO - make sure code is designed so no matter what happens, a disc is disposed in case of errors.
                //perhaps the CUE_Format2 (once renamed to something like Context) can handle that
                var cuePath = IN_FromPath;
                var cueContext = new CUE_Context();
                cueContext.DiscMountPolicy = IN_DiscMountPolicy;

                cueContext.Resolver = cfr;
                if (!cfr.IsHardcodedResolve) cfr.SetBaseDirectory(Path.GetDirectoryName(infile));

                //parse the cue file
                var parseJob = new ParseCueJob();
                if (cue_content == null)
                    cue_content = File.ReadAllText(cuePath);
                parseJob.IN_CueString = cue_content;
                parseJob.Run(parseJob);
                //TODO - need better handling of log output
                if (!string.IsNullOrEmpty(parseJob.OUT_Log)) Console.WriteLine(parseJob.OUT_Log);
                ConcatenateJobLog(parseJob);

                //compile the cue file:
                //includes this work: resolve required bin files and find out what it's gonna take to load the cue
                var compileJob = new CompileCueJob();
                compileJob.IN_CueContext = cueContext;
                compileJob.IN_CueFile = parseJob.OUT_CueFile;
                compileJob.Run();
                //TODO - need better handling of log output
                if (!string.IsNullOrEmpty(compileJob.OUT_Log)) Console.WriteLine(compileJob.OUT_Log);
                ConcatenateJobLog(compileJob);

                //check slow loading threshold
                if (compileJob.OUT_LoadTime >= IN_SlowLoadAbortThreshold)
                {
                    Warn("Loading terminated due to slow load threshold");
                    OUT_SlowLoadAborted = true;
                    goto DONE;
                }

                //actually load it all up
                var loadJob = new LoadCueJob();
                loadJob.IN_CompileJob = compileJob;
                loadJob.Run();
                //TODO - need better handling of log output
                if (!string.IsNullOrEmpty(loadJob.OUT_Log)) Console.WriteLine(loadJob.OUT_Log);
                ConcatenateJobLog(loadJob);

                OUT_Disc = loadJob.OUT_Disc;
                //OUT_Disc.DiscMountPolicy = IN_DiscMountPolicy; //NOT SURE WE NEED THIS (only makes sense for cue probably)

                //apply SBI if it exists (TODO - for formats other than cue?)
                var sbiPath = Path.ChangeExtension(IN_FromPath, ".sbi");
                if (File.Exists(sbiPath) && SBI.SBIFormat.QuickCheckISSBI(sbiPath))
                {
                    var loadSbiJob = new SBI.LoadSBIJob() { IN_Path = sbiPath };
                    loadSbiJob.Run();
                    var applySbiJob = new ApplySBIJob();
                    applySbiJob.Run(OUT_Disc, loadSbiJob.OUT_Data, IN_DiscMountPolicy.SBI_As_Mednafen);
                }
            }
            else if (ext == ".ccd")
            {
                CCD_Format ccdLoader = new CCD_Format();
                OUT_Disc = ccdLoader.LoadCCDToDisc(IN_FromPath, IN_DiscMountPolicy);
            }

            DONE: ;
        }
		private void LoadFromString(ParseCueJob job)
		{
			string cueString = job.IN_CueString;
			TextReader tr = new StringReader(cueString);

			for (; ; )
			{
				job.CurrentLine++;
				string line = tr.ReadLine();
				if (line == null) break;
				line = line.Trim();
				if (line == "") continue;
				var clp = new CueLineParser(line);

				string key = clp.ReadToken().ToUpperInvariant();
				
				//remove nonsense at beginning
				if (!IN_Strict)
				{
					while (key.Length > 0)
					{
						char c = key[0];
						if(c == ';') break;
						if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) break;
						key = key.Substring(1);
					}
				}

				bool startsWithSemicolon = key.StartsWith(";");

				if (startsWithSemicolon)
				{
					clp.EOF = true;
					OUT_CueFile.Commands.Add(new CUE_File.Command.COMMENT(line));
				}
				else switch (key)
				{
					default:
						job.Warn($"Unknown command: {key}");
						break;

					case "CATALOG":
						if (OUT_CueFile.GlobalDiscInfo.Catalog != null)
							job.Warn("Multiple CATALOG commands detected. Subsequent ones are ignored.");
						else if (clp.EOF)
							job.Warn("Ignoring empty CATALOG command");
						else OUT_CueFile.Commands.Add(OUT_CueFile.GlobalDiscInfo.Catalog = new CUE_File.Command.CATALOG(clp.ReadToken()));
						break;

					case "CDTEXTFILE":
						if (OUT_CueFile.GlobalDiscInfo.CDTextFile != null)
							job.Warn("Multiple CDTEXTFILE commands detected. Subsequent ones are ignored.");
						else if (clp.EOF)
							job.Warn("Ignoring empty CDTEXTFILE command");
						else OUT_CueFile.Commands.Add(OUT_CueFile.GlobalDiscInfo.CDTextFile = new CUE_File.Command.CDTEXTFILE(clp.ReadPath()));
						break;

					case "FILE":
						{
							var path = clp.ReadPath();
							CueFileType ft;
							if (clp.EOF)
							{
								job.Error("FILE command is missing file type.");
								ft = CueFileType.Unspecified;
							}
							else
							{
								var strType = clp.ReadToken().ToUpperInvariant();
								switch (strType)
								{
									default:
										job.Error($"Unknown FILE type: {strType}");
										ft = CueFileType.Unspecified;
										break;
									case "BINARY": ft = CueFileType.BINARY; break;
									case "MOTOROLA": ft = CueFileType.MOTOROLA; break;
									case "BINARAIFF": ft = CueFileType.AIFF; break;
									case "WAVE": ft = CueFileType.WAVE; break;
									case "MP3": ft = CueFileType.MP3; break;
								}
							}
							OUT_CueFile.Commands.Add(new CUE_File.Command.FILE(path, ft));
						}
						break;

					case "FLAGS":
						{
							CueTrackFlags flags = default;
							while (!clp.EOF)
							{
								var flag = clp.ReadToken().ToUpperInvariant();
								switch (flag)
								{
									case "DATA":
									default:
										job.Warn($"Unknown FLAG: {flag}");
										break;
									case "DCP": flags |= CueTrackFlags.DCP; break;
									case "4CH": flags |= CueTrackFlags._4CH; break;
									case "PRE": flags |= CueTrackFlags.PRE; break;
									case "SCMS": flags |= CueTrackFlags.SCMS; break;
								}
							}
							if (flags == CueTrackFlags.None)
								job.Warn("Empty FLAG command");
							OUT_CueFile.Commands.Add(new CUE_File.Command.FLAGS(flags));
						}
						break;

					case "INDEX":
						{
							if (clp.EOF)
							{
								job.Error("Incomplete INDEX command");
								break;
							}
							string strindexnum = clp.ReadToken();
							if (!int.TryParse(strindexnum, out var indexnum) || indexnum < 0 || indexnum > 99)
							{
								job.Error($"Invalid INDEX number: {strindexnum}");
								break;
							}
							string str_timestamp = clp.ReadToken();
							var ts = new Timestamp(str_timestamp);
							if (!ts.Valid && !IN_Strict)
							{
								//try cleaning it up
								str_timestamp = Regex.Replace(str_timestamp, "[^0-9:]", "");
								ts = new Timestamp(str_timestamp);
							}
							if (!ts.Valid)
							{
								if (IN_Strict)
									job.Error($"Invalid INDEX timestamp: {str_timestamp}");
								break;
							}
							OUT_CueFile.Commands.Add(new CUE_File.Command.INDEX(indexnum, ts));
						}
						break;

					case "ISRC":
						if (OUT_CueFile.GlobalDiscInfo.ISRC != null)
							job.Warn("Multiple ISRC commands detected. Subsequent ones are ignored.");
						else if (clp.EOF)
							job.Warn("Ignoring empty ISRC command");
						else
						{
							var isrc = clp.ReadToken();
							if (isrc.Length != 12)
								job.Warn($"Invalid ISRC code ignored: {isrc}");
							else
							{
								OUT_CueFile.Commands.Add(OUT_CueFile.GlobalDiscInfo.ISRC = new CUE_File.Command.ISRC(isrc));
							}
						}
						break;

					case "PERFORMER":
						OUT_CueFile.Commands.Add(new CUE_File.Command.PERFORMER(clp.ReadPath() ?? ""));
						break;

					case "POSTGAP":
					case "PREGAP":
						{
							var str_msf = clp.ReadToken();
							var msf = new Timestamp(str_msf);
							if (!msf.Valid)
								job.Error($"Ignoring {{0}} with invalid length MSF: {str_msf}", key);
							else
							{
								if (key == "POSTGAP")
									OUT_CueFile.Commands.Add(new CUE_File.Command.POSTGAP(msf));
								else
									OUT_CueFile.Commands.Add(new CUE_File.Command.PREGAP(msf));
							}
						}
						break;

					case "REM":
						OUT_CueFile.Commands.Add(new CUE_File.Command.REM(clp.ReadLine()));
						break;

					case "SONGWRITER":
						OUT_CueFile.Commands.Add(new CUE_File.Command.SONGWRITER(clp.ReadPath() ?? ""));
						break;

					case "TITLE":
						OUT_CueFile.Commands.Add(new CUE_File.Command.TITLE(clp.ReadPath() ?? ""));
						break;

					case "TRACK":
						{
							if (clp.EOF)
							{
								job.Error("Incomplete TRACK command");
								break;
							}

							string str_tracknum = clp.ReadToken();
							if (!int.TryParse(str_tracknum, out int tracknum) || tracknum < 1 || tracknum > 99)
							{
								job.Error($"Invalid TRACK number: {str_tracknum}");
								break;
							}

							// TODO - check sequentiality? maybe as a warning

							CueTrackType tt;
							var str_trackType = clp.ReadToken();
							switch (str_trackType.ToUpperInvariant())
							{
								default:
									job.Error($"Unknown TRACK type: {str_trackType}");
									tt = CueTrackType.Unknown;
									break;
								case "AUDIO": tt = CueTrackType.Audio; break;
								case "CDG": tt = CueTrackType.CDG; break;
								case "MODE1/2048": tt = CueTrackType.Mode1_2048; break;
								case "MODE1/2352": tt = CueTrackType.Mode1_2352; break;
								case "MODE2/2336": tt = CueTrackType.Mode2_2336; break;
								case "MODE2/2352": tt = CueTrackType.Mode2_2352; break;
								case "CDI/2336": tt = CueTrackType.CDI_2336; break;
								case "CDI/2352": tt = CueTrackType.CDI_2352; break;
							}

							OUT_CueFile.Commands.Add(new CUE_File.Command.TRACK(tracknum, tt));
						}
						break;
				}

				if (!clp.EOF)
				{
					var remainder = clp.ReadLine();
					if (remainder.TrimStart().StartsWith(";"))
					{
						//add a comment
						OUT_CueFile.Commands.Add(new CUE_File.Command.COMMENT(remainder));
					}
					else job.Warn($"Unknown text at end of line after processing command: {key}");
				}

			} //end cue parsing loop

			job.FinishLog();
		} //LoadFromString
Example #7
0
		void RunBizHawk()
		{
			string infile = IN_FromPath;
			string cue_content = null;

			var cfr = new CueFileResolver();

		RERUN:
			var ext = Path.GetExtension(infile).ToLowerInvariant();

			if (ext == ".iso")
			{
				//make a fake cue file to represent this iso file and rerun it as a cue
				string filebase = Path.GetFileName(infile);
				cue_content = string.Format(@"
						FILE ""{0}"" BINARY
							TRACK 01 MODE1/2048
								INDEX 01 00:00:00",
					filebase);
				infile = Path.ChangeExtension(infile, ".cue");
				goto RERUN;
			}
			if (ext == ".cue")
			{
				//TODO - major renovation of error handling needed

				//TODO - make sure code is designed so no matter what happens, a disc is disposed in case of errors.
				//perhaps the CUE_Format2 (once renamed to something like Context) can handle that
				var cuePath = IN_FromPath;
				var cueContext = new CUE_Context();
				cueContext.DiscMountPolicy = IN_DiscMountPolicy;

				cueContext.Resolver = cfr;
				if (!cfr.IsHardcodedResolve) cfr.SetBaseDirectory(Path.GetDirectoryName(infile));

				//parse the cue file
				var parseJob = new ParseCueJob();
				if (cue_content == null)
					cue_content = File.ReadAllText(cuePath);
				parseJob.IN_CueString = cue_content;
				bool okParse = true;
				try { parseJob.Run(parseJob); }
				catch (DiscJobAbortException) { okParse = false; parseJob.FinishLog(); }
				if (!string.IsNullOrEmpty(parseJob.OUT_Log)) Console.WriteLine(parseJob.OUT_Log);
				ConcatenateJobLog(parseJob);
				if (!okParse)
					goto DONE;

				//compile the cue file:
				//includes this work: resolve required bin files and find out what it's gonna take to load the cue
				var compileJob = new CompileCueJob();
				compileJob.IN_CueContext = cueContext;
				compileJob.IN_CueFile = parseJob.OUT_CueFile;
				bool okCompile = true;
				try { compileJob.Run(); }
				catch (DiscJobAbortException) { okCompile = false; compileJob.FinishLog();  }
				if (!string.IsNullOrEmpty(compileJob.OUT_Log)) Console.WriteLine(compileJob.OUT_Log);
				ConcatenateJobLog(compileJob);
				if (!okCompile || compileJob.OUT_ErrorLevel)
					goto DONE;

				//check slow loading threshold
				if (compileJob.OUT_LoadTime > IN_SlowLoadAbortThreshold)
				{
					Warn("Loading terminated due to slow load threshold");
					OUT_SlowLoadAborted = true;
					goto DONE;
				}

				//actually load it all up
				var loadJob = new LoadCueJob();
				loadJob.IN_CompileJob = compileJob;
				loadJob.Run();
				//TODO - need better handling of log output
				if (!string.IsNullOrEmpty(loadJob.OUT_Log)) Console.WriteLine(loadJob.OUT_Log);
				ConcatenateJobLog(loadJob);

				OUT_Disc = loadJob.OUT_Disc;
				//OUT_Disc.DiscMountPolicy = IN_DiscMountPolicy; //NOT SURE WE NEED THIS (only makes sense for cue probably)
			}
			else if (ext == ".ccd")
			{
				CCD_Format ccdLoader = new CCD_Format();
				OUT_Disc = ccdLoader.LoadCCDToDisc(IN_FromPath, IN_DiscMountPolicy);
			}


		DONE:

			//setup the lowest level synth provider
			if (OUT_Disc != null)
			{
				var sssp = new ArraySectorSynthProvider()
				{
					Sectors = OUT_Disc._Sectors,
					FirstLBA = -150
				};
				OUT_Disc.SynthProvider = sssp;
			}
		}