/// <summary> /// создание итема в списке для невалидной книги /// </summary> private void createNotValidateBookItem(string FilePath, FB2UnionGenres fb2g, FB2Validator fv2Validator, SharpZipLibWorker sharpZipLib) { if (File.Exists(FilePath)) { string TempDir = Settings.Settings.TempDirPath; string FileExt = Path.GetExtension(FilePath); ListViewItem.ListViewSubItem[] subItems; if (FilesWorker.isFB2File(FilePath) || FilesWorker.isFB2Archive(FilePath)) { ListViewItem item = new ListViewItem(FilePath, FilesWorker.isFB2File(FilePath) ? 1 : 2); try { if (FilesWorker.isFB2File(FilePath)) { item.ForeColor = Colors.FB2ForeColor; subItems = createSubItemsWithMetaData(FilePath, FileExt, item, ref fb2g, ref fv2Validator); } else { // для zip-архивов FilesWorker.RemoveDir(TempDir); sharpZipLib.UnZipFB2Files(FilePath, TempDir); string [] files = Directory.GetFiles(TempDir); if (FilesWorker.isFB2File(files[0])) { item.ForeColor = Colors.ZipFB2ForeColor; subItems = createSubItemsWithMetaData(files[0], FileExt, item, ref fb2g, ref fv2Validator); } else { item.ForeColor = Colors.BadZipForeColor; subItems = WorksWithBooks.createEmptySubItemsForItem(item); } } if (subItems != null) { item.SubItems.AddRange(subItems); } } catch (Exception ex) { Debug.DebugMessage( null, ex, "FB2NotValidateForm.createNotValidateBookItem(): Создание итема в списке для невалидной книги." ); subItems = WorksWithBooks.createEmptySubItemsForItem(item); if (subItems != null) { item.SubItems.AddRange(subItems); item.ForeColor = Colors.BadZipForeColor; } } item.Tag = new ListViewItemType("f", FilePath); item.BackColor = Colors.FileBackColor; if (subItems != null) { m_listViewFB2Files.Items.Add(item); } } } }
/// <summary> /// Формирование представления Групп с их книгами /// </summary> private void makeBookCopiesView(FB2FilesDataInGroup fb2BookList, ListView listViewFB2Files, ref StatusView sv) { Hashtable htBookGroups = new Hashtable(new FB2CultureComparer()); // хеш-таблица групп одинаковых книг ListViewGroup lvGroup = null; // группа одинаковых книг string Valid = string.Empty; foreach (BookData bd in fb2BookList) { ++sv.AllFB2InGroups; // число книг во всех группах одинаковых книг lvGroup = new ListViewGroup(fb2BookList.Group); ListViewItem lvi = new ListViewItem(bd.Path); if (FilesWorker.isFB2Archive(bd.Path)) { lvi.ForeColor = Colors.ZipFB2ForeColor; } lvi.SubItems.Add(MakeBookTitleString(bd.BookTitle)); lvi.SubItems.Add(MakeAuthorsString(bd.Authors)); lvi.SubItems.Add(MakeGenresString(bd.Genres)); lvi.SubItems.Add(bd.Lang); lvi.SubItems.Add(bd.Id); lvi.SubItems.Add(bd.Version); lvi.SubItems.Add(bd.Encoding); Valid = _fv2Validator.ValidatingFB2File(bd.Path); if (string.IsNullOrEmpty(Valid)) { Valid = "Да"; lvi.ForeColor = FilesWorker.isFB2File(bd.Path) ? Color.FromName("WindowText") : Colors.ZipFB2ForeColor; } else { Valid = "Нет"; lvi.ForeColor = Colors.FB2NotValidForeColor; } lvi.SubItems.Add(Valid); lvi.SubItems.Add(GetFileLength(bd.Path)); lvi.SubItems.Add(GetFileCreationTime(bd.Path)); lvi.SubItems.Add(FileLastWriteTime(bd.Path)); // заносим группу в хеш, если она там отсутствует AddBookGroupInHashTable(htBookGroups, lvGroup); // присваиваем группу книге listViewFB2Files.Groups.Add((ListViewGroup)htBookGroups[fb2BookList.Group]); lvi.Group = (ListViewGroup)htBookGroups[fb2BookList.Group]; listViewFB2Files.Items.Add(lvi); } }
/// <summary> /// Хеширование файлов в контексте Id книг: /// Одинаковый Id Книги (копии и/или разные версии правки одной и той же книги) /// </summary> /// <param name="FilesList">Список файлов для сканированияl</param> /// <param name="htFB2ForID">Хеш Таблица с книгами с одинаковыми ID</param> /// <returns>Признак непрерывности обработки файлов</returns> public bool FilesHashForIDParser(BackgroundWorker bw, DoWorkEventArgs e, Label StatusLabel, ProgressBar ProgressBar, string TempDir, List <string> FilesList, HashtableClass htFB2ForID) { StatusLabel.Text += "Хэширование по Id книг...\r"; ProgressBar.Maximum = FilesList.Count; ProgressBar.Value = 0; List <string> FinishedFilesList = new List <string>(); for (int i = 0; i != FilesList.Count; ++i) { if (FilesWorker.isFB2File(FilesList[i])) { // заполнение хеш таблицы данными о fb2-книгах в контексте их ID MakeFB2IDHashTable(null, FilesList[i], ref htFB2ForID); // обработанные файлы FinishedFilesList.Add(FilesList[i]); } else { if (FilesWorker.isFB2Archive(FilesList[i])) { try { if (_sharpZipLib.UnZipFB2Files(FilesList[i], TempDir) != -1) { string[] files = Directory.GetFiles(TempDir); if (files.Length > 0) { if (FilesWorker.isFB2File(files[0])) { // заполнение хеш таблицы данными о fb2-книгах в контексте их ID MakeFB2IDHashTable(FilesList[i], files[0], ref htFB2ForID); // обработанные файлы FinishedFilesList.Add(FilesList[i]); } } } } catch (Exception ex) { Debug.DebugMessage( FilesList[i], ex, "Дубликатор.CompareForm.FilesHashForIDParser(): Хеширование файлов в контексте Id книг." ); } FilesWorker.RemoveDir(TempDir); } } bw.ReportProgress(i); // отобразим данные в контролах if (bw.CancellationPending) { // удаление из списка всех файлов обработанных книг WorksWithBooks.removeFinishedFilesInFilesList(ref FilesList, ref FinishedFilesList); e.Cancel = true; return(false); } } // удаление элементов таблицы, value (списки) которых состоят из 1-го элемента (это не копии) _compComm.removeNotCopiesEntryInHashTable(htFB2ForID); // удаление из списка всех файлов обработанных книг WorksWithBooks.removeFinishedFilesInFilesList(ref FilesList, ref FinishedFilesList); return(true); }
/// <summary> /// Добавление Группы в Список Групп /// </summary> /// <param name="bw">BackgroundWorker</param> /// <param name="e">DoWorkEventArgs</param> /// <param name="doc">xml документ - объект класса XDocument, в который заносятся данные на книги Групп</param> /// <param name="fb2BookList">Список данных fb2 книг для конкретной Группы</param> /// <param name="BookInGroups">Число книг в Группе</param> /// <param name="GroupCountInGroups">Счетчик числа Групп</param> private void addAllBookInGroup(BackgroundWorker bw, DoWorkEventArgs e, XDocument doc, FB2FilesDataInGroup fb2BookList, ref int BookInGroups, ref int GroupCountInGroups, ref StatusView sv) { BookInGroups += fb2BookList.Count; // Добавление Группы в Список Групп XElement xeGroup = null; doc.Root.Element("Groups").Add( xeGroup = new XElement( "Group", new XAttribute("number", 0), new XAttribute("count", fb2BookList.Count), new XAttribute("name", fb2BookList.Group) ) ); int BookNumber = 0; // номер Книги (Book number) В Группе (Group) int BookCountInGroup = 0; // число Книг (Group count) в Группе (Group) foreach (BookData bd in fb2BookList) { if (bw.CancellationPending) { e.Cancel = true; return; } ++sv.AllFB2InGroups; // число книг во всех группах одинаковых книг string sForeColor = "WindowText"; if (FilesWorker.isFB2Archive(bd.Path)) { sForeColor = Colors.ZipFB2ForeColor.Name; } string Validation = _fv2Validator.ValidatingFB2File(bd.Path); if (string.IsNullOrEmpty(Validation)) { Validation = "Да"; sForeColor = FilesWorker.isFB2File(bd.Path) ? "WindowText" : Colors.ZipFB2ForeColor.Name; } else { Validation = "Нет"; sForeColor = Colors.FB2NotValidForeColor.Name; } // Добавление Книги в Группу xeGroup.Add( new XElement("Book", new XAttribute("number", ++BookNumber), new XElement("Group", fb2BookList.Group), new XElement("Path", bd.Path), new XElement("BookTitle", MakeBookTitleString(bd.BookTitle)), new XElement("Authors", MakeAuthorsString(bd.Authors)), new XElement("Genres", MakeGenresString(bd.Genres)), new XElement("BookLang", bd.Lang), new XElement("BookID", bd.Id), new XElement("Version", bd.Version), new XElement("FB2Authors", MakeAuthorsString(bd.FB2Authors)), new XElement("Encoding", bd.Encoding), new XElement("Validation", Validation), new XElement("FileLength", GetFileLength(bd.Path)), new XElement("FileCreationTime", GetFileCreationTime(bd.Path)), new XElement("FileLastWriteTime", FileLastWriteTime(bd.Path)), new XElement("ForeColor", sForeColor), new XElement("BackColor", "Window"), new XElement("IsChecked", false) ) ); xeGroup.SetAttributeValue("count", ++BookCountInGroup); if (!xeGroup.HasElements) { xeGroup.Remove(); } } // по всем книгам Группы ++GroupCountInGroups; }
/// <summary> /// Валидация fb2, fb2.zip ли fbz файлов по пути FilePath, согласно схеме SchemePath /// </summary> /// <param name="FilePath">Путь к проверяемому файлу</param> /// <param name="SchemePath">Путь к схеме fb2у</param> /// <param name="IsZip">Ссылка, проверяемый файл - архив (true)?</param> /// <returns>Пустая строка, файл валиден; Строка с сообщением, если файл невалиден</returns> private string validate(string FilePath, string SchemePath, ref bool IsZip) { string [] files = null; if (FilesWorker.isFB2Archive(FilePath)) { IsZip = true; _sharpZipLib.UnZipFB2Files(FilePath, _TempDir); files = Directory.GetFiles(_TempDir); } string FB2Path = (files != null && files.Length > 0) ? files[0] : FilePath; XmlDocument xmlDoc = new XmlDocument(); try { xmlDoc.Load(FB2Path); // Проверка наличия атрибутов корневого тега <FictionBook int FictionBookTagIndex = xmlDoc.InnerXml.IndexOf("<FictionBook", StringComparison.CurrentCulture); if (FictionBookTagIndex != -1) { Regex regex = new Regex("<FictionBook [^>]+>", RegexOptions.None); Match m = regex.Match(xmlDoc.InnerXml); if (m.Success) { string FBookTag = m.Value; int xmlnsIndex = FBookTag.IndexOf("xmlns=\"http://www.gribuser.ru/xml/fictionbook/2.", StringComparison.CurrentCulture); int xmlnsLinkIndex = FBookTag.IndexOf("=\"http://www.w3.org/1999/xlink\"", StringComparison.CurrentCulture); if (xmlnsIndex == -1) { return("Файл: " + FilePath + "\r\nВ корневом теге <FictionBook отсутствует атрибут xmlns=\"http://www.gribuser.ru/xml/fictionbook/2.0\""); } if (xmlnsLinkIndex == -1) { return("Файл: " + FilePath + "\r\nВ корневом теге <FictionBook отсутствует атрибут xmlns:l=\"http://www.w3.org/1999/xlink\""); } } } // Проверка обязательных тегов string TI = string.Empty; string DI = string.Empty; try { Regex regDesc = new Regex(@"<description>\s*?.+?\s*?</description>", RegexOptions.Multiline | RegexOptions.Singleline); Match mDesc = regDesc.Match(xmlDoc.InnerXml); if (mDesc.Success) { string Desc = mDesc.Value; Regex regTitleInfo = new Regex(@"<title-info>\s*?.+?\s*?</title-info>", RegexOptions.Multiline | RegexOptions.Singleline); Match mTI = regTitleInfo.Match(Desc); if (mTI.Success) { TI = mTI.Value; } Regex regDocumentInfo = new Regex(@"<document-info>\s*?.+?\s*?</document-info>", RegexOptions.Multiline | RegexOptions.Singleline); Match mDI = regDocumentInfo.Match(Desc); if (mDI.Success) { DI = mDI.Value; } } else { regDesc = new Regex("(?:<description[^/]+?(?:\"[^\"]*\"|'[^']*')?>)", RegexOptions.Multiline | RegexOptions.Singleline); mDesc = regDesc.Match(xmlDoc.InnerXml); return(mDesc.Success ? string.Format("Файл: {0}\r\nВ теге <description> присутствует(ет) аттрибут(ы), что недопустимо по стандарту FictionBook", FilePath) : string.Format("Файл: {0}\r\nОтсутствует раздел описания книги <description>", FilePath)); } } catch (RegexMatchTimeoutException ex) { Debug.DebugMessage( FilePath, ex, "FB2Validator.validate(): Проверка обязательных разделов fb2 структуры. Исключение RegexMatchTimeoutException." ); } catch (Exception ex) { Debug.DebugMessage( FilePath, ex, "FB2Validator.validate(): Проверка обязательных разделов fb2 структуры. Исключение Exception." ); } if (!string.IsNullOrEmpty(TI)) { // Проверка <genre> if (TI.IndexOf("<genre", StringComparison.CurrentCulture) == -1) { return(string.Format("Файл: {0}\r\nОтсутствует тег <genre> книги", FilePath)); } else { Regex regGenre = new Regex(@"(<genre ?/>)|(<genre></genre>)", RegexOptions.None); Match mGenre = regGenre.Match(TI); if (mGenre.Success) { return(string.Format("Файл: {0}\r\nТег <genre> книги 'пустой'", FilePath)); } } // Проверка <lang> if (TI.IndexOf("<lang", StringComparison.CurrentCulture) == -1) { return(string.Format("Файл: {0}\r\nОтсутствует тег <lang> книги", FilePath)); } else { Regex regLang = new Regex(@"(<lang ?/>)|(<lang></lang>)", RegexOptions.None); Match mLang = regLang.Match(TI); if (mLang.Success) { return(string.Format("Файл: {0}\r\nТег <lang> книги 'пустой'", FilePath)); } else { regLang = new Regex(@"(?<=<lang>)[^<]+(?=</lang>)", RegexOptions.None); mLang = regLang.Match(TI); if (mLang.Success) { if (mLang.Value.Length > 2) { return(string.Format("Файл: {0}\r\nТег Название языка книги (тег <lang>) не может быть более 2 символов.\r\nЗначение тега <lang>: '{1}'", FilePath, mLang.Value)); } } } } // Проверка <author> if (TI.IndexOf("<author", StringComparison.CurrentCulture) == -1) { return(string.Format("Файл: {0}\r\nОтсутствует тег <author> Автора книги", FilePath)); } else { Regex regAuthor = new Regex(@"(<author ?/>)|(<author></author>)", RegexOptions.None); Match mAuthor = regAuthor.Match(TI); if (mAuthor.Success) { return(string.Format("Файл: {0}\r\nТег <author> Автора книги 'пустой'", FilePath)); } } // Проверка <book-title> if (TI.IndexOf("<book-title", StringComparison.CurrentCulture) == -1) { return(string.Format("Файл: {0}\r\nОтсутствует тег <book-title> Названия книги", FilePath)); } else { Regex regBT = new Regex(@"(<book-title ?/>)|(<book-title></book-title>)", RegexOptions.None); Match mBT = regBT.Match(TI); if (mBT.Success) { return(string.Format("Файл: {0}\r\nТег <book-title> Названия книги 'пустой'", FilePath)); } } } else { return(string.Format("Файл: {0}\r\nОтсутствует раздел описания книги <title-info>", FilePath)); } if (!string.IsNullOrEmpty(DI)) { // Проверка id книги if (DI.IndexOf("<id", StringComparison.CurrentCulture) == -1) { return("Файл: " + FilePath + "\r\nОтсутствует идентификатор книги тег <id>"); } else { Regex regID = new Regex(@"(<id ?/>)|(<id></id>)", RegexOptions.None); Match mID = regID.Match(DI); if (mID.Success) { return(string.Format("Файл: {0}\r\nИдентификатор книги тег <id> 'пустой'", FilePath)); } } } else { return(string.Format("Файл: {0}\r\nОтсутствует раздел описания книги <document-info>", FilePath)); } } catch (Exception ex) { return(string.Format("{0}\r\n\r\nФайл: {1}", ex.Message, FilePath)); } Cursor.Current = Cursors.WaitCursor; string fb2FileNamespaceURI = xmlDoc.DocumentElement.NamespaceURI; using (Stream xmlSchemeFile = new FileStream(SchemePath, FileMode.Open)) { XmlSchemaSet sc = new XmlSchemaSet(); try { if (fb2FileNamespaceURI.Equals(_aFB21Namespace)) { sc.Add(_aFB21Namespace, XmlReader.Create(xmlSchemeFile)); } else { sc.Add(_aFB20Namespace, XmlReader.Create(xmlSchemeFile)); } } catch (System.Xml.Schema.XmlSchemaException ex) { return(string.Format( "Файл: {0}\r\n{1}\r\nСтрока: {2}; Позиция: {3}", FilePath, ex.Message, ex.LineNumber, ex.LinePosition )); } XmlReaderSettings settings = new XmlReaderSettings(); settings.ValidationType = ValidationType.Schema; settings.Schemas = sc; XmlReader reader = XmlReader.Create(FB2Path, settings); try { while (reader.Read()) { ; } reader.Close(); Cursor.Current = Cursors.Default; return(string.Empty); } catch (System.Xml.Schema.XmlSchemaException ex) { reader.Close(); Cursor.Current = Cursors.Default; return(string.Format( "Файл: {0}\r\n{1}\r\nСтрока: {2}; Позиция: {3}", FilePath, ex.Message, ex.LineNumber, ex.LinePosition )); } catch (Exception ex) { reader.Close(); Cursor.Current = Cursors.Default; return(string.Format("Файл: {0}\r\n{1}", FilePath, ex.Message)); } } }