Exemplo n.º 1
0
        /// <summary>
        /// Metoda Close, jen pro lepší přehlednost - prostě zavolá Dispose
        /// </summary>
        public void Close()
        {
            FilesIn.Clear();
            FilesToAdd.Clear();
            FilesToRemove.Clear();

            Dispose();
        }
        protected override bool ReplaceLink(ref IProcessLinkParameter parameters, LinkType linkType)
        {
            FoundLink link = ((ConceptualItemParameter)parameters).Link;
            string    href = ((ConceptualItemParameter)parameters).Href;

            string baseUrl = null;

            switch (linkType)
            {
            case LinkType.GeneralLink:
                baseUrl = BaseUrl;
                break;

            case LinkType.EnUsLink:
                baseUrl = BaseEnUsUrl;
                break;

            case LinkType.RelativeWoExt:
                baseUrl = BaseWoExtUrl;
                break;
            }

            if (baseUrl == null)
            {
                return(false);
            }

            if (Uri.TryCreate(new Uri(baseUrl), href.TrimStart('\\').TrimEnd(".md"), out Uri uri))
            {
                string query = GetQueryFromLink(link.Link);
                if (linkType == LinkType.EnUsLink)
                {
                    ReplacedEnUsLinks.AppendLine($"{SourceFilePath},{link.Link},\"{link.Title}\",{uri.AbsoluteUri},\"{link.Title + ExternalText}\"");
                }
                else
                {
                    ReplacedLinks.AppendLine($"{SourceFilePath},{link.Link},\"{link.Title}\",{uri.AbsoluteUri},\"{link.Title + ExternalText}\"");
                    string fileToRemove = href.TrimStart('\\');
                    if (!String.IsNullOrEmpty(query))
                    {
                        fileToRemove = fileToRemove.Replace(query, "");
                    }
                    if (Path.GetExtension(fileToRemove).Equals(".md", StringComparison.InvariantCultureIgnoreCase) && !FilesToRemove.Contains(fileToRemove))
                    {
                        FilesToRemove.Add(fileToRemove);
                    }
                }

                _newContent.Replace(link.FullMatch, link.FullMatch.Replace(link.Title, link.Title + ExternalText).Replace(link.Link, uri.AbsoluteUri));
                return(true);
            }
            Logger.LogWarning($"URI could not be created: {BaseUrl} {href}");
            return(false);
        }
Exemplo n.º 3
0
        /// <summary>
        /// Odstraní soubor - rozliší jestli je odstraňovaný soubor už fyzicky v archívu nebo má být teprve přidán po uložení
        /// </summary>
        /// <param name="Name">Název souboru k odstranění</param>
        public void RemoveFile(string Name)
        {
            // Zkus soubor prvně najít a odstranit ze seznamu nových souborů k přidání do archívu
            for (int i = 0; i < FilesToAdd.Count; i++)
            {
                // V kolekci FilesToAdd jsou absolutní cesty k souborů, my chceme však jen jejich názvy s příponou k porovnání
                if (Path.GetFileName(FilesToAdd[i].ToString()) == Name)
                {
                    FilesToAdd.RemoveAt(i); // Odstraň a skonči metodu
                    return;
                }
            }

            // Když tam nebyl, zkus najít a označit ke smazání takový soubor v seznamu souborů v archívu - když tam nebude metoda skončí vyjímkou (protože pomocní metoda FindFileByName skončí vyjímkou)
            FilesToRemove.Add(FindFileByName(Name));
        }
Exemplo n.º 4
0
        /// <summary>
        /// Nejsložitější metoda v celé třídě. Má na starost uložení změn provedených v archívu.
        /// </summary>
        public void SaveArchieve()
        {
            // Metoda nemá smysl, pokud není otevřen nějaký soubor
            if (!IsOpened)
            {
                throw new ArchieverException("Nepracujete s žádným souborem!");
            }

            // Do tohoto MemoryStreamu načteme všechny staré věci které mají v archívu zůstat (nebyly odstraněny) a zároveň do něj přidáme nové věci.
            using (MemoryStream MyMemory = new MemoryStream())
            {
                // Musíme tedy projít všechny soubory které chceme zachovat a "přeuložit" je do streamu MyMemory
                int ToJump = 0, CurrentSize = 0;
                for (int i = 0; i < FilesIn.Count; i++)
                {
                    // CurrentSize používám jen jako pomocnou proměnnou abych pořád nemusel dělat toto nepěkné přetypování
                    CurrentSize = ((FileHeader)FilesIn[i]).Size;

                    // Jesliže je momentální index v poli indexů pro odstranění z archívu, vynecháme jej, ale musíme s ním počítat i při přeskoku pomocí Seek
                    if (FilesToRemove.IndexOf(i) > -1)
                    {
                        ToJump += CurrentSize;
                        continue; // Jak jistě víte, příkaz continue ukončí momentální iteraci, ale ne samotný cyklus.
                    }

                    // Přeskoč na daný soubor
                    MyArchieve.Seek((long)(FilesBegin + ToJump), SeekOrigin.Begin);

                    // Opět se zde vědomě dopouštím stejné chyby jako v indexeru, viz. komentáře v kódu indexeru
                    byte[] buffer = new byte[CurrentSize];
                    MyArchieve.Read(buffer, 0, CurrentSize);
                    MyMemory.Write(buffer, 0, CurrentSize);

                    ToJump += CurrentSize;
                }

                // Teď už můžeme z FilesIn skutečně bezpečně odstranit všechny ty indexy, které jsou v poli FilesToRemove
                foreach (int index in FilesToRemove)
                {
                    FilesIn.RemoveAt(index);
                }

                // Další krok bude přidání nových souborů do archívu...

                byte[] buf = new byte[1024];
                // V BytesRead bude počet bajtů který se přečtl při jedné blokové operaci.V TotalSize nasčítáme počet všech přečtěných bajtů, což je totéž jako velikost souboru
                int BytesRead = 0, TotalSize = 0;
                foreach (string PathToFile in FilesToAdd)
                {
                    try // Zde by mohla nastat spousta špatností, protože pracujeme s filesystémem
                    {
                        // Toto je již velmi známá konstrukce čtení dat po pevných blocích - netřeba dál komentovat.
                        using (FileStream MyNewFile = File.OpenRead(PathToFile))
                        {
                            TotalSize = 0;
                            while ((BytesRead = MyNewFile.Read(buf, 0, 1024)) > 0)
                            {
                                MyMemory.Write(buf, 0, BytesRead);
                                TotalSize += BytesRead;
                            }
                        }
                    }
                    catch (Exception e) // Chytej jakoukoliv vyjímku
                    {
                        // Vyhoď vyjímku ArchieverException s textem původní vyjímky která nastala
                        throw new ArchieverException(e.Message);
                    } // Všimněte si, že díky bloku using() nemusíme používat finally a v něm stream zavírat!

                    // Když všechno prošlo bez chyby, tak vytvoříme pro nový soubor hlavičku a přidáme ji do pole FilesIn
                    FileHeader MyNewHeader = new FileHeader();
                    MyNewHeader.Name = Path.GetFileName(PathToFile);
                    MyNewHeader.Size = TotalSize;
                    FilesIn.Add(MyNewHeader);
                }

                // Vyčistíme kolekce FilesToAdd a FilesToRemove
                FilesToAdd.Clear();
                FilesToRemove.Clear();

                // V posledním kroku prostě přepíšeme původní stream MyArchieve novou hlavičkou a tím co máme v MyMemory streamu
                MyArchieve.Seek(0, SeekOrigin.Begin);
                MyArchieve.SetLength(0); // Toto zničí všechny data ve streamu (zkrátí délku souboru na 0)

                // První čtyři bajty archívu je počet souborů v něm (opět používáme BitConverter)
                MyArchieve.Write(BitConverter.GetBytes(FilesIn.Count), 0, 4);

                // Teď zapíšeme názvy souborů (s ohledem na 150 bajtový limit jeho délky) a hned za něj jeho velikost, celkem tedy 154 bajtů (v případě že někdo nezmění NameMaxLength na jinou hodnotu než 150)
                foreach (FileHeader item in FilesIn)
                {
                    // Toto pole bajtů má přesně takovou velikost jako je délka názvu souboru v kódování systému
                    byte[] bytesOfName = Encoding.Default.GetBytes(item.Name);

                    // Musíme velikost pole bytesOfName zarovnat na NameMaxLength, což je v našem případě 150
                    byte[] normalizedName = new byte[NameMaxLength];

                    // Pozorně prosím prostudujte jak pracuje tento cyklus (kopíruje z pole s názvem souboru do normalizovaného pole od délce NameMaxLength, když je delší - oseká se)
                    for (int i = 0; i < (bytesOfName.Length > NameMaxLength ? NameMaxLength : bytesOfName.Length); i++)
                    {
                        normalizedName[i] = bytesOfName[i];
                    }

                    MyArchieve.Write(normalizedName, 0, NameMaxLength);
                    MyArchieve.Write(BitConverter.GetBytes(item.Size), 0, 4);
                }

                // ... a úplně nakonec zapíšeme všechny soubory, které již máme připraveny v MyMemory - tam jsou ve stejném pořadí tak jako v hlavičce.
                MyArchieve.Write(MyMemory.ToArray(), 0, (int)MyMemory.Length);
            } // A HOTOVO! (Všimněte si, že celý kód metody byl v postatě "zabalen" v bloku od using(MemoryStream MyMemory ...) takže ať se stalo cokoliv bude vždycky zavřen!
        }
        public override bool ProcessContentLinks()
        {
            string fname  = Path.GetFileName(SourceFilePath);
            bool   yml    = string.Equals(fname, "toc.yml", StringComparison.InvariantCultureIgnoreCase);
            bool   result = string.Equals(fname, "toc.md", StringComparison.InvariantCultureIgnoreCase) ||
                            yml ||
                            ContentHasAudienceApplicationUser(_content);

            if (result)
            {
                FoundLink[] links = FindAllLinks(yml, _content);
                Links.AddRange(links.Select(l => l.FullMatch));
                foreach (FoundLink link in links.GroupBy(k => k).Select(k => k.Key))
                {
                    if (String.IsNullOrEmpty(link.Link.Trim()))
                    {
                        continue;
                    }

                    string linkClear = CleanLinkOfQueryAndHash(link.Link);

                    if (linkClear.StartsWith("http", StringComparison.InvariantCultureIgnoreCase) ||
                        linkClear.EndsWith("toc.md", StringComparison.InvariantCultureIgnoreCase) ||
                        linkClear.EndsWith("toc.yml", StringComparison.InvariantCultureIgnoreCase) ||
                        linkClear.StartsWith("mailto", StringComparison.InvariantCultureIgnoreCase))
                    {
                        continue;
                    }

                    try
                    {
                        string href = BuildFullUrl("/" + SourceFilePath, linkClear);
                        ProcessLink(href, link.Link, new ConceptualItemParameter(ref _content, link, href));
                    }
                    catch (Exception ex)
                    {
                        Logger.LogWarning($"Message: \"{ex.Message}\", File: \"{fname}\", Href: \"{link.Link}\"");
                    }
                }

                FoundPicture[] pictures = FindAllPictures(_content);
                Pictures.AddRange(pictures.Select(p => p.FullMatch));
                foreach (FoundPicture picture in pictures)
                {
                    try
                    {
                        string href = BuildFullUrl("/" + SourceFilePath, GetOnlyLink(picture.Link1));
                        ProcessLink(href, picture.Link1, null);

                        if (!String.IsNullOrEmpty(picture.Link2) && !picture.Link1.Equals(picture.Link2))
                        {
                            string link2 = CleanLinkOfQueryAndHash(GetOnlyLink(picture.Link2));
                            href = BuildFullUrl("/" + SourceFilePath, link2);
                            ProcessLink(href, picture.Link2, null);
                        }
                    }
                    catch (Exception ex)
                    {
                        Logger.LogWarning($"Message: \"{ex.Message}\", File: \"{fname}\", Link1: \"{picture.Link1}\", Link2: \"{picture.Link2}\"");
                    }
                }

                FoundLink[] includes = FindIncludedLinks(_content);
                foreach (FoundLink link in includes.GroupBy(k => k).Select(k => k.Key))
                {
                    if (String.IsNullOrEmpty(link.Link.Trim()))
                    {
                        continue;
                    }

                    string linkClear = CleanLinkOfQueryAndHash(link.Link);

                    if (linkClear.StartsWith("http", StringComparison.InvariantCultureIgnoreCase) ||
                        linkClear.EndsWith("toc.md", StringComparison.InvariantCultureIgnoreCase) ||
                        linkClear.EndsWith("toc.yml", StringComparison.InvariantCultureIgnoreCase))
                    {
                        continue;
                    }

                    try
                    {
                        string href = BuildFullUrl("/" + SourceFilePath, linkClear);
                        if (!FilesToIgnore.Contains(href.TrimStart('\\')))
                        {
                            FilesToIgnore.Add(href.TrimStart('\\'));
                        }
                    }
                    catch (Exception ex)
                    {
                        Logger.LogWarning($"Message: \"{ex.Message}\", File: \"{fname}\", Href: \"{link.Link}\"");
                    }
                }
                return(HasModified);
            }
            if (!(fname != null && fname.Equals("toc.md", StringComparison.InvariantCultureIgnoreCase)))
            {
                FilesToRemove.Add(SourceFilePath.TrimStart('\\'));
            }
            return(false);
        }