#include "Fb2File.h" #include "../DesktopEditor/xml/include/xmlutils.h" #include "../DesktopEditor/xml/include/xmlencoding.h" #include "../DesktopEditor/common/Base64.h" #include "../DesktopEditor/common/File.h" #include "../DesktopEditor/common/Directory.h" #include "../DesktopEditor/common/StringBuilder.h" #include "../DesktopEditor/common/SystemUtils.h" #include "../DesktopEditor/raster/BgraFrame.h" #include "../OfficeUtils/src/OfficeUtils.h" #include "../Common/3dParty/html/htmltoxhtml.h" #include "./template/template.h" #include #include #include #include #include #include #include #ifndef VALUE2STR #define VALUE_TO_STRING(x) #x #define VALUE2STR(x) VALUE_TO_STRING(x) #endif // Ячейка таблицы struct CTc { int i; int j; std::wstring sGridSpan = L"1"; CTc(int _i, int _j, const std::wstring& sColspan) : i(_i), j(_j), sGridSpan(sColspan) {} bool operator==(const CTc& c2) { return (i == c2.i && j == c2.j && sGridSpan == c2.sGridSpan); } }; // Информация об авторе книги. Тэг author, translator struct SAuthor { std::wstring first_name; std::wstring middle_name; std::wstring last_name; std::wstring nickname; /* std::vector home_page; std::vector email; std::wstring id; */ }; // Описание информации о произведении. Тэг title-info, src-title-info struct STitleInfo { std::vector m_arGenres; // Жанры std::vector m_arAuthors; // Авторы std::wstring m_sBookTitle; // Название std::wstring m_pKeywords; // Ключевые слова /* std::vector m_arTranslator; // Переводчики std::wstring m_sLang; // Язык после перевода std::pair* m_pDate; // Дата std::wstring* m_pSrcLang; // Язык до перевода std::map m_mSequence; // Серии книг STitleInfo() { m_pKeywords = NULL; m_pDate = NULL; m_pSrcLang = NULL; } */ ~STitleInfo() { m_arGenres .clear(); m_arAuthors.clear(); /* m_arTranslator.clear(); m_mSequence.clear(); RELEASEARRAYOBJECTS(m_pDate); RELEASEARRAYOBJECTS(m_pSrcLang); */ } // Преобразование закодированного жанра /* static std::wstring definitionGenre(std::wstring sGenre) { std::wstring sRes = L""; if(sGenre == L"sf_fantasy") sRes = L"Фэнтези"; return sRes; } */ // Разделитель не важен , std::wstring getGenres() { std::wstring sRes = std::accumulate(m_arGenres.begin(), m_arGenres.end(), std::wstring(), [] (std::wstring& sRes, const std::wstring& vElem) { return sRes += (vElem.empty() ? L"" : (vElem + L", ")); }); if (!sRes.empty()) sRes.erase(sRes.end() - 2, sRes.end()); return sRes; } // Разделитель ; std::wstring getAuthors() { std::wstring sRes = std::accumulate(m_arAuthors.begin(), m_arAuthors.end(), std::wstring(), [] (std::wstring& sRes, const SAuthor& vElem) { return sRes += (vElem.middle_name.empty() ? L"" : (vElem.middle_name + L' ')) + (vElem.first_name.empty() ? L"" : (vElem.first_name + L' ')) + (vElem.last_name.empty() ? L"" : (vElem.last_name + L' ')) + vElem.nickname + L';'; }); if (!sRes.empty()) sRes.erase(sRes.end() - 1); return sRes; } }; // Описание информации о fb2-документе. Тэг document-info /* struct SDocumentInfo { std::vector m_arAuthors; // Авторы std::vector m_arSrcUrl; // URL страницы std::wstring m_pDate; // Дата std::wstring m_sId; // Идентификатор std::wstring m_sVersion; // Версия документа std::wstring* m_pProgramUsed; // Использованные программы std::wstring* m_pSrcOcr; // Автор текста std::wstring* m_pHistory; // История SDocumentInfo() { m_pProgramUsed = NULL; m_pSrcOcr = NULL; m_pHistory = NULL; } ~SDocumentInfo() { m_arAuthors.clear(); m_arSrcUrl.clear(); RELEASEARRAYOBJECTS(m_pProgramUsed); RELEASEARRAYOBJECTS(m_pSrcOcr); RELEASEARRAYOBJECTS(m_pHistory); } }; */ // Информация о бумажном издании. Тэг publish-info /* struct SPublishInfo { std::wstring* m_pBookName; // Название std::wstring* m_pPublisher; // Издательство std::wstring* m_pCity; // Место std::wstring* m_pYear; // Год std::wstring* m_pIsbn; // ISBN std::map m_mSequence; // Серии книг SPublishInfo() { m_pBookName = NULL; m_pPublisher = NULL; m_pCity = NULL; m_pYear = NULL; m_pIsbn = NULL; } ~SPublishInfo() { m_mSequence.clear(); RELEASEARRAYOBJECTS(m_pBookName); RELEASEARRAYOBJECTS(m_pPublisher); RELEASEARRAYOBJECTS(m_pCity); RELEASEARRAYOBJECTS(m_pYear); RELEASEARRAYOBJECTS(m_pIsbn); } }; */ class CFb2File_Private { public: XmlUtils::CXmlLiteReader m_oLightReader; // SAX Reader STitleInfo m_oTitleInfo; // Данные о книге // SDocumentInfo m_oDocumentInfo; // Информация об fb2-документе // std::wstring m_sTmpFolder; // Рабочая папка private: int m_nContentsId; // ID содержания int m_nCrossReferenceId; // ID перекрестной ссылки // STitleInfo* m_pSrcTitleInfo; // Данные об исходнике книги // SPublishInfo* m_pPublishInfo; // Сведения об издании книги std::map m_mFootnotes; // Сноски std::map> m_mImages; // Картинки // std::map m_mCustomInfo; // Произвольная информация public: CFb2File_Private() { // m_pSrcTitleInfo = NULL; // m_pPublishInfo = NULL; m_nContentsId = 1; m_nCrossReferenceId = 1; } ~CFb2File_Private() { m_oLightReader.Clear(); m_mFootnotes.clear(); m_mImages.clear(); /* m_mCustomInfo.clear(); if(m_pSrcTitleInfo) delete m_pSrcTitleInfo; if(m_pPublishInfo) delete m_pPublishInfo; */ } // wrapper для чтения из файла bool OpenFromFile(const std::wstring& sFile) { // считаем, что это хмл, так как проверка на формат будет раньше (x2t) std::string sFileContentUtf8 = XmlUtils::GetXmlContentAsUTF8(sFile); return m_oLightReader.FromStringA(sFileContentUtf8); } // Проверяет наличие тэга FictionBook bool isFictionBook() { return m_oLightReader.ReadNextNode() && m_oLightReader.GetName() == L"FictionBook"; } // Читает поля автора void getAuthor(std::vector& arAuthor) { if (m_oLightReader.IsEmptyNode()) return; SAuthor oAuthor; int nDepth = m_oLightReader.GetDepth(); while (m_oLightReader.ReadNextSiblingNode(nDepth)) { std::wstring sName = m_oLightReader.GetName(); if (sName == L"first-name") oAuthor.first_name = content(); else if (sName == L"middle-name") oAuthor.middle_name = content(); else if (sName == L"last-name") oAuthor.last_name = content(); else if (sName == L"nickname") oAuthor.nickname = content(); /* else if(sName == L"home-page") oAuthor.home_page.push_back(content()); else if(sName == L"email") oAuthor.email.push_back(content()); else if(sName == L"id") oAuthor.id = content(); */ } arAuthor.push_back(oAuthor); } // Читает image // НЕ имеет право писать p void readImage(NSStringUtils::CStringBuilder& oBuilder) { // Читаем href std::wstring sImageName; while (m_oLightReader.MoveToNextAttribute()) { std::wstring sName = m_oLightReader.GetName(); size_t nLen = (sName.length() > 4 ? sName.length() - 4 : 0); if (sName.substr(nLen) == L"href") { std::wstring sText = m_oLightReader.GetText(); if (sText.length() > 1) sImageName = sText.substr(1); } } m_oLightReader.MoveToElement(); readCrossReference(oBuilder); std::map>::iterator it = m_mImages.find(sImageName); if (it != m_mImages.end()) { // Пишем картинку в файл // extent oBuilder += L"second[1]; oBuilder += L"\" cy=\""; oBuilder += it->second[2]; // docPr oBuilder += L"\"/>second[0]; // graphic // pic:nvPicPr oBuilder += L"\" name=\"\"/>second[0]; // pic:blipFill // рельсы rPic + id oBuilder += L"\" name=\"\"/>second[0]; // pic:spPr oBuilder += L"\"/>second[1]; oBuilder += L"\" cy=\""; oBuilder += it->second[2]; // Конец записи oBuilder += L"\"/>"; } } // Читает title void readTitle(const std::wstring& sLevel, NSStringUtils::CStringBuilder& oBuilder) { if (m_oLightReader.IsEmptyNode()) return; bool bFirstP = true; int nDeath = m_oLightReader.GetDepth(); while (m_oLightReader.ReadNextSiblingNode(nDeath)) { // Пишем заголовок if (m_oLightReader.GetName() == L"p") { // Пишем title + sLevel oBuilder += L""; // Заголовок книги с новой страницы if (sLevel == L"title" && bFirstP) { oBuilder += L""; bFirstP = false; } oBuilder += L""; // Пишем ссылку от оглавления std::wstring sContentsId; if (sLevel == L"title1") { sContentsId = std::to_wstring(m_nContentsId++); oBuilder += L""; } readP(L"", oBuilder); // Пишем ссылку от оглавления if (sLevel == L"title1") { oBuilder += L""; } oBuilder += L""; } } } // Читает epigraph void readEpigraph(NSStringUtils::CStringBuilder& oBuilder) { readCrossReference(oBuilder); if (m_oLightReader.IsEmptyNode()) return; int nDeath = m_oLightReader.GetDepth(); while (m_oLightReader.ReadNextSiblingNode(nDeath)) { std::wstring sName = m_oLightReader.GetName(); if (sName == L"p") { oBuilder += L""; readP(L"", oBuilder); oBuilder += L""; } else if (sName == L"poem") readPoem(oBuilder); else if (sName == L"cite") readCite(oBuilder); else if (sName == L"empty-line") oBuilder += L""; // Автор эпиграфа выделяется полужирным else if (sName == L"text-author") { oBuilder += L""; readP(L"", oBuilder); oBuilder += L""; } } } // Читает p // НЕ имеет право писать p // sRStyle - накопленный стиль void readP(const std::wstring& sRStyle, NSStringUtils::CStringBuilder& oBuilder) { readCrossReference(oBuilder); if (m_oLightReader.IsEmptyNode()) return; int nDepth = m_oLightReader.GetDepth(); while (m_oLightReader.ReadNextSiblingNode2(nDepth)) { std::wstring sName = m_oLightReader.GetName(); // Читаем обычный текст if (sName == L"#text") { // Стиль текста oBuilder += L""; oBuilder += sRStyle; // Сам текст oBuilder += L""; oBuilder.WriteEncodeXmlString(m_oLightReader.GetText()); oBuilder += L""; } // Читаем полужирный текст else if (sName == L"strong") readP(sRStyle + L"", oBuilder); // Читаем курсивный текст else if (sName == L"emphasis") readP(sRStyle + L"", oBuilder); // Читаем стилизованный текст else if (sName == L"style") readP(sRStyle, oBuilder); // Читаем ссылку else if (sName == L"a") { // Читаем href std::wstring sFootnoteName; while (m_oLightReader.MoveToNextAttribute()) { std::wstring sTName = m_oLightReader.GetName(); size_t nLen = (sTName.length() > 4 ? sTName.length() - 4 : 0); if (sTName.substr(nLen) == L"href") { std::wstring sText = m_oLightReader.GetText(); if (sText.length() > 1) sFootnoteName = sText.substr(1); break; } } m_oLightReader.MoveToElement(); std::map::iterator it = m_mFootnotes.find(sFootnoteName); if (it != m_mFootnotes.end()) { // Пробел перед текстом внутри сноски oBuilder += L" "; // Читаем текст внутри сноски readP(sRStyle, oBuilder); // Стиль сноски oBuilder += L"second; oBuilder += L"\"/>"; } // Перекрестная ссылка else { oBuilder += L""; // Читаем текст внутри ссылки readP(sRStyle + L"", oBuilder); oBuilder += L""; } } // Читаем вычеркнутый текст else if (sName == L"strikethrough") readP(sRStyle + L"", oBuilder); // Читает нижний текст else if (sName == L"sub") readP(sRStyle + L"", oBuilder); // Читает верхний текст else if (sName == L"sup") readP(sRStyle + L"", oBuilder); // Читает код else if (sName == L"code") readP(sRStyle + L"", oBuilder); // Читает картинку в тексте else if (sName == L"image") readImage(oBuilder); } } // Читает poem void readPoem(NSStringUtils::CStringBuilder& oBuilder) { readCrossReference(oBuilder); if (m_oLightReader.IsEmptyNode()) return; int nDeath = m_oLightReader.GetDepth(); while (m_oLightReader.ReadNextSiblingNode(nDeath)) { std::wstring sName = m_oLightReader.GetName(); if (sName == L"title") readTitle(L"title4", oBuilder); else if (sName == L"epigraph") readEpigraph(oBuilder); else if (sName == L"stanza") { if (m_oLightReader.IsEmptyNode()) continue; int nSDeath = m_oLightReader.GetDepth(); while (m_oLightReader.ReadNextSiblingNode(nSDeath)) { std::wstring sSName = m_oLightReader.GetName(); if (sSName == L"title") readTitle(L"title5", oBuilder); else if (sSName == L"v" || sSName == L"subtitle") { oBuilder += L""; readP(L"", oBuilder); oBuilder += L""; } } } // Автор поэмы выделяется полужирным else if (sName == L"text-author") { oBuilder += L""; readP(L"", oBuilder); oBuilder += L""; } else if (sName == L"date") { oBuilder += L""; oBuilder.WriteEncodeXmlString(content()); oBuilder += L""; } } } // Читает cite void readCite(NSStringUtils::CStringBuilder& oBuilder) { readCrossReference(oBuilder); if (m_oLightReader.IsEmptyNode()) return; int nDeath = m_oLightReader.GetDepth(); while (m_oLightReader.ReadNextSiblingNode(nDeath)) { std::wstring sName = m_oLightReader.GetName(); if (sName == L"p" || sName == L"subtitle") { oBuilder += L""; readP(L"", oBuilder); oBuilder += L""; } else if (sName == L"empty-line") oBuilder += L""; else if (sName == L"poem") readPoem(oBuilder); else if (sName == L"table") readTable(oBuilder); // Автор цитаты выделяется полужирным else if (sName == L"text-author") { oBuilder += L""; readP(L"", oBuilder); oBuilder += L""; } } } // Читает table void readTable(NSStringUtils::CStringBuilder& oBuilder) { readCrossReference(oBuilder); if (m_oLightReader.IsEmptyNode()) return; // Стиль таблицы oBuilder += L""; NSStringUtils::CStringBuilder oTmpBuilder; std::vector mTable; int nGridCol = 0; int i = 1; // Строка int nDeath = m_oLightReader.GetDepth(); while (m_oLightReader.ReadNextSiblingNode(nDeath)) { // tr - строки в таблице if (m_oLightReader.GetName() != L"tr" || m_oLightReader.IsEmptyNode()) continue; int nTCol = 0; int j = 1; // Столбец oTmpBuilder += L""; int nTrDeath = m_oLightReader.GetDepth(); while (m_oLightReader.ReadNextSiblingNode(nTrDeath)) { int nColspan = 1; int nRowspan = 1; while(m_oLightReader.MoveToNextAttribute()) { if(m_oLightReader.GetName() == L"colspan") nColspan = stoi(m_oLightReader.GetText()); else if(m_oLightReader.GetName() == L"rowspan") nRowspan = stoi(m_oLightReader.GetText()); } m_oLightReader.MoveToElement(); // Вставляем ячейки до std::vector::iterator it1 = std::find_if(mTable.begin(), mTable.end(), [i, j](const CTc& item){ return item.i == i && item.j == j; }); std::vector::iterator it2 = std::find_if(mTable.begin(), mTable.end(), [j] (const CTc& item){ return item.i == 0 && item.j == j; }); while(it1 != mTable.end() || it2 != mTable.end()) { oTmpBuilder.WriteString(L"sGridSpan : it2->sGridSpan); oTmpBuilder.WriteString(sCol); oTmpBuilder.WriteString(L"\"/>"); j += stoi(sCol); it1 = std::find_if(mTable.begin(), mTable.end(), [i, j](const CTc& item){ return item.i == i && item.j == j; }); it2 = std::find_if(mTable.begin(), mTable.end(), [j] (const CTc& item){ return item.i == 0 && item.j == j; }); } oTmpBuilder += L""; if (nRowspan != 1) { oTmpBuilder.WriteString(L""); std::wstring sColspan = std::to_wstring(nColspan); if (nRowspan == 0) mTable.push_back({0, j, sColspan}); else for (int k = i + 1; k < i + nRowspan; k++) mTable.push_back({k, j, sColspan}); } if (nColspan != 1) { oTmpBuilder.WriteString(L""); j += nColspan - 1; } oTmpBuilder.WriteString(L""); // Читаем th. Ячейка заголовка таблицы. Выравнивание посередине. Выделяется полужирным if (m_oLightReader.GetName() == L"th") { if (++nTCol > nGridCol) nGridCol = nTCol; oTmpBuilder += L""; readP(L"", oTmpBuilder); } // Читаем td. Ячейка таблицы. Выравнивание вправо else if (m_oLightReader.GetName() == L"td") { if(++nTCol > nGridCol) nGridCol = nTCol; oTmpBuilder += L""; readP(L"", oTmpBuilder); } oTmpBuilder += L""; j++; // Вставляем ячейки после it1 = std::find_if(mTable.begin(), mTable.end(), [i, j](const CTc& item){ return item.i == i && item.j == j; }); it2 = std::find_if(mTable.begin(), mTable.end(), [j] (const CTc& item){ return item.i == 0 && item.j == j; }); while(it1 != mTable.end() || it2 != mTable.end()) { oTmpBuilder.WriteString(L"sGridSpan : it2->sGridSpan); oTmpBuilder.WriteString(sCol); oTmpBuilder.WriteString(L"\"/>"); j += stoi(sCol); it1 = std::find_if(mTable.begin(), mTable.end(), [i, j](const CTc& item){ return item.i == i && item.j == j; }); it2 = std::find_if(mTable.begin(), mTable.end(), [j] (const CTc& item){ return item.i == 0 && item.j == j; }); } } oTmpBuilder += L""; i++; } // Размеры таблицы std::wstring sGridCol; if (nGridCol != 0) sGridCol = std::to_wstring((int)(9570.0 / (double)nGridCol)); oBuilder += L""; for (int i = 0; i < nGridCol; i++) { oBuilder += L""; } oBuilder += L""; // Конец таблицы oBuilder += oTmpBuilder.GetData(); oBuilder += L""; // Пустая строка после таблицы, чтобы следующий текст не приклеивался oBuilder += L""; } // Читает annotation void readAnnotation(NSStringUtils::CStringBuilder& oBuilder) { readCrossReference(oBuilder); if (m_oLightReader.IsEmptyNode()) return; int nADeath = m_oLightReader.GetDepth(); while (m_oLightReader.ReadNextSiblingNode(nADeath)) { std::wstring sAnName = m_oLightReader.GetName(); if (sAnName == L"p" || sAnName == L"subtitle") { oBuilder += L""; readP(L"", oBuilder); oBuilder += L""; } else if (sAnName == L"poem") readPoem(oBuilder); else if (sAnName == L"cite") readCite(oBuilder); else if (sAnName == L"empty-line") oBuilder += L""; else if (sAnName == L"table") readTable(oBuilder); } } // Читает перекрестные ссылки void readCrossReference(NSStringUtils::CStringBuilder& oBuilder) { // id для перекрестных ссылок while (m_oLightReader.MoveToNextAttribute()) { if (m_oLightReader.GetName() == L"id") { std::wstring sCrossId = std::to_wstring(m_nCrossReferenceId++); oBuilder += L""; break; } } m_oLightReader.MoveToElement(); } // Читает section void readSection(int nLevel, NSStringUtils::CStringBuilder& oBuilder) { readCrossReference(oBuilder); if (m_oLightReader.IsEmptyNode()) return; int nDeath = m_oLightReader.GetDepth(); while (m_oLightReader.ReadNextSiblingNode(nDeath)) { std::wstring sName = m_oLightReader.GetName(); if (sName == L"title") { std::wstring sTitle = L"section-p"; if (nLevel < 10) sTitle = L"title" + std::to_wstring(nLevel); readTitle(sTitle, oBuilder); } else if (sName == L"epigraph") readEpigraph(oBuilder); else if (sName == L"image") { oBuilder += L""; readImage(oBuilder); oBuilder += L""; } else if (sName == L"annotation") readAnnotation(oBuilder); else if (sName == L"section") readSection(nLevel + 1, oBuilder); else if (sName == L"p") { oBuilder += L""; readP(L"", oBuilder); oBuilder += L""; } else if (sName == L"subtitle") { oBuilder += L""; readP(L"", oBuilder); oBuilder += L""; } else if (sName == L"poem") readPoem(oBuilder); else if (sName == L"cite") readCite(oBuilder); else if (sName == L"empty-line") oBuilder += L""; else if (sName == L"table") readTable(oBuilder); } } // Читает body void readBody(NSStringUtils::CStringBuilder& oBuilder) { if (m_oLightReader.IsEmptyNode()) return; int nDeath = m_oLightReader.GetDepth(); while (m_oLightReader.ReadNextSiblingNode(nDeath)) { std::wstring sName = m_oLightReader.GetName(); if (sName == L"image") { oBuilder += L""; readImage(oBuilder); oBuilder += L""; } else if (sName == L"title") readTitle(L"title", oBuilder); else if (sName == L"epigraph") readEpigraph(oBuilder); else if (sName == L"section") readSection(1, oBuilder); } } // Читает содержание, binary, body, сноски, description bool readText(const std::wstring& sPath, const std::wstring& sMediaDirectory, NSStringUtils::CStringBuilder& oContents, NSStringUtils::CStringBuilder& oRels, NSStringUtils::CStringBuilder& oFootnotes) { if (!m_oLightReader.IsValid()) { // Открывает файл на проверку if (!OpenFromFile(sPath)) return false; // Читаем FictionBook if (!isFictionBook()) return false; } if (m_oLightReader.IsEmptyNode()) return true; int nContentsId = 1; int nImageId = 1; int nFootnoteId = 1; oContents += L""; int nDeath = m_oLightReader.GetDepth(); while (m_oLightReader.ReadNextSiblingNode(nDeath)) { std::wstring sName = m_oLightReader.GetName(); // Читаем body if (sName == L"body") { // Сноски bool bNotes = false; while(m_oLightReader.MoveToNextAttribute()) { if (m_oLightReader.GetName() == L"name" && m_oLightReader.GetText() == L"notes") bNotes = true; } m_oLightReader.MoveToElement(); // Читаем сноски if (bNotes) readNotes(nFootnoteId, oFootnotes); // Читаем содержание else readContents(nContentsId, oContents); } // Читаем картинки else if (sName == L"binary") getImage(std::to_wstring(nImageId++), sMediaDirectory, oRels); } oContents += L""; return true; } // Читает содержание void readContents(int& nContentsId, NSStringUtils::CStringBuilder& oContents) { if (m_oLightReader.IsEmptyNode()) return; bool bFirstTitle = true; int nBDeath = m_oLightReader.GetDepth(); while (m_oLightReader.ReadNextSiblingNode(nBDeath)) { // Читаем section if (m_oLightReader.GetName() != L"section" || m_oLightReader.IsEmptyNode()) continue; int nSDeath = m_oLightReader.GetDepth(); while (m_oLightReader.ReadNextSiblingNode(nSDeath)) { // Читаем title if (m_oLightReader.GetName() != L"title" || m_oLightReader.IsEmptyNode()) continue; oContents += L""; // Абзац с новой страницы if (bFirstTitle) oContents += L""; oContents += L""; if (bFirstTitle) { oContents += L"TOC \\n \\h "; bFirstTitle = false; } oContents += L""; int nTDeath = m_oLightReader.GetDepth(); while (m_oLightReader.ReadNextSiblingNode(nTDeath)) { if (m_oLightReader.GetName() == L"p") { readP(L"", oContents); // Вставляем пробел между словами oContents += L" "; } } oContents += L""; } } if (!bFirstTitle) oContents += L""; } // Читает сноски void readNotes(int& nFootnoteId, NSStringUtils::CStringBuilder& oFootnotes) { if (m_oLightReader.IsEmptyNode()) return; int nBDepth = m_oLightReader.GetDepth(); while (m_oLightReader.ReadNextSiblingNode(nBDepth)) { if (m_oLightReader.GetName() != L"section") continue; // Читаем id std::wstring sFootnoteName; while (m_oLightReader.MoveToNextAttribute()) { if (m_oLightReader.GetName() == L"id") { sFootnoteName = m_oLightReader.GetText(); break; } } m_oLightReader.MoveToElement(); if (sFootnoteName.empty() || m_oLightReader.IsEmptyNode()) continue; std::wstring sFootnoteId = std::to_wstring(nFootnoteId++); m_mFootnotes.insert(std::make_pair(sFootnoteName, sFootnoteId)); // Пишем сноску oFootnotes += L""; // Читаем внутренность section int nSDepth = m_oLightReader.GetDepth(); while (m_oLightReader.ReadNextSiblingNode(nSDepth)) { std::wstring sName = m_oLightReader.GetName(); if (sName == L"title") { if (m_oLightReader.IsEmptyNode()) continue; int nTDepth = m_oLightReader.GetDepth(); while (m_oLightReader.ReadNextSiblingNode(nTDepth)) { if (m_oLightReader.GetName() == L"p") { oFootnotes += L""; readP(L"", oFootnotes); oFootnotes += L""; } } } else if (sName == L"p" || sName == L"subtitle") { oFootnotes += L""; readP(L"", oFootnotes); oFootnotes += L""; } else if (sName == L"poem") { if (m_oLightReader.IsEmptyNode()) continue; int nPDepth = m_oLightReader.GetDepth(); while (m_oLightReader.ReadNextSiblingNode(nPDepth)) { std::wstring sPName = m_oLightReader.GetName(); // Читаем stanza (один или более) if (sPName == L"stanza") { if (m_oLightReader.IsEmptyNode()) continue; int nSDeath = m_oLightReader.GetDepth(); while (m_oLightReader.ReadNextSiblingNode(nSDeath)) { // Читаем v (один или более) if (m_oLightReader.GetName() == L"v") { oFootnotes += L""; readP(L"", oFootnotes); oFootnotes += L""; } } } // Читаем text-author (любое) else if (sPName == L"text-author") { oFootnotes += L""; readP(L"", oFootnotes); oFootnotes += L""; } } } } oFootnotes += L""; } } // Читает binary void getImage(const std::wstring& sImageId, const std::wstring& sMediaDirectory, NSStringUtils::CStringBuilder& oRels) { std::wstring sId; while (m_oLightReader.MoveToNextAttribute()) { // Читает id if (m_oLightReader.GetName() == L"id") sId = m_oLightReader.GetText(); } m_oLightReader.MoveToElement(); if (sId.empty() || m_oLightReader.IsEmptyNode()) return; // Пишет картинку в файл NSFile::CFileBinary oImageWriter; if (oImageWriter.CreateFileW(sMediaDirectory + L'/' + sId + (sId.find(L'.') == std::wstring::npos ? L".png" : L""))) { std::string sBase64 = contentA(); int nSrcLen = (int)sBase64.length(); int nDecodeLen = NSBase64::Base64DecodeGetRequiredLength(nSrcLen); BYTE* pImageData = new BYTE[nDecodeLen]; if (TRUE == NSBase64::Base64Decode(sBase64.c_str(), nSrcLen, pImageData, &nDecodeLen)) oImageWriter.WriteFile(pImageData, (DWORD)nDecodeLen); RELEASEARRAYOBJECTS(pImageData); oImageWriter.CloseFile(); // Получаем размеры картинки CBgraFrame oBgraFrame; oBgraFrame.OpenFile(sMediaDirectory + L'/' + sId); int nHy = oBgraFrame.get_Height(); int nWx = oBgraFrame.get_Width(); if (nWx > nHy) { int nW = nWx * 9525; nW = (nW > 7000000 ? 7000000 : nW); nHy = (int)((double)nHy * (double)nW / (double)nWx); nWx = nW; } else { int nH = nHy * 9525; nH = (nH > 9000000 ? 9000000 : nH); int nW = (int)((double)nWx * (double)nH / (double)nHy); if (nW > 7000000) { nW = 7000000; nHy = (int)((double)nHy * (double)nW / (double)nWx); } else nHy = nH; nWx = nW; } std::vector vImage; vImage.push_back(sImageId); vImage.push_back(std::to_wstring(nWx)); vImage.push_back(std::to_wstring(nHy)); m_mImages.insert(std::make_pair(sId, vImage)); // Запись картинок в рельсы oRels += L""; } } // Читает description void readDescription(NSStringUtils::CStringBuilder& oBuilder) { if (m_oLightReader.IsEmptyNode()) return; int nDepth = m_oLightReader.GetDepth(); while (m_oLightReader.ReadNextSiblingNode(nDepth)) { // Читаем title-info if (m_oLightReader.GetName() == L"title-info") getTitleInfo(m_oTitleInfo, oBuilder); /* // Читаем src-title-info (ноль или один) else if(sName == L"src-title-info") { m_pSrcTitleInfo = new STitleInfo(); getTitleInfo(*m_pSrcTitleInfo); } // Читаем document-info else if(sName == L"document-info") getDocumentInfo(); // Читаем publish-info (ноль или один) else if(sName == L"publish-info") { m_pPublishInfo = new SPublishInfo(); getPublishInfo(); } // Читаем custom-info (любое) else if(sName == L"custom-info") getCustomInfo(); */ } } // Читает custom-info /* void getCustomInfo() { std::wstring sIntoType = L""; if(m_oLightReader.MoveToNextAttribute()) sIntoType = m_oLightReader.GetText(); m_oLightReader.MoveToElement(); std::wstring sCustomInfo = content(); m_mCustomInfo.insert(std::make_pair(sIntoType, sCustomInfo)); } */ // Читает publish-info /* void getPublishInfo() { if(m_oLightReader.IsEmptyNode()) return; int nDepth = m_oLightReader.GetDepth(); while(m_oLightReader.ReadNextSiblingNode(nDepth)) { std::wstring sName = m_oLightReader.GetName(); // Читаем book-name (ноль или один) if(sName == L"book-name") { if(m_pPublishInfo->m_pBookName) delete[] m_pPublishInfo->m_pBookName; m_pPublishInfo->m_pBookName = new std::wstring[1]; *m_pPublishInfo->m_pBookName = content(); } // Читаем publisher (ноль или один) else if(sName == L"publisher") { if(m_pPublishInfo->m_pPublisher) delete[] m_pPublishInfo->m_pPublisher; m_pPublishInfo->m_pPublisher = new std::wstring[1]; *m_pPublishInfo->m_pPublisher = content(); } // Читаем city (ноль или один) else if(sName == L"city") { if(m_pPublishInfo->m_pCity) delete[] m_pPublishInfo->m_pCity; m_pPublishInfo->m_pCity = new std::wstring[1]; *m_pPublishInfo->m_pCity = content(); } // Читаем year (ноль или один) else if(sName == L"year") { if(m_pPublishInfo->m_pYear) delete[] m_pPublishInfo->m_pYear; m_pPublishInfo->m_pYear = new std::wstring[1]; *m_pPublishInfo->m_pYear = content(); } // Читаем isbn (ноль или один) else if(sName == L"isbn") { if(m_pPublishInfo->m_pIsbn) delete[] m_pPublishInfo->m_pIsbn; m_pPublishInfo->m_pIsbn = new std::wstring[1]; *m_pPublishInfo->m_pIsbn = content(); } // Читаем sequence (любое) else if(sName == L"sequence") { std::wstring sSName = L""; std::wstring sSNumber = L""; while(m_oLightReader.MoveToNextAttribute()) { if(m_oLightReader.GetName() == L"name") sSName = m_oLightReader.GetText(); else if(m_oLightReader.GetName() == L"number") sSNumber = m_oLightReader.GetText(); } m_oLightReader.MoveToElement(); m_pPublishInfo->m_mSequence.insert(std::make_pair(sSName, sSNumber)); } } } */ // Читает document-info /* void getDocumentInfo() { if(m_oLightReader.IsEmptyNode()) return; int nDepth = m_oLightReader.GetDepth(); while(m_oLightReader.ReadNextSiblingNode(nDepth)) { std::wstring sName = m_oLightReader.GetName(); // Читаем author (один или более) if(sName == L"author") getAuthor(m_oDocumentInfo.m_arAuthors); // Читаем program-used (ноль или один) else if(sName == L"program-used") { if(m_oDocumentInfo.m_pProgramUsed) delete[] m_oDocumentInfo.m_pProgramUsed; m_oDocumentInfo.m_pProgramUsed = new std::wstring[1]; *m_oDocumentInfo.m_pProgramUsed = content(); } // Читаем date else if(sName == L"date") m_oDocumentInfo.m_pDate = content(); // Читаем src-url (любое) else if(sName == L"src-url") m_oDocumentInfo.m_arSrcUrl.push_back(content()); // Читаем src-ocr (ноль или один) else if(sName == L"src-ocr") { if(m_oDocumentInfo.m_pSrcOcr) delete[] m_oDocumentInfo.m_pSrcOcr; m_oDocumentInfo.m_pSrcOcr = new std::wstring[1]; *m_oDocumentInfo.m_pSrcOcr = content(); } // Читаем id else if(sName == L"id") m_oDocumentInfo.m_sId = content(); // Читаем version else if(sName == L"version") m_oDocumentInfo.m_sVersion = content(); // Читаем history (ноль или один) else if(sName == L"history") { if(m_oDocumentInfo.m_pHistory) delete[] m_oDocumentInfo.m_pHistory; m_oDocumentInfo.m_pHistory = new std::wstring[1]; *m_oDocumentInfo.m_pHistory = L""; } } } */ // Читает title-info и src-title-info void getTitleInfo(STitleInfo& oTitleInfo, NSStringUtils::CStringBuilder& oBuilder) { if (m_oLightReader.IsEmptyNode()) return; int nDepth = m_oLightReader.GetDepth(); while (m_oLightReader.ReadNextSiblingNode(nDepth)) { std::wstring sName = m_oLightReader.GetName(); if (sName == L"annotation") readAnnotation(oBuilder); else if (sName == L"coverpage") { if (m_oLightReader.IsEmptyNode()) continue; int nCDepth = m_oLightReader.GetDepth(); while (m_oLightReader.ReadNextSiblingNode(nCDepth)) { if (m_oLightReader.GetName() == L"image") { oBuilder += L""; readImage(oBuilder); oBuilder += L""; } } } else if (sName == L"genre") oTitleInfo.m_arGenres.push_back(content()); else if (sName == L"author") getAuthor(oTitleInfo.m_arAuthors); else if (sName == L"book-title") oTitleInfo.m_sBookTitle = content(); // Читаем keywords (ноль или один) else if(sName == L"keywords") oTitleInfo.m_pKeywords = content(); /* // Читаем date (ноль или один) else if(sName == L"date") { if(oTitleInfo.m_pDate) delete[] oTitleInfo.m_pDate; oTitleInfo.m_pDate = new std::pair[1]; std::wstring sDate = L""; while(m_oLightReader.MoveToNextAttribute()) { if(m_oLightReader.GetName() == L"name") sDate = m_oLightReader.GetText(); } m_oLightReader.MoveToElement(); *oTitleInfo.m_pDate = make_pair(sDate, content()); } // Читаем lang else if(sName == L"lang") oTitleInfo.m_sLang = content(); // Читаем src-lang (ноль или один) else if(sName == L"src-lang") { if(oTitleInfo.m_pSrcLang) delete[] oTitleInfo.m_pSrcLang; oTitleInfo.m_pSrcLang = new std::wstring[1]; *oTitleInfo.m_pSrcLang = content(); } // Читаем translator (любое) else if(sName == L"translator") getAuthor(oTitleInfo.m_arTranslator); // Читаем sequence (любое) else if(sName == L"sequence") { std::wstring sSName = L""; std::wstring sSNumber = L""; while(m_oLightReader.MoveToNextAttribute()) { if(m_oLightReader.GetName() == L"name") sSName = m_oLightReader.GetText(); else if(m_oLightReader.GetName() == L"number") sSNumber = m_oLightReader.GetText(); } m_oLightReader.MoveToElement(); oTitleInfo.m_mSequence.insert(std::make_pair(sSName, sSNumber)); } */ } } // Возвращает содержание узла std::wstring content() { if (!m_oLightReader.IsEmptyNode() && m_oLightReader.ReadNextSiblingNode2(m_oLightReader.GetDepth())) return m_oLightReader.GetText(); return L""; } std::string contentA() { if(!m_oLightReader.IsEmptyNode() && m_oLightReader.ReadNextSiblingNode2(m_oLightReader.GetDepth())) return m_oLightReader.GetTextA(); return ""; } }; CFb2File::CFb2File() { m_internal = new CFb2File_Private(); } CFb2File::~CFb2File() { RELEASEOBJECT(m_internal); } // Проверяет, соответствует ли fb2 файл формату bool CFb2File::IsFb2File(const std::wstring& sFile) { // Открывает файл на проверку if (!m_internal->OpenFromFile(sFile)) return false; // Читаем FictionBook return m_internal->isFictionBook(); } // Выставление рабочей папки void CFb2File::SetTmpDirectory(const std::wstring& sFolder) { // m_internal->m_sTmpFolder = sFolder; } // sPath - путь к файлу fb2, sDirectory - директория, где формируется и создается docx HRESULT CFb2File::Open(const std::wstring& sPath, const std::wstring& sDirectory, CFb2Params* oParams) { // Копирование шаблона if (!ExtractTemplate(sDirectory)) return S_FALSE; // Начало файла NSStringUtils::CStringBuilder oDocument; oDocument += L""; // Создаем сноски NSStringUtils::CStringBuilder oFootnotes; oFootnotes += L""; oFootnotes += L""; // Создаем рельсы NSStringUtils::CStringBuilder oRels; oRels += L""; oRels += L""; oRels += L""; oRels += L""; oRels += L""; oRels += L""; oRels += L""; // Директория картинок std::wstring sMediaDirectory = sDirectory + L"/word/media"; NSDirectory::CreateDirectory(sMediaDirectory); NSStringUtils::CStringBuilder oBuilder; NSStringUtils::CStringBuilder oDescription; NSStringUtils::CStringBuilder oContents; // Читаем содержание, картинки, сноски bool bNeedContents = false; if (oParams) bNeedContents = oParams->bNeedContents; if (!m_internal->readText(sPath, sMediaDirectory, oContents, oRels, oFootnotes)) return S_FALSE; // Переходим в начало if (!m_internal->m_oLightReader.MoveToStart()) return S_FALSE; int nDeath = m_internal->m_oLightReader.GetDepth(); while (m_internal->m_oLightReader.ReadNextSiblingNode(nDeath)) { std::wstring sName = m_internal->m_oLightReader.GetName(); if (sName == L"description") m_internal->readDescription(oDescription); else if (sName == L"body") { bool bNotes = false; while (m_internal->m_oLightReader.MoveToNextAttribute()) { if (m_internal->m_oLightReader.GetName() == L"name" && m_internal->m_oLightReader.GetText() == L"notes") bNotes = true; } m_internal->m_oLightReader.MoveToElement(); if (bNotes) continue; m_internal->readBody(oBuilder); } } // Конец сносок oFootnotes += L""; // Пишем сноски в файл NSFile::CFileBinary oFootnotesWriter; if (oFootnotesWriter.CreateFileW(sDirectory + L"/word/footnotes.xml")) { oFootnotesWriter.WriteStringUTF8(oFootnotes.GetData()); oFootnotesWriter.CloseFile(); } // Вставляем description oDocument += oDescription.GetData(); // Вставляем содержание if (bNeedContents) oDocument += oContents.GetData(); // Вставляем основное тело oDocument += oBuilder.GetData(); // Конец документа oDocument += L""; // Пишем документ в файл NSFile::CFileBinary oDocumentXmlWriter; if (oDocumentXmlWriter.CreateFileW(sDirectory + L"/word/document.xml")) { oDocumentXmlWriter.WriteStringUTF8(oDocument.GetData()); oDocumentXmlWriter.CloseFile(); } // Конец рельсов oRels += L""; // Пишем рельсы в файл NSFile::CFileBinary oRelsWriter; if (oRelsWriter.CreateFileW(sDirectory + L"/word/_rels/document.xml.rels")) { oRelsWriter.WriteStringUTF8(oRels.GetData()); oRelsWriter.CloseFile(); } // Директория app и core std::wstring sDocPropsDirectory = sDirectory + L"/docProps"; NSDirectory::CreateDirectory(sDocPropsDirectory); // Создаем core.xml NSStringUtils::CStringBuilder oCore; // Заголовок oCore += L""; oCore.WriteEncodeXmlString(m_internal->m_oTitleInfo.m_sBookTitle); // Жанры oCore += L""; oCore.WriteEncodeXmlString(m_internal->m_oTitleInfo.getGenres()); // Авторы oCore += L""; oCore.WriteEncodeXmlString(m_internal->m_oTitleInfo.getAuthors()); oCore.WriteString(L""); // Ключевые слова if (!m_internal->m_oTitleInfo.m_pKeywords.empty()) { oCore.WriteString(L""); oCore.WriteEncodeXmlString(m_internal->m_oTitleInfo.m_pKeywords); oCore.WriteString(L""); } // Конец core oCore += L"1"; // Пишем core в файл NSFile::CFileBinary oCoreWriter; if (oCoreWriter.CreateFileW(sDocPropsDirectory + L"/core.xml")) { oCoreWriter.WriteStringUTF8(oCore.GetData()); oCoreWriter.CloseFile(); } // Получаем версию ONLYOFFICE std::wstring sApplication = NSSystemUtils::GetEnvVariable(NSSystemUtils::gc_EnvApplicationName); if (sApplication.empty()) sApplication = NSSystemUtils::gc_EnvApplicationNameDefault; #if defined(INTVER) std::string sVersion = VALUE2STR(INTVER); #endif sApplication += L"/"; sApplication += UTF8_TO_U(sVersion); // Создаем app.xml NSStringUtils::CStringBuilder oApp; oApp += L""; oApp += sApplication; oApp += L"000false1false11falsefalse10"; // Пишем app в файл NSFile::CFileBinary oAppWriter; if (oAppWriter.CreateFileW(sDocPropsDirectory + L"/app.xml")) { oAppWriter.WriteStringUTF8(oApp.GetData()); oAppWriter.CloseFile(); } // Архивим в docx bool bNeedDocx = false; if (oParams) bNeedDocx = oParams->bNeedDocx; if (bNeedDocx) { COfficeUtils oZip; return oZip.CompressFileOrDirectory(sDirectory, sDirectory + L"/" + NSFile::GetFileName(sPath) + L".docx"); } return S_OK; } void readLi(NSStringUtils::CStringBuilder& oXml, XmlUtils::CXmlLiteReader& oIndexHtml, std::vector& arrBinary, bool bUl, bool bWasTable); void readStream(NSStringUtils::CStringBuilder& oXml, XmlUtils::CXmlLiteReader& oIndexHtml, std::vector& arrBinary, bool bWasP, bool bWasTable) { int nDeath = oIndexHtml.GetDepth(); if (oIndexHtml.IsEmptyNode() || !oIndexHtml.ReadNextSiblingNode2(nDeath)) return; do { std::wstring sName = oIndexHtml.GetName(); if (sName == L"#text") oXml.WriteEncodeXmlString(oIndexHtml.GetText()); else if (sName == L"p") { if (!bWasP) oXml.WriteString(L"

"); readStream(oXml, oIndexHtml, arrBinary, true, bWasTable); if (!bWasP) oXml.WriteString(L"

"); } else if (sName == L"h1") { if (!bWasP) oXml.WriteString(L"
<p>"); readStream(oXml, oIndexHtml, arrBinary, true, bWasTable); if (!bWasP) oXml.WriteString(L"</p>
"); } else if (sName == L"h2") { if (!bWasP) oXml.WriteString(L"
<p>"); readStream(oXml, oIndexHtml, arrBinary, true, bWasTable); if (!bWasP) oXml.WriteString(L"</p>
"); } else if (sName == L"h3") { if (!bWasP) oXml.WriteString(L"
<p>"); readStream(oXml, oIndexHtml, arrBinary, true, bWasTable); if (!bWasP) oXml.WriteString(L"</p>
"); } else if (sName == L"h4") { if (!bWasP) oXml.WriteString(L"
<p>"); readStream(oXml, oIndexHtml, arrBinary, true, bWasTable); if (!bWasP) oXml.WriteString(L"</p>
"); } else if (sName == L"h5") { if (!bWasP) oXml.WriteString(L"
<p>"); readStream(oXml, oIndexHtml, arrBinary, true, bWasTable); if (!bWasP) oXml.WriteString(L"</p>
"); } else if (sName == L"h6") { if (!bWasP) oXml.WriteString(L"
<p>"); readStream(oXml, oIndexHtml, arrBinary, true, bWasTable); if (!bWasP) oXml.WriteString(L"</p>
"); } else if (sName == L"span") { std::wstring sStyle; while (oIndexHtml.MoveToNextAttribute()) if (oIndexHtml.GetName() == L"style") sStyle = oIndexHtml.GetText(); oIndexHtml.MoveToElement(); std::wstring sAlign; size_t nAlign = sStyle.find(L"vertical-align"); if (nAlign != std::wstring::npos) { nAlign = sStyle.find(L':', nAlign); size_t nAlignEnd = sStyle.find(L';', nAlign); sAlign = sStyle.substr(nAlign + 1, (nAlignEnd < sStyle.length() ? nAlignEnd : sStyle.length()) - nAlign); if (sAlign == L"super") { oXml.WriteString(L""); readStream(oXml, oIndexHtml, arrBinary, bWasP, bWasTable); oXml.WriteString(L""); } else if (sAlign == L"sub") { oXml.WriteString(L""); readStream(oXml, oIndexHtml, arrBinary, bWasP, bWasTable); oXml.WriteString(L""); } else readStream(oXml, oIndexHtml, arrBinary, bWasP, bWasTable); } else readStream(oXml, oIndexHtml, arrBinary, bWasP, bWasTable); } else if (sName == L"s") { oXml.WriteString(L""); readStream(oXml, oIndexHtml, arrBinary, bWasP, bWasTable); oXml.WriteString(L""); } else if (sName == L"i") { oXml.WriteString(L""); readStream(oXml, oIndexHtml, arrBinary, bWasP, bWasTable); oXml.WriteString(L""); } else if (sName == L"b") { oXml.WriteString(L""); readStream(oXml, oIndexHtml, arrBinary, bWasP, bWasTable); oXml.WriteString(L""); } else if (sName == L"table") { if (!bWasTable) oXml.WriteString(L""); readStream(oXml, oIndexHtml, arrBinary, bWasP, bWasTable); if (!bWasTable) oXml.WriteString(L"
"); } else if (sName == L"tr") { if (!bWasTable) oXml.WriteString(L""); readStream(oXml, oIndexHtml, arrBinary, bWasP, bWasTable); if (!bWasTable) oXml.WriteString(L""); } else if (sName == L"td" || sName == L"th") { if (!bWasTable) { oXml.WriteString(L""); } readStream(oXml, oIndexHtml, arrBinary, true, true); if (!bWasTable) oXml.WriteString(L""); } else if (sName == L"a") { oIndexHtml.MoveToNextAttribute(); oXml.WriteString(L""); oIndexHtml.MoveToElement(); readStream(oXml, oIndexHtml, arrBinary, bWasP, bWasTable); oXml.WriteString(L""); } else if (sName == L"ul") readLi(oXml, oIndexHtml, arrBinary, true, bWasTable); else if (sName == L"ol") readLi(oXml, oIndexHtml, arrBinary, false, bWasTable); else if (sName == L"img") { std::wstring sBinary; while (oIndexHtml.MoveToNextAttribute()) { if (oIndexHtml.GetName() == L"src") { sBinary = oIndexHtml.GetText(); sBinary.erase(0, sBinary.find(L',') + 2); arrBinary.push_back(sBinary); } } oIndexHtml.MoveToElement(); oXml.WriteString(L""); } else readStream(oXml, oIndexHtml, arrBinary, bWasP, bWasTable); } while (oIndexHtml.ReadNextSiblingNode2(nDeath)); } void readLi(NSStringUtils::CStringBuilder& oXml, XmlUtils::CXmlLiteReader& oIndexHtml, std::vector& arrBinary, bool bUl, bool bWasTable) { int nNum = 1; int nDeath = oIndexHtml.GetDepth(); if (oIndexHtml.IsEmptyNode() || !oIndexHtml.ReadNextSiblingNode2(nDeath)) return; do { if (oIndexHtml.GetName() == L"li") { oXml.WriteString(L"

"); bUl ? oXml.AddCharSafe(183) : oXml.AddInt(nNum++); oXml.WriteString(L" "); readStream(oXml, oIndexHtml, arrBinary, true, bWasTable); oXml.WriteString(L"

"); } } while (oIndexHtml.ReadNextSiblingNode2(nDeath)); } std::wstring GenerateUUID() { std::mt19937 oRand(time(0)); std::wstringstream sstream; sstream << std::setfill(L'0') << std::hex << std::setw(8) << (oRand() & 0xffffffff); sstream << L'-'; sstream << std::setfill(L'0') << std::hex << std::setw(4) << (oRand() & 0xffff); sstream << L'-'; sstream << std::setfill(L'0') << std::hex << std::setw(4) << (oRand() & 0xffff); sstream << L'-'; sstream << std::setfill(L'0') << std::hex << std::setw(4) << (oRand() & 0xffff); sstream << L'-'; sstream << std::setfill(L'0') << std::hex << std::setw(8) << (oRand() & 0xffffffff); return sstream.str(); } HRESULT CFb2File::FromHtml(const std::wstring& sHtmlFile, const std::wstring& sCoreFile, const std::wstring& sDst, const std::wstring& sInpTitle) { NSStringUtils::CStringBuilder oDocument; oDocument.WriteString(L""); // description // title-info oDocument.WriteString(L""); std::wstring sBookTitle = sInpTitle.empty() ? NSFile::GetFileName(sDst) : sInpTitle; std::wstring sAuthor = sBookTitle; std::wstring sAnnotation, sKeywords, sGenre; std::wstring sLanguage = L"en-EN", sVersion = L"1.0"; std::wstring sIdentifier = GenerateUUID(); XmlUtils::CXmlLiteReader oCoreReader; oCoreReader.FromString(sCoreFile); oCoreReader.ReadNextNode(); int nDeath = oCoreReader.GetDepth(); while (oCoreReader.ReadNextSiblingNode(nDeath)) { std::wstring sName = oCoreReader.GetName(); if (sName == L"dc:creator") sAuthor = oCoreReader.GetText2(); else if (sName == L"dc:title") sBookTitle = oCoreReader.GetText2(); else if (sName == L"dc:description") sAnnotation = oCoreReader.GetText2(); else if (sName == L"dc:subject") sGenre = oCoreReader.GetText2(); else if (sName == L"cp:keywords") sKeywords = oCoreReader.GetText2(); else if (sName == L"dc:identifier") sIdentifier = oCoreReader.GetText2(); else if (sName == L"dc:language") sLanguage = oCoreReader.GetText2(); else if (sName == L"cp:version") sVersion = oCoreReader.GetText2(); } oDocument.WriteString(L""); oDocument.WriteString(sGenre); oDocument.WriteString(L""); oDocument.WriteString(sAuthor); oDocument.WriteString(L""); oDocument.WriteString(sBookTitle); oDocument.WriteString(L""); if (!sAnnotation.empty()) oDocument.WriteString(L"

" + sAnnotation + L"

"); if (!sKeywords.empty()) oDocument.WriteString(L"" + sKeywords + L""); oDocument.WriteString(L""); oDocument.WriteString(sLanguage); oDocument.WriteString(L"
"); // document-info oDocument.WriteString(sAuthor); oDocument.WriteString(L""); oDocument.WriteString(sIdentifier); oDocument.WriteString(L""); oDocument.WriteString(sVersion); oDocument.WriteString(L""); // body oDocument.WriteString(L"
"); std::string sContent; NSFile::CFileBinary::ReadAllTextUtf8A(sHtmlFile, sContent);; XmlUtils::CXmlLiteReader oIndexHtml; std::vector arrBinary; if (oIndexHtml.FromString(htmlToXhtml(sContent))) { oIndexHtml.ReadNextNode(); // html int nDepth = oIndexHtml.GetDepth(); oIndexHtml.ReadNextSiblingNode(nDepth); // head oIndexHtml.ReadNextSiblingNode(nDepth); // body readStream(oDocument, oIndexHtml, arrBinary, false, false); } oDocument.WriteString(L"
"); // binary for (size_t i = 0; i < arrBinary.size(); i++) { oDocument.WriteString(L""); oDocument.WriteString(arrBinary[i]); oDocument.WriteString(L""); } oDocument.WriteString(L"
"); // Запись в файл NSFile::CFileBinary oWriter; if (oWriter.CreateFileW(sDst)) { oWriter.WriteStringUTF8(oDocument.GetData()); oWriter.CloseFile(); } return S_OK; }