#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 "./template/template.h" #include #include #include #ifndef VALUE2STR #define VALUE_TO_STRING(x) #x #define VALUE2STR(x) VALUE_TO_STRING(x) #endif // Информация об авторе книги. Тэг 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::vector m_arTranslator; // Переводчики std::wstring m_sLang; // Язык после перевода std::wstring* m_pKeywords; // Ключевые слова 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_pKeywords); 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() { return std::accumulate(m_arGenres.begin(), m_arGenres.end(), std::wstring(), [] (std::wstring& sRes, const std::wstring& vElem) { return sRes += vElem + L", "; }); } // Разделитель ; std::wstring getAuthors() { return std::accumulate(m_arAuthors.begin(), m_arAuthors.end(), std::wstring(), [] (std::wstring& sRes, const SAuthor& vElem) { return sRes += vElem.middle_name + L" " + vElem.first_name + L" " + vElem.last_name + L";"; }); } }; // Описание информации о 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" : false; } // Читает поля автора 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 = L""; 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(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(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 = L""; 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; int nGridCol = 0; int nDeath = m_oLightReader.GetDepth(); while(m_oLightReader.ReadNextSiblingNode(nDeath)) { // tr - строки в таблице if(m_oLightReader.GetName() == L"tr") { if(m_oLightReader.IsEmptyNode()) continue; int nTCol = 0; oTmpBuilder += L""; int nTrDeath = m_oLightReader.GetDepth(); while(m_oLightReader.ReadNextSiblingNode(nTrDeath)) { oTmpBuilder += 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""; } oTmpBuilder += L""; } } // Размеры таблицы std::wstring sGridCol = L""; 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(unsigned 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") { std::wstring sImageId = std::to_wstring(nImageId++); getImage(sImageId, 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)) { std::wstring sName = m_oLightReader.GetName(); // Читаем section if(sName == L"section") { if(m_oLightReader.IsEmptyNode()) continue; int nSDeath = m_oLightReader.GetDepth(); while(m_oLightReader.ReadNextSiblingNode(nSDeath)) { // Читаем title if(m_oLightReader.GetName() == L"title") { if(m_oLightReader.IsEmptyNode()) continue; std::wstring sContentsId = std::to_wstring(nContentsId++); 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") { // Читаем id std::wstring sFootnoteName = L""; while(m_oLightReader.MoveToNextAttribute()) { if(m_oLightReader.GetName() == L"id") { sFootnoteName = m_oLightReader.GetText(); break; } } m_oLightReader.MoveToElement(); if(sFootnoteName == L"") continue; if(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 = L""; while(m_oLightReader.MoveToNextAttribute()) { // Читает id if(m_oLightReader.GetName() == L"id") sId = m_oLightReader.GetText(); } m_oLightReader.MoveToElement(); if(sId == L"") return; if(m_oLightReader.IsEmptyNode()) return; // Пишет картинку в файл NSFile::CFileBinary oImageWriter; if(oImageWriter.CreateFileW(sMediaDirectory + L"/" + sId)) { 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)) { std::wstring sName = m_oLightReader.GetName(); // Читаем title-info if(sName == 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") { if(oTitleInfo.m_pKeywords) delete[] oTitleInfo.m_pKeywords; oTitleInfo.m_pKeywords = new std::wstring[1]; *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() { std::wstring sRes = L""; if(m_oLightReader.IsEmptyNode()) return sRes; if(m_oLightReader.ReadNextSiblingNode2(m_oLightReader.GetDepth())) sRes = m_oLightReader.GetText(); return sRes; } std::string contentA() { std::string sRes = ""; if(m_oLightReader.IsEmptyNode()) return sRes; if(m_oLightReader.ReadNextSiblingNode2(m_oLightReader.GetDepth())) sRes = m_oLightReader.GetTextA(); return sRes; } }; 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 if(!m_internal->isFictionBook()) return false; return true; } // Выставление рабочей папки void CFb2File::SetTmpDirectory(const std::wstring& sFolder) { // m_internal->m_sTmpFolder = sFolder; } // Проверяет, соответствует ли fb2 файл формату // 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()); // Конец 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; HRESULT oRes = oZip.CompressFileOrDirectory(sDirectory, sDirectory + L"/" + NSFile::GetFileName(sPath) + L".docx"); return oRes; } return S_OK; }