Пример #1
0
        public static ObjectData Decode(byte[] bytes)
        {
            if (bytes == null)
            {
                return(null);
            }

            bytes = LZMACoder.Uncompress(bytes);

            using (BinaryReader reader = new BinaryReader(new MemoryStream(bytes)))
            {
                ushort version = reader.ReadUInt16();

                if (version == (ushort)ObdVersion.Version3)
                {
                    return(DecodeV3(reader));
                }
                else if (version == (ushort)ObdVersion.Version2)
                {
                    return(DecodeV2(reader));
                }
                else if (version >= (ushort)DatFormat.Format_710)
                {
                    return(DecodeV1(reader));
                }
                else
                {
                    ////
                }
            }

            return(null);
        }
Пример #2
0
        /// <summary>
        ///    Writes the current replay to a binary file.
        /// </summary>
        public void Write(string path)
        {
            var frames = FramesToString();

            ReplayVersion = CurrentVersion;

            using (var replayDataStream = new MemoryStream(Encoding.ASCII.GetBytes(frames)))
                using (var bw = new BinaryWriter(File.Open(path, FileMode.Create)))
                {
                    bw.Write(ReplayVersion);
                    bw.Write(MapMd5);
                    bw.Write(GetMd5(frames));
                    bw.Write(PlayerName);
                    bw.Write(DateTime.Now.ToString(CultureInfo.InvariantCulture));
                    bw.Write(TimePlayed);
                    bw.Write((int)Mode);
                    bw.Write((int)Mods);
                    bw.Write(Score);
                    bw.Write(Accuracy);
                    bw.Write(MaxCombo);
                    bw.Write(CountMarv);
                    bw.Write(CountPerf);
                    bw.Write(CountGreat);
                    bw.Write(CountGood);
                    bw.Write(CountOkay);
                    bw.Write(CountMiss);
                    bw.Write(PauseCount);
                    bw.Write(RandomizeModifierSeed);
                    bw.Write(StreamHelper.ConvertStreamToByteArray(LZMACoder.Compress(replayDataStream)));
                }
        }
Пример #3
0
        public static byte[] Decompress(byte[] inputBytes)
        {
            byte[] result;

            using (LZMACoder coder = new LZMACoder())
                using (MemoryStream input = new MemoryStream(inputBytes))
                    using (MemoryStream output = new MemoryStream())
                    {
                        coder.Decompress(input, output);

                        result = output.ToArray();
                    }

            return(result);
        }
Пример #4
0
        /// <summary>
        ///    Writes the current replay to a binary file.
        /// </summary>
        public void Write(string path)
        {
            var frames = FramesToString();

            // TOOD: This should be removed when everyone is running the new redesign client
            // This will manually downgrade the replay version if the user isn't using new modifiers to keep
            // compatibility between old and new clients.
            // 0.0.1 used to write the modifiers as a 32-bit integer, but because of the amount of new mods, they need
            // to be written as 64-bit.
            ReplayVersion = Mods < ModIdentifier.Speed105X ? "0.0.1" : CurrentVersion;

            using (var replayDataStream = new MemoryStream(Encoding.ASCII.GetBytes(frames)))
                using (var bw = new BinaryWriter(File.Open(path, FileMode.Create)))
                {
                    bw.Write(ReplayVersion);
                    bw.Write(MapMd5);
                    bw.Write(GetMd5(frames));
                    bw.Write(PlayerName);
                    bw.Write(DateTime.Now.ToString(CultureInfo.InvariantCulture));
                    bw.Write(TimePlayed);
                    bw.Write((int)Mode);
                    // This check is to keep compatibility with older clients.
                    // We only want to write a 64-bit integer for replays with newer mods activated
                    if (ReplayVersion == "0.0.1" || Mods < ModIdentifier.Speed105X)
                    {
                        bw.Write((int)Mods);
                    }
                    else
                    {
                        bw.Write((long)Mods);
                    }
                    bw.Write(Score);
                    bw.Write(Accuracy);
                    bw.Write(MaxCombo);
                    bw.Write(CountMarv);
                    bw.Write(CountPerf);
                    bw.Write(CountGreat);
                    bw.Write(CountGood);
                    bw.Write(CountOkay);
                    bw.Write(CountMiss);
                    bw.Write(PauseCount);
                    bw.Write(RandomizeModifierSeed);
                    bw.Write(StreamHelper.ConvertStreamToByteArray(LZMACoder.Compress(replayDataStream)));
                }
        }
Пример #5
0
        private bool Download(CacheContentFile file)
        {
            var fileName        = Path.Combine(Location, file.Name);
            var outputDirectory = Path.GetDirectoryName(fileName);
            var temporaryFile   = Path.Combine(outputDirectory, file.SHA1Hash + ".cpart");
            var URL             = _server + file.Cache + "/" + file.Name;

            if (!Directory.Exists(outputDirectory))
            {
                Directory.CreateDirectory(outputDirectory);
            }
            int startAt = 0;

            Log.Info(String.Format("Starting to download {0}, {1} bytes.", file.Name, file.Size));
            if (File.Exists(temporaryFile))
            {
                //resume the download
                if (_usecpart)
                {
                    var fi = new FileInfo(temporaryFile);
                    startAt = (int)fi.Length;
                    SendStatus(StatusChangedEnum.FileDownloading, new object[] { file.Name, file.CompressedSize, startAt }, startAt);
                    Log.Info(String.Format("Partial file for {1} found, starting download at {0} bytes.", startAt, file.Name));
                }
                else
                {
                    File.Delete(temporaryFile);
                }
            }
            bool compressed = false;

#if !DEBUG
            try
            {
#endif
            if (Utilities.URLExists(URL + ".lzma"))
            {
                compressed = true;
                URL       += ".lzma";
                SendStatus(StatusChangedEnum.FileDownloadingLzma, file.Name, 0);
                Log.Info(String.Format("Found a compressed file for {0}.", fileName));
            }
            Stream inStream, outStream;
            if (startAt != file.Size && startAt != file.CompressedSize)     //if they equal, ._.
            {
                // initialize request
                var webRequest = (HttpWebRequest)WebRequest.Create(URL);
                webRequest.AddRange(startAt);

                var webResponse = (HttpWebResponse)webRequest.GetResponse();

                inStream  = webResponse.GetResponseStream();
                outStream = File.Open(temporaryFile, FileMode.Append, FileAccess.Write, FileShare.Read);

                var buffer    = new byte[2048];
                var lastBytes = 0;

                while ((lastBytes = inStream.Read(buffer, 0, buffer.Length)) > 0)
                {
                    outStream.Write(buffer, 0, lastBytes);
                    SendStatus(StatusChangedEnum.FileDownloading, new object[] { file.Name, file.CompressedSize, lastBytes }, lastBytes);
                }

                // clean up the streams
                inStream.Close();
                outStream.Close();
                SendStatus(StatusChangedEnum.FileDownloadFinish, file.Name, 0);
            }
            if (compressed)
            {
                try
                {
                    // decompress the temp file
                    var tempDecPath = fileName + ".deco";
                    var decoder     = new LZMACoder();
                    SendStatus(StatusChangedEnum.FileDecompressStart, file.Name, 0);
                    Log.Info("decompressing " + file.Name);

                    inStream  = File.OpenRead(temporaryFile);
                    outStream = File.Open(tempDecPath, FileMode.Create);

                    try
                    {
                        decoder.Decompress(inStream, outStream);
                    }
                    catch (ApplicationException ex)
                    {
                        inStream.Close();
                        outStream.Close();

                        throw ex;
                    }

                    inStream.Close();
                    outStream.Close();

                    File.Delete(temporaryFile);
                    File.Move(tempDecPath, temporaryFile);
                    SendStatus(StatusChangedEnum.FileDecompressFinish, file.Name, 0);
                }
                catch (ApplicationException e)
                {
                    // lzma sdk threw an error.
                    File.Delete(temporaryFile);
                    Log.Error(String.Format("LZMA file failed to decompress. {0}", e.ToString()));
                    _lastException = e;
                    return(false);
                }
            }
            // check the temp file's validity
            SendStatus(StatusChangedEnum.FileVerifyStart, file.Name, 0);
            var outHash = Utilities.GetFileSHA1(temporaryFile);
            var inHash  = file.SHA1Hash;

            if (inHash != outHash)
            {
                _lastException = new Exception("Hash verification failed for " + fileName);
                Log.Error("Hash verification failed for " + fileName);
                File.Delete(temporaryFile);
                SendStatus(StatusChangedEnum.FileVerifyFailed, file.Name, 0);
                return(false);
            }
            SendStatus(StatusChangedEnum.FileVerifyFinish, file.Name, 0);
            // and rename the temp file, and then delete it
            File.Copy(temporaryFile, fileName, true);
            File.Delete(temporaryFile);
            return(true);

#if !DEBUG
        }

        catch (Exception e) {
            Log.Error(String.Format("Error while downloading {0}.", e.ToString()));
            _lastException = e;
        }
        return(false);
#endif
        }
Пример #6
0
        private static byte[] EncodeV1(ObjectData data)
        {
            using (FlagsBinaryWriter writer = new FlagsBinaryWriter(new MemoryStream()))
            {
                // write client version
                writer.Write((ushort)DatFormat.Format_1010);

                // write category
                string category = string.Empty;
                switch (data.Category)
                {
                case ThingCategory.Item:
                    category = "item";
                    break;

                case ThingCategory.Outfit:
                    category = "outfit";
                    break;

                case ThingCategory.Effect:
                    category = "effect";
                    break;

                case ThingCategory.Missile:
                    category = "missile";
                    break;
                }

                writer.Write((ushort)category.Length);
                writer.Write(Encoding.UTF8.GetBytes(category));

                if (!ThingTypeSerializer.WriteProperties(data.ThingType, DatFormat.Format_1010, writer))
                {
                    return(null);
                }

                FrameGroup group = data.GetFrameGroup(FrameGroupType.Default);

                writer.Write(group.Width);
                writer.Write(group.Height);

                if (group.Width > 1 || group.Height > 1)
                {
                    writer.Write(group.ExactSize);
                }

                writer.Write(group.Layers);
                writer.Write(group.PatternX);
                writer.Write(group.PatternY);
                writer.Write(group.PatternZ);
                writer.Write(group.Frames);

                Sprite[] sprites = data.Sprites[FrameGroupType.Default];
                for (int i = 0; i < sprites.Length; i++)
                {
                    Sprite sprite = sprites[i];
                    byte[] pixels = sprite.GetARGBPixels();
                    writer.Write((uint)sprite.ID);
                    writer.Write((uint)pixels.Length);
                    writer.Write(pixels);
                }

                return(LZMACoder.Compress(((MemoryStream)writer.BaseStream).ToArray()));
            }
        }
Пример #7
0
        private static byte[] EncodeV2(ObjectData data)
        {
            using (FlagsBinaryWriter writer = new FlagsBinaryWriter(new MemoryStream()))
            {
                // write obd version
                writer.Write((ushort)ObdVersion.Version2);

                // write client version
                writer.Write((ushort)DatFormat.Format_1050);

                // write category
                writer.Write((byte)data.Category);

                // skipping the texture patterns position.
                int patternsPosition = (int)writer.BaseStream.Position;
                writer.Seek(4, SeekOrigin.Current);

                if (!WriteProperties(data.ThingType, writer))
                {
                    return(null);
                }

                // write the texture patterns position.
                int position = (int)writer.BaseStream.Position;
                writer.Seek(patternsPosition, SeekOrigin.Begin);
                writer.Write((uint)writer.BaseStream.Position);
                writer.Seek(position, SeekOrigin.Begin);

                FrameGroup group = data.GetFrameGroup(FrameGroupType.Default);

                writer.Write(group.Width);
                writer.Write(group.Height);

                if (group.Width > 1 || group.Height > 1)
                {
                    writer.Write(group.ExactSize);
                }

                writer.Write(group.Layers);
                writer.Write(group.PatternX);
                writer.Write(group.PatternY);
                writer.Write(group.PatternZ);
                writer.Write(group.Frames);

                if (group.IsAnimation)
                {
                    writer.Write((byte)group.AnimationMode);
                    writer.Write(group.LoopCount);
                    writer.Write(group.StartFrame);

                    for (int i = 0; i < group.Frames; i++)
                    {
                        writer.Write((uint)group.FrameDurations[i].Minimum);
                        writer.Write((uint)group.FrameDurations[i].Maximum);
                    }
                }

                Sprite[] sprites = data.Sprites[FrameGroupType.Default];
                for (int i = 0; i < sprites.Length; i++)
                {
                    Sprite sprite = sprites[i];
                    byte[] pixels = sprite.GetARGBPixels();
                    writer.Write(sprite.ID);
                    writer.Write(pixels);
                }

                return(LZMACoder.Compress(((MemoryStream)writer.BaseStream).ToArray()));
            }
        }
Пример #8
0
        /// <summary>
        ///     Ctor - Read replay.
        /// </summary>
        /// <param name="path"></param>
        /// <param name="readHeaderless"></param>
        public Replay(string path, bool readHeaderless = false)
        {
            if (!File.Exists(path))
            {
                throw new FileNotFoundException();
            }

            // Read the replay data
            using (var fs = new FileStream(path, FileMode.Open))
                using (var br = new BinaryReader(fs))
                {
                    if (!readHeaderless)
                    {
                        // Version None (Original data)
                        ReplayVersion = br.ReadString();
                        MapMd5        = br.ReadString();
                        Md5           = br.ReadString();
                        PlayerName    = br.ReadString();
                        Date          = Convert.ToDateTime(br.ReadString(), CultureInfo.InvariantCulture);
                        TimePlayed    = br.ReadInt64();

                        // The dates are serialized incorrectly in older replays, so to keep compatibility,
                        // use the time played.
                        Date = new DateTime(1970, 1, 1, 0, 0, 0, 0).AddMilliseconds(TimePlayed);

                        Mode = (GameMode)br.ReadInt32();

                        // The mirror mod is the 32-nd bit, which, when read as an Int32, results in a negative number.
                        // To fix this, that case is handled separately.
                        if (ReplayVersion == "0.0.1" || ReplayVersion == "None")
                        {
                            var mods = br.ReadInt32();

                            // First check if the mods are None, which is -1 (all bits set). This doesn't cause issues because
                            // there are incompatible mods among the first 32 (like all the speed mods), so all first 32 bits
                            // can't be 1 simultaneously unless it's a None.
                            if (mods == -1)
                            {
                                Mods = ModIdentifier.None;
                                mods = 0;
                            }
                            else if (mods < 0)
                            {
                                // If the 32-nd bit is set, add the Mirror mod and unset the 32-nd bit.
                                Mods  = ModIdentifier.Mirror;
                                mods &= ~(1 << 31);
                            }
                            // Add the rest of the mods.
                            Mods |= (ModIdentifier)mods;
                        }
                        else
                        {
                            Mods = (ModIdentifier)br.ReadInt64();
                        }

                        Score      = br.ReadInt32();
                        Accuracy   = br.ReadSingle();
                        MaxCombo   = br.ReadInt32();
                        CountMarv  = br.ReadInt32();
                        CountPerf  = br.ReadInt32();
                        CountGreat = br.ReadInt32();
                        CountGood  = br.ReadInt32();
                        CountOkay  = br.ReadInt32();
                        CountMiss  = br.ReadInt32();
                        PauseCount = br.ReadInt32();

                        // Versions beyond None
                        if (ReplayVersion != "None")
                        {
                            var replayVersion = new Version(ReplayVersion);

                            if (replayVersion >= new Version("0.0.1"))
                            {
                                RandomizeModifierSeed = br.ReadInt32();
                            }
                        }
                    }

                    // Create the new list of replay frames.
                    Frames = new List <ReplayFrame>();

                    // Split the frames up by commas
                    var frames = new List <string>();

                    if (!readHeaderless)
                    {
                        frames = Encoding.ASCII.GetString(LZMACoder.Decompress(br.BaseStream).ToArray()).Split(',').ToList();
                    }
                    else
                    {
                        frames = Encoding.ASCII.GetString(LZMACoder.Decompress(br.ReadBytes((int)br.BaseStream.Length))).Split(',').ToList();
                    }

                    // Add all the replay frames to the object
                    foreach (var frame in frames)
                    {
                        try
                        {
                            // Split up the frame string by SongTime|KeyPressState
                            var frameSplit = frame.Split('|');

                            Frames.Add(new ReplayFrame(int.Parse(frameSplit[0]), (ReplayKeyPressState)Enum.Parse(typeof(ReplayKeyPressState), frameSplit[1])));
                        }
                        catch (Exception e)
                        {
                            continue;
                        }
                    }
                }
        }
Пример #9
0
        /// <summary>
        ///     Ctor - Read replay.
        /// </summary>
        /// <param name="path"></param>
        /// <param name="readHeaderless"></param>
        public Replay(string path, bool readHeaderless = false)
        {
            if (!File.Exists(path))
            {
                throw new FileNotFoundException();
            }

            // Read the replay data
            using (var fs = new FileStream(path, FileMode.Open))
                using (var br = new BinaryReader(fs))
                {
                    if (!readHeaderless)
                    {
                        // Version None (Original data)
                        ReplayVersion = br.ReadString();
                        MapMd5        = br.ReadString();
                        Md5           = br.ReadString();
                        PlayerName    = br.ReadString();
                        Date          = Convert.ToDateTime(br.ReadString(), CultureInfo.InvariantCulture);
                        TimePlayed    = br.ReadInt64();

                        // The dates are serialized incorrectly in older replays, so to keep compatibility,
                        // use the time played.
                        Date = new DateTime(1970, 1, 1, 0, 0, 0, 0).AddMilliseconds(TimePlayed);

                        Mode       = (GameMode)br.ReadInt32();
                        Mods       = (ModIdentifier)br.ReadInt32();
                        Score      = br.ReadInt32();
                        Accuracy   = br.ReadSingle();
                        MaxCombo   = br.ReadInt32();
                        CountMarv  = br.ReadInt32();
                        CountPerf  = br.ReadInt32();
                        CountGreat = br.ReadInt32();
                        CountGood  = br.ReadInt32();
                        CountOkay  = br.ReadInt32();
                        CountMiss  = br.ReadInt32();
                        PauseCount = br.ReadInt32();

                        // Versions beyond None
                        if (ReplayVersion != "None")
                        {
                            var replayVersion = new Version(ReplayVersion);

                            if (replayVersion >= new Version("0.0.1"))
                            {
                                RandomizeModifierSeed = br.ReadInt32();
                            }
                        }
                    }

                    // Create the new list of replay frames.
                    Frames = new List <ReplayFrame>();

                    // Split the frames up by commas
                    var frames = new List <string>();

                    if (!readHeaderless)
                    {
                        frames = Encoding.ASCII.GetString(LZMACoder.Decompress(br.BaseStream).ToArray()).Split(',').ToList();
                    }
                    else
                    {
                        frames = Encoding.ASCII.GetString(LZMACoder.Decompress(br.ReadBytes((int)br.BaseStream.Length))).Split(',').ToList();
                    }

                    // Add all the replay frames to the object
                    foreach (var frame in frames)
                    {
                        try
                        {
                            // Split up the frame string by SongTime|KeyPressState
                            var frameSplit = frame.Split('|');

                            Frames.Add(new ReplayFrame(int.Parse(frameSplit[0]), (ReplayKeyPressState)Enum.Parse(typeof(ReplayKeyPressState), frameSplit[1])));
                        }
                        catch (Exception e)
                        {
                            continue;
                        }
                    }
                }
        }
Пример #10
0
        static void Main(string[] args)
        {
            //some logical steps to help my mind code :>
            //1. read Caches folder, if a caches.xml file is found, go to step 3, if not, 2
            //2. get all the directories inside the Caches folder, add those to a list with version number being 0
            //3. get all the caches inside the cache file, add those to a list with its version number
            //4. read all cache folders recursively, if an info.xml file exists, use that file to verify if any files have changed.
            //5. any files that haven't changed (or all if an info.xml file doesn't exist) or are new should be compressed and added to the info.xml file
            //6. build the caches.xml file with an incremented version (if the info.xml file has changed)
            //7. copy all files to be uploaded (caches.xml + directories with info.xml and only files to be uploaded (lzma's)) to the CacheUpload folder

            Environment.CurrentDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

            var cf = CombinePaths(Environment.CurrentDirectory, "Caches", "caches.xml");

            try
            {
                Directory.Delete(CombinePaths(Environment.CurrentDirectory, "CachesUpload"), true);
            }
            catch (DirectoryNotFoundException)
            {
            }

            var cacheDict    = new SortedDictionary <string, int>();
            var cacheChanged = new SortedDictionary <string, bool>();

            if (File.Exists(cf))
            {
                foreach (var el in XDocument.Parse(File.ReadAllText(cf, Encoding.UTF8)).Element("Caches").Elements())
                {
                    cacheDict.Add(el.Attribute("ID").Value, int.Parse(el.Attribute("Version").Value));
                }
            }
            foreach (var dir in Directory.GetDirectories(Path.Combine(Environment.CurrentDirectory, "Caches")))
            {
                if (!cacheDict.ContainsKey(Path.GetFileName(dir)))
                {
                    cacheDict.Add(Path.GetFileName(dir), 0);
                }
            }
            foreach (var keyval in cacheDict)
            {
                var changed       = false;
                var CCFList       = new SortedDictionary <string, CacheContentFile>();
                var infoXML       = new XDocument();
                var currentFolder = CombinePaths(Environment.CurrentDirectory, "Caches", keyval.Key);
                if (File.Exists(CombinePaths(currentFolder, "info.xml")))
                {
                    foreach (var el in XDocument.Parse(File.ReadAllText(CombinePaths(currentFolder, "info.xml"), Encoding.UTF8)).Element("CacheInfo").Elements())
                    {
                        var name = el.Attribute("Name").Value;
                        if (File.Exists(CombinePaths(currentFolder, name)))
                        {
                            var size           = long.Parse(el.Attribute("Size").Value);
                            var sizeCompressed = long.Parse(el.Attribute("CompressedSize").Value);
                            var hash           = el.Attribute("SHA1Hash").Value;
                            CCFList.Add(name, new CacheContentFile
                            {
                                SHA1Hash       = hash,
                                Size           = size,
                                CompressedSize = sizeCompressed
                            });
                        }
                    }
                }
                foreach (var file in GetFilesRecursive(currentFolder))
                {
                    var afile = file.Replace(currentFolder, "").Substring(1).Replace("\\", "/"); //remove current folder and the slash, replace \ with / for linux (still works on windows)

                    if (Path.GetFileName(afile) == "info.xml" || Path.GetExtension(afile) == ".lzma")
                    {
                        continue;                                                                               //both files shouldn't be here!!!1
                    }
                    var  length           = new FileInfo(Path.Combine(currentFolder, afile)).Length;
                    var  lengthCompressed = length;
                    var  hash             = GetFileSHA1(Path.Combine(currentFolder, afile));
                    bool compressed       = true;
                    if (!CCFList.ContainsKey(afile) || CCFList[afile].SHA1Hash != hash || CCFList[afile].Size != length)
                    {
                        changed = true;
                        //doesn't exist in info.xml, hash changed or size changed
                        var pathToGo = CombinePaths(Environment.CurrentDirectory, "CacheUpload", keyval.Key, afile);
                        if (length < 75 * 1024 * 1024) //bigger than 75mb = no compress (should work for most situations)
                        {
                            var lz       = new LZMACoder();
                            var inStream = File.Open(Path.Combine(currentFolder, afile), FileMode.Open, FileAccess.Read);
                            Directory.CreateDirectory(Path.GetDirectoryName(pathToGo));
                            var outStream = File.Open(pathToGo + ".lzma", FileMode.Create, FileAccess.Write);
                            try
                            {
                                Console.WriteLine("Compressing {0} to {1}....", Path.Combine(currentFolder, afile), pathToGo + ".lzma");
                                lz.Compress(inStream, outStream);

                                inStream.Close();
                                outStream.Close();
                                lengthCompressed = new FileInfo(pathToGo + ".lzma").Length;
                            }
                            catch (Exception e)
                            {
                                Console.WriteLine("Failed to compress {0}, {1}", file, e.ToString());
                                inStream.Close();
                                outStream.Close();
                                compressed = false;
                                File.Delete(pathToGo + ".lzma");
                            }
                        }
                        if (!compressed)
                        {
                            File.Copy(Path.Combine(currentFolder, afile), pathToGo, true);
                        }
                        if (CCFList.ContainsKey(afile))
                        {
                            CCFList[afile].Size           = length;
                            CCFList[afile].CompressedSize = lengthCompressed;
                            CCFList[afile].SHA1Hash       = hash;
                        }
                        else
                        {
                            CCFList.Add(afile, new CacheContentFile
                            {
                                Size           = length,
                                CompressedSize = lengthCompressed,
                                SHA1Hash       = hash
                            });
                        }
                    }
                }
                infoXML = new XDocument(
                    new XElement("CacheInfo")
                    );

                foreach (var keyval2 in CCFList)
                {
                    infoXML.Element("CacheInfo").Add(
                        new XElement("CacheFile",
                                     new XAttribute("Name", keyval2.Key),
                                     new XAttribute("Size", keyval2.Value.Size.ToString()),
                                     new XAttribute("CompressedSize", keyval2.Value.CompressedSize.ToString()),
                                     new XAttribute("SHA1Hash", keyval2.Value.SHA1Hash)
                                     )
                        );
                }
                cacheChanged.Add(keyval.Key, changed);
                //  using (XmlTextWriter writer = new XmlTextWriter(Path.Combine(currentFolder, "info.xml"), null))
                //  {
                //      infoXML.Save(writer);
                ////   }
                Store(infoXML, Path.Combine(currentFolder, "info.xml"));
                Directory.CreateDirectory(Path.GetDirectoryName(CombinePaths(Environment.CurrentDirectory, "CacheUpload", keyval.Key, "info.xml")));
                File.Copy(Path.Combine(currentFolder, "info.xml"), CombinePaths(Environment.CurrentDirectory, "CacheUpload", keyval.Key, "info.xml"), true);
            }
            var caches = new XDocument(
                new XElement("Caches")
                );

            foreach (var keyval3 in cacheDict)
            {
                caches.Element("Caches").Add(
                    new XElement("Cache",
                                 new XAttribute("ID", keyval3.Key),
                                 new XAttribute("Version", (keyval3.Value + (cacheChanged[keyval3.Key] ? 1 : 0)).ToString())
                                 )
                    );
            }
            //  using (XmlTextWriter writer = new XmlTextWriter(CombinePaths(Environment.CurrentDirectory, "Caches", "caches.xml"), null))
            //  {
            //      caches.Save(writer);
            //   }
            Store(caches, CombinePaths(Environment.CurrentDirectory, "Caches", "caches.xml"));
            Directory.CreateDirectory(Path.GetDirectoryName(CombinePaths(Environment.CurrentDirectory, "Caches", "caches.xml")));
            File.Copy(CombinePaths(Environment.CurrentDirectory, "Caches", "caches.xml"), CombinePaths(Environment.CurrentDirectory, "CacheUpload", "caches.xml"), true);
        }