Example #1
0
        }// -----------------------------------------

        /*
         * Reads a CUE file, line by line, used in load();
         * CUE SHEET INFO : http://wiki.hydrogenaud.io/index.php?title=Cue_sheet
         * This is not a complete Cue Parser, just a basic one
         * that can read game disks. A track of data and tracks of CDDA audio.
         */
        int cue_parser(string line)
        {
            // Get FILE image name
            if (line.ToUpper().StartsWith("FILE"))
            {
                openTrack = null;         // Close any open Track

                // Try to get the filename within the quotes after FILE
                var ff = Regex.Split(line, "[\"\']");

                if (ff.Length < 3)
                {
                    // Because Array should be like [] {"FILE","GAME NAME.BIN", ... ,"BINARY"}
                    ERROR = "Could not get filename";
                    return(0);
                }

                // [SAFEGUARD]
                if (!new string[] { "BINARY", "WAVE", "MP3" }.Contains(ff.Last().ToUpper().Trim()))
                {
                    ERROR = "Unsupported File Type, or identifier missing. Supported = {BINARY,WAVE,MP3}";
                    return(0);
                }

                // First and last elements are not needed
                openFile = string.Join("'", ff, 1, ff.Length - 2);

                return(1); // No reason to check for other cases
            }              // -- FILE


            // Get Track NO and track TYPE
            if (line.ToUpper().StartsWith("TRACK"))
            {
                openTrack = null;         // Close any open Track

                Match m = Regex.Match(line, @"^\s*TRACK\s+(\d+)\s+(\S+)", RegexOptions.IgnoreCase);
                if (m.Success)
                {
                    int    trackNo   = int.Parse(m.Groups[1].Value);
                    string trackType = m.Groups[2].Value.ToUpper();

                    // [SAFEGUARD] Check to see if Track Type is valid
                    if (getSectorsByDataType(trackType) == 0)
                    {
                        ERROR = "Unsupported TRACK type:" + trackType; return(0);
                    }

                    // [SAFEGUARD] Check to see if the trackNO is already defined in the tracks
                    foreach (var t in tracks)
                    {
                        if (t.trackNo == trackNo)
                        {
                            ERROR = "TRACK Number already defined"; return(0);
                        }
                    }

                    CueTrack tr = new CueTrack(trackNo, trackType);
                    openTrack    = tr;
                    tr.trackFile = openFile; openFile = null;
                    tracks.Add(tr);
                }
                else
                {
                    ERROR = "Cannot parse TRACK line"; return(0);
                }

                return(1);
            }    // -- TRACK

            // --
            if (line.ToUpper().StartsWith("INDEX"))
            {
                if (openTrack == null)
                {
                    ERROR = "INDEX not inside a TRACK"; return(0);
                }

                Match m = Regex.Match(line, @"^\s*INDEX\s+(\d+)\s+(\d{1,2}):(\d{1,2}):(\d{1,2})", RegexOptions.IgnoreCase);
                if (m.Success)
                {
                    var indexNo = int.Parse(m.Groups[1].Value);
                    if (openTrack.indexExists(indexNo))
                    {
                        ERROR = String.Format("Duplicate Index on track {0}", openTrack.trackNo); return(0);
                    }
                    openTrack.addIndex(indexNo,
                                       int.Parse(m.Groups[2].Value),
                                       int.Parse(m.Groups[3].Value),
                                       int.Parse(m.Groups[4].Value));
                }
                else
                {
                    ERROR = "Cannot parse INDEX line"; return(0);
                }
                return(1);
            }    // -- INDEX

            // --
            if (line.ToUpper().StartsWith("PREGAP"))
            {
                if (openTrack == null)
                {
                    ERROR = "INDEX not inside a TRACK"; return(0);
                }

                Match m = Regex.Match(line, @"^\s*PREGAP\s+(\d{1,2}):(\d{1,2}):(\d{1,2})", RegexOptions.IgnoreCase);
                if (m.Success)
                {
                    openTrack.setGap(int.Parse(m.Groups[1].Value),
                                     int.Parse(m.Groups[2].Value),
                                     int.Parse(m.Groups[3].Value));
                }
                else
                {
                    ERROR = "Cannot parse PREGAP line"; return(0);
                }
                return(1);
            }    // - PREGAP

            // --
            // Title can be either at ROOT is used as the CD title, or inside a Track
            if (line.ToUpper().StartsWith("TITLE"))
            {
                // Currently only used as CD title, and only works with titles inside ""
                if (openTrack == null)
                {
                    Match m = Regex.Match(line, ".+\"(.+)\"$");
                    if (m.Success)
                    {
                        CD_TITLE = m.Value;
                    }
                    else
                    {
                        ERROR = "Can't parse TITLE"; return(0);
                    }
                }
            }    // -- TITLE

            // Skip Comments
            // if (line.ToUpper().StartsWith("REM")) return 1; -- Everything else will return 1

            return(1);
        }// -----------------------------------------
Example #2
0
        }// -----------------------------------------

        /// <summary>
        /// Load a previously saved JSON settings file
        /// </summary>
        /// <param name="file">The JSON file to load</param>
        /// <returns>Success 1 OK,0 ERROR</returns>
        public bool loadJson(string file)
        {
            if (!File.Exists(file))
            {
                ERROR = "File:" + file + "does not exist";
                return(false);
            }

            string loadedJSONText;

            try{
                loadedJSONText = File.ReadAllText(file);
            }
            catch (IOException e)
            {
                ERROR = e.ToString(); return(false);
            }
            catch (UnauthorizedAccessException)
            {
                ERROR = "Unauthorized Access"; return(false);
            }

            // -- JSON Get
            var js = new JavaScriptSerializer();
            // Note: Should never throw error because it was created internally
            Dictionary <string, object> data = js.Deserialize <Dictionary <string, object> >(loadedJSONText);

            // -- Version check, defaults to 1 if field missing
            int versionLoaded = 1;

            if (data.ContainsKey("version"))
            {
                versionLoaded = int.Parse(data["version"].ToString());
            }

            // -- Backwards Compatibility ::
            switch (versionLoaded)
            {
            case 1:
                // Convert V1 to V2
                int ssize = (int)data["sectorSize"];
                foreach (Dictionary <string, object> t in (ArrayList)data["tracks"])
                {
                    t["diskFileSize"] = (int)t["sectorSize"] * ssize;
                    t["diskFile"]     = null;
                    t["isData"]       = (bool)!((t["type"] as string) == "AUDIO");
                }
                goto case 2;

            case 2:
                // Convert V2 to V3
                string CDT       = null;            // If any is data, then set to the data type.
                int    diskFiles = 0;               // Count tracks with diskfiles set
                bool   anyAudio  = false;           // Is there any audio track?
                foreach (Dictionary <string, object> t in (ArrayList)data["tracks"])
                {
                    t["trackType"]      = t["type"];
                    t["indexes"]        = t["indexAr"];                     // Array is the same
                    t["storedFileName"] = t["filename"];
                    t["byteSize"]       = t["diskFileSize"];
                    t["md5"]            = "";                  // New field
                    if (!anyAudio && t["trackType"].ToString() == "AUDIO")
                    {
                        anyAudio = true;
                    }
                    // Capture the first data format of any track:
                    if ((bool)t["isData"] && CDT == null)
                    {
                        CDT = t["trackType"].ToString();
                    }
                    if (t["diskFile"] != null)
                    {
                        diskFiles++;
                    }
                }

                // New/Renamed properties :
                data["audio"]     = anyAudio ? "??? kbps" : "";
                data["cdType"]    = CDT ?? "AUDIO";
                data["totalSize"] = data["imageSize"];
                data["multiFile"] = (diskFiles > 1) && (diskFiles == (data["tracks"] as ArrayList).Count);
                break;

            default: break;
            }

            // -- At this point the data is properly in v3 format.


            // -- Read tracks ::
            tracks = new List <CueTrack>();
            foreach (Dictionary <string, object> t in (ArrayList)data["tracks"])
            {
                var tr = new CueTrack((int)t["trackNo"], t["trackType"].ToString());
                tr.sectorSize      = (int)t["sectorSize"];
                tr.sectorStart     = (int)t["sectorStart"];
                tr.byteSize        = (int)t["byteSize"];
                tr.pregapMinutes   = (int)t["pregapMinutes"];
                tr.pregapSeconds   = (int)t["pregapSeconds"];
                tr.pregapMillisecs = (int)t["pregapMillisecs"];
                tr.storedFileName  = (string)t["storedFileName"];
                tr.md5             = (string)t["md5"];

                foreach (Dictionary <string, object> ind in (ArrayList)t["indexes"])
                {
                    tr.addIndex((int)ind["no"], (int)ind["minutes"], (int)ind["seconds"], (int)ind["millisecs"]);
                }

                tracks.Add(tr);
            }

            // -- cd info data ::
            CD_TITLE         = data["cdTitle"].ToString();
            CD_TYPE          = data["cdType"].ToString();
            CD_TOTAL_SIZE    = (int)data["totalSize"];
            CD_AUDIO_QUALITY = data["audio"].ToString();
            MULTIFILE        = (bool)data["multiFile"];
            SECTOR_SIZE      = (int)data["sectorSize"];

            // Some Checks ::
            if (tracks[0].byteSize == 0)
            {
                calculateTracksByteSize();                              // Single File Multi Tracks
            }
            if (tracks.Count > 1 && tracks[1].sectorStart == 0)
            {
                calculateTracksSectorStart();                                                     // Multi File Multi Track
            }
            return(true);
        }// -----------------------------------------
Example #3
0
        }// -----------------------------------------

        /// <summary>
        /// Load a descriptor file
        /// The CD title is read from the .CUE filename
        /// Also checks if files declared inside the .CUE exist or not
        /// </summary>
        /// <param name="file">Filename to load [.cue]</param>
        /// <returns>Success ( read the ERROR Property )</returns>
        public bool load(string file)
        {
            if (!File.Exists(file))
            {
                ERROR = "File:" + file + "does not exist"; return(false);
            }

            // Vars init
            loadedFile_path = file;
            loadedFile_dir  = Path.GetDirectoryName(loadedFile_path);
            loadedFile_ext  = Path.GetExtension(loadedFile_path).ToLower().Trim('.');

            // This is redudant..
            if (!SUPPORTED_FORMATS.Contains(loadedFile_ext))
            {
                ERROR = "File Type is not supported.- Supported formats : " + SUPPORTED_FORMATS.ToString(); return(false);
            }

            try {
                loadedFile = File.ReadAllLines(file);
            }
            catch (IOException) {
                ERROR = "There was an I/O problem loading the file"; return(false);
            }

            // Init vars
            CD_TOTAL_SIZE = 0;
            CD_TITLE      = "untitled CD"; SECTOR_SIZE = 0; CD_TYPE = null;
            tracks        = new List <CueTrack>();
            openTrack     = null; openFile = null;

            // Try to capture the CD TITLE from the CUE filename
            Match m1 = Regex.Match(loadedFile_path, @"([^\/\\]*)\.(?:" + SUPPORTED_FORMATS + @")$", RegexOptions.IgnoreCase);

            if (m1.Success)
            {
                CD_TITLE = m1.Groups[1].Value;
            }

            // Start Parsing the file based on it's type
            Func <string, int> parser;

            switch (loadedFile_ext)
            {
            case "cue": parser = cue_parser; break;

            case "ccd": parser = ccd_parser; break;

            default: parser = cue_parser; break;
            }

            // Parser ::

            for (int c = 0; c < loadedFile.Length; c++)
            {
                loadedFile[c] = loadedFile[c].Trim();         // Trim whitespaces
                if (loadedFile[c].Length == 0)
                {
                    continue;                                    // Skip blank lines
                }
                if (loadedFile[c] == "\n")
                {
                    continue;
                }

                if (parser(loadedFile[c]) == 0)
                {
                    ERROR = String.Format("Parse Error at line[{0}] : {1}", c + 1, ERROR);
                    return(false);
                }
            }

            // -- POST PARSE CHECK ::

            if (tracks.Count == 0)
            {
                ERROR = "No Tracks in the CUE file"; return(false);
            }

            getCDTypeFromTracks();

            // :: Some Debug Info
            LOG.log("[CUEREADER] : Loading : `{0}`", loadedFile_path);
            LOG.log("[CUEREADER] : Title : `{0}`, Type: `{1}`, NumberOfTracks:{2}", CD_TITLE, CD_TYPE, tracks.Count);
            LOG.indent(1);
            // --

            if (loadedFile_ext == "ccd")
            {
                // TODO: CCD
            }

            // :: Go through each and every track, regardless if multitrack or not,
            //	Check for every single one of the files if exist or not
            //	Also count the number of file images to figure out `multifilecd`

            int cc = 0;     // Number of tracks with DiskFiles found

            foreach (var tr in tracks)
            {
                if (tr.indexes.Count == 0)
                {
                    ERROR = "Track [" + tr.trackNo + "] has no indexes defined"; return(false);
                }

                if (tr.trackFile == null)
                {
                    continue;
                }

                cc++;

                tr.workingFile = Path.Combine(loadedFile_dir, tr.trackFile);

                // Check the diskfiles
                if (!File.Exists(tr.workingFile))
                {
                    ERROR = "Image \"" + tr.trackFile + "\" does not exist"; return(false);
                }

                // Get Sizes
                var finfo = new FileInfo(Path.Combine(loadedFile_dir, tr.trackFile));
                tr.byteSize   = (int)finfo.Length;       // it can't be more than 800MB, so it's safe
                tr.sectorSize = (int)Math.Ceiling((double)(tr.byteSize / SECTOR_SIZE));

                // --
                if (tr.sectorSize <= 0)
                {
                    // Rare but worth checking
                    ERROR = "DiskFile " + tr.trackFile + " is currupt"; return(false);
                }

                CD_TOTAL_SIZE += tr.byteSize;
            }    // -- end each track


            // :: POST PARSE CALCULATIONS AND CHECKS ::


            // - Is it MultiTrack with MultiFiles?
            if (cc == tracks.Count && cc > 1)
            {
                LOG.log("+ MULTI-FILE Image CD");
                MULTIFILE = true;
                // Need to set sectorStart at each tracks;
                calculateTracksSectorStart();
            }
            else if (cc == 1)
            {
                LOG.log("+ SINGLE-FILE Image CD");
                MULTIFILE = false;
                // In case an single was found but not at the first track:
                if (tracks[0].trackFile == null)
                {
                    ERROR = "First track must declare an image file"; return(false);
                }

                var imageSectorSize = tracks[0].sectorSize;
                //Calculate tracks, starting from the end, backwards to 0
                var c = tracks.Count - 1;
                //Calculate last track manually, out of the loop
                tracks[c].calculateStart();
                tracks[c].sectorSize = imageSectorSize - tracks[c].sectorStart;
                while (--c >= 0)
                {
                    tracks[c].calculateStart();
                    tracks[c].sectorSize = tracks[c + 1].sectorStart - tracks[c].sectorStart;
                }

                calculateTracksByteSize();
            }
            else if (cc == 0)
            {
                ERROR = "There are no image files declared in the sheet."; return(false);
            }
            else
            {
                // Rare, and I don't know if anything does this
                ERROR = "Multiple Image sheets are restricted to one Track per Image only"; return(false);
            }

            LOG.log("+ Total CD SIZE : {0}", CD_TOTAL_SIZE);
            foreach (var tt in tracks)
            {
                LOG.log(tt);
            }
            LOG.line(); LOG.indent(0);
            return(true);
        }// -----------------------------------------