#pragma once #include "Writer.h" #define CODEPAGE_ISSUE_FIX #include "../AVSOfficeUtils/ZLIB/zlib-1.2.3/contrib/minizip/zip.h" #define BUFSIZE 2048 #define MAXHTMLSIZE 1024*1024*50//130000 // 130000 bytes namespace NSEBook { class CWriter_Epub { private: NSCommon::CStringWriter m_oWriter; NSCommon::CStringWriter m_oWriterTOC; NSCommon::CStringWriter m_oWriterTOCReferenses; LONG m_lCurrentHtml; CFormat* m_pFormat; LONG m_lSectionWrite; CString m_strFontsItems; bool m_bIsFontsEmbedded; bool m_bIsSaveCover; public: void CreateDocument(CWriter* pWriter) { m_bIsFontsEmbedded = pWriter->m_bIsEmbeddedFonts; m_bIsSaveCover = pWriter->m_bIsSaveCover; m_lSectionWrite = 1; m_lCurrentHtml = 1; // METAINF CString strMETA_INF = pWriter->m_oFormat.m_oTempManager.m_strTempDirectory + _T("\\META-INF"); CDirectory::CreateDirectory(strMETA_INF); CString str1 = _T("\ "); CFile oFile1; oFile1.CreateFile(strMETA_INF + _T("\\container.xml")); oFile1.WriteStringUTF8(str1); oFile1.CloseFile(); // mimetype CStringA str2 = "application/epub+zip"; CFile oFile2; oFile2.CreateFile(pWriter->m_oFormat.m_oTempManager.m_strTempDirectory + _T("\\mimetype")); oFile2.WriteFile((void*)str2.GetBuffer(), str2.GetLength()); oFile2.CloseFile(); // css CString strCSS = _T(".heading1 { text-align: center; font-weight: bold; font-size: 2em; }\n\ .heading2 { text-align: center; font-weight: bold; font-size: 1.5em; }n\ .heading0 { text-indent: 2em; text-align: justify; font-size: 1em; }\n\ .image_inline { vertical-align: baseline; }\n\ .image_block { vertical-align: baseline; }\n\ .bookpagebreak { display: block; page-break-after:always; margin-bottom: 0; margin-left: 0; margin-right: 0; margin-top: 0 }\n\ p {text-indent: 1.5em; }\n\ .main { display: block; font-size: 1em; margin-bottom: 0; margin-left: 5pt; margin-right: 5pt; margin-top: 0; padding-left: 0; padding-right: 0; text-align: justify }\n\ .hyper { text-decoration: underline; }\n"); if (m_bIsFontsEmbedded && (NULL != pWriter->m_pCurrentPage)) { ::CreateDirectory(pWriter->m_oFormat.m_oTempManager.m_strTempDirectory + _T("\\fonts"), NULL); CString strCssMem = _T(""); m_strFontsItems = _T(""); pWriter->m_pCurrentPage->m_oFontsGen.WriteFonts(pWriter->m_oFormat.m_oTempManager.m_strTempDirectory, strCssMem, m_strFontsItems); strCSS += strCssMem; } CFile oFile3; oFile3.CreateFile(pWriter->m_oFormat.m_oTempManager.m_strTempDirectory + _T("\\stylesheet.css")); oFile3.WriteStringUTF8(strCSS); oFile3.CloseFile(); m_pFormat = &pWriter->m_oFormat; POSITION posSect = m_pFormat->m_listSections.GetHeadPosition(); while (NULL != posSect) { if (1 != m_lCurrentHtml) DumpCurrentHtml(m_pFormat); CSection& oSection = m_pFormat->m_listSections.GetNext(posSect); DumpSection(&oSection); POSITION pos = oSection.m_arItems.GetHeadPosition(); while (NULL != pos) { IEbookItem* pItem = oSection.m_arItems.GetNext(pos); switch (pItem->m_eType) { case IEbookItem::ebitParagraph: { WriteParagraph((CEbookParagraph*)pItem); break; } case IEbookItem::ebitTable: { WriteTable((CEbookTable*)pItem); break; } case IEbookItem::ebitGraphic: { WriteImage((CEbookGraphicObject*)pItem); break; } case IEbookItem::ebitNumbering: { WriteNumbering((CEbookNumbering*)pItem); break; } default: break; } } } DumpCurrentHtml(m_pFormat, true); } void CloseFile(CString strDstFile, CWriter* pWriter) { WriteOPF(m_pFormat); CompressEpubDir(pWriter->m_oFormat.m_oTempManager.m_strTempDirectory, strDstFile); } void DumpSection(CSection* pSection) { //DumpCurrentHtml(m_pFormat, true); if (m_oWriter.GetCurSize() > MAXHTMLSIZE) DumpCurrentHtml(m_pFormat, true); CString strText = _T(""); POSITION pos = pSection->m_arItems.GetHeadPosition(); while (NULL != pos) { IEbookItem* pItem = pSection->m_arItems.GetNext(pos); if (IEbookItem::ebitParagraph == pItem->m_eType) { CEbookParagraph* pParagraph = (CEbookParagraph*)pItem; strText = pParagraph->GetAllText(); break; } } CorrectString(strText); GUID guid; CoCreateGuid(&guid); CString strGuid = _T(""); strGuid.Format(_T("%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x"), guid.Data1, guid.Data2, guid.Data3, guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]); CString s1 = _T(""); s1.Format(_T("%d"), m_lSectionWrite++); CString s2 = _T(""); s2.Format(_T("%d"), m_lCurrentHtml); CString strSect = _T("") + strText + _T(""); m_oWriterTOC.WriteStringC(strSect); CString strSectRef = _T("

") + strText + _T("

"); m_oWriterTOCReferenses.WriteStringC(strSectRef); } void DumpCurrentHtml(NSEBook::CFormat* pFormat, bool bIsEnd = false) { if (bIsEnd) { if (0 == m_oWriter.GetCurSize()) return; } CString str1 = _T("") + pFormat->m_oMeta.m_strName + _T("\ "); CString str2 = _T(""); CString strNum = _T(""); strNum.Format(_T("%d"), m_lCurrentHtml); ++m_lCurrentHtml; CString strSave = pFormat->m_oTempManager.m_strTempDirectory + _T("\\content_") + strNum + _T(".xhtml"); CFile oFile; oFile.CreateFile(strSave); BYTE utf8_mem[3]; utf8_mem[0] = 0xEF; utf8_mem[1] = 0xBB; utf8_mem[2] = 0xBF; oFile.WriteFile((void*)utf8_mem, 3); oFile.WriteStringUTF8(str1); CString strBody = m_oWriter.GetCString(); oFile.WriteStringUTF8(strBody); oFile.WriteStringUTF8(str2); oFile.CloseFile(); m_oWriter.ClearNoAttack(); } protected: static CStringA UnicodeToCodepage( CStringW sUni, UINT nCodepage = CP_UTF8 ) { CStringA sUtf; int nBufSize = WideCharToMultiByte(nCodepage, 0, sUni, -1, NULL, NULL, NULL, NULL); LPSTR pBuff = new CHAR[ nBufSize + 1 ]; WideCharToMultiByte(nCodepage, 0, sUni, -1, pBuff, nBufSize, NULL, NULL); pBuff[ nBufSize ] = 0; sUtf.Append( pBuff ); delete pBuff; return sUtf; } int _WriteFileToZip( CString sSource, CString sSourceRel, zipFile zf, int nCompressionLevel ) { int err = 0; if( Z_NO_COMPRESSION == nCompressionLevel ) err = zipOpenNewFileInZip( zf, UnicodeToCodepage (sSourceRel, CP_OEMCP), NULL, NULL, 0, NULL, 0, NULL, NULL, nCompressionLevel ); else err = zipOpenNewFileInZip( zf, UnicodeToCodepage (sSourceRel, CP_OEMCP), NULL, NULL, 0, NULL, 0, NULL, Z_DEFLATED, nCompressionLevel ); HANDLE hSourceFile = ::CreateFile( sSource, GENERIC_READ, 0, 0, OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL, 0); if( INVALID_HANDLE_VALUE == hSourceFile ) err = -1; DWORD dwBytesRead = 1; BYTE bBuffer[ BUFSIZE ]; while( -1 != err && 0 != dwBytesRead ) { ReadFile( hSourceFile, bBuffer, BUFSIZE, &dwBytesRead, NULL ); if( dwBytesRead > 0 ) err = zipWriteInFileInZip( zf, bBuffer, dwBytesRead ); } RELEASEHANDLE( hSourceFile ); if( 0 == err ) err = zipCloseFileInZip( zf ); else zipCloseFileInZip( zf ); return err; } int _CompressEpubDir( CString sSource, CString sPathRel, zipFile zf, int nCompresstionLevel ) { DWORD dwFileAttrib = ::GetFileAttributes( sSource ); if( dwFileAttrib != INVALID_FILE_ATTRIBUTES ) { DWORD dwResult = 0; if( 0 != (FILE_ATTRIBUTE_DIRECTORY & dwFileAttrib) ) { HANDLE Handle; WIN32_FIND_DATA FindData; DWORDLONG Result = 0; Handle = FindFirstFile( ( sSource + _T("\\*.*") ), &FindData ); if ( Handle == INVALID_HANDLE_VALUE ) return 0; do { int nRes = 0; if( ( CString( FindData.cFileName ) != _T("mimetype") ) && ( CString( FindData.cFileName ) != _T(".") ) && ( CString( FindData.cFileName ) != _T("..") ) ) { if( FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) { if( _T("fonts") == CString( FindData.cFileName ) ) dwResult += _CompressEpubDir( sSource + _T("\\") + FindData.cFileName, sPathRel + FindData.cFileName + _T("/"), zf, Z_NO_COMPRESSION );//фонты и так уже запакованы else dwResult += _CompressEpubDir( sSource + _T("\\") + FindData.cFileName, sPathRel + FindData.cFileName + _T("/"), zf, nCompresstionLevel ); } else dwResult += _CompressEpubDir( sSource + _T("\\") + FindData.cFileName, sPathRel, zf, nCompresstionLevel ); } } while( FindNextFile( Handle, &FindData ) != 0 ); FindClose( Handle ); } else { TCHAR tExt[256]; TCHAR tFilename[256]; _wsplitpath( sSource, NULL, NULL, tFilename, tExt ); CString sExt = tExt; CString sFilename = tFilename; _WriteFileToZip( sSource, sPathRel + sFilename + sExt, zf, nCompresstionLevel ); } return dwResult; }// 0 - все закончилось хорошо return 0; } int CompressEpubDir( CString sSource, CString sDestination ) { int err = 0; zipFile zf = zipOpen( sDestination, APPEND_STATUS_CREATE ); if( NULL == zf ) return 1; //первый в архиве всегда должен быть mimetype CString sMimeFile = sSource + _T("\\mimetype"); if( ::GetFileAttributes( sMimeFile ) != INVALID_FILE_ATTRIBUTES ) err = _WriteFileToZip( sMimeFile, _T("mimetype"), zf, Z_NO_COMPRESSION ); if( err == 0 ) { //записываем все остальное err = _CompressEpubDir( sSource, _T(""), zf, Z_BEST_COMPRESSION ); } if( 0 == err ) err = zipClose( zf, NULL ); else zipClose( zf, NULL ); return err; } void WriteOPF(NSEBook::CFormat* pFormat) { NSCommon::CStringWriter oOpf; oOpf.WriteStringC(_T("")); oOpf.WriteStringC(_T("")); oOpf.WriteStringC(CorrectString2(pFormat->m_oMeta.m_strPublisher)); oOpf.WriteStringC(_T("")); oOpf.WriteStringC(_T("")); //oOpf.WriteStringC(CorrectString2(pFormat->m_oMeta.m_strLanguage)); oOpf.WriteStringC(_T("")); oOpf.WriteStringC(_T("")); oOpf.WriteStringC(CorrectString2(pFormat->m_oMeta.m_strAuthor)); oOpf.WriteStringC(_T("")); oOpf.WriteStringC(_T("")); oOpf.WriteStringC(CorrectString2(pFormat->m_oMeta.m_strName)); oOpf.WriteStringC(_T("")); oOpf.WriteStringC(_T("")); oOpf.WriteStringC(CorrectString2(pFormat->m_oMeta.m_strCreatorProgram)); oOpf.WriteStringC(_T("")); if (0 != pFormat->m_oMeta.m_listAnnotation.GetCount()) { oOpf.WriteStringC(_T("")); POSITION pos = pFormat->m_oMeta.m_listAnnotation.GetHeadPosition(); while (NULL != pos) { IEbookItem* pItem = pFormat->m_oMeta.m_listAnnotation.GetNext(pos); switch (pItem->m_eType) { case IEbookItem::ebitParagraph: { CEbookParagraph* pPar = (CEbookParagraph*)pItem; oOpf.WriteStringC(CorrectString2(pPar->GetAllText())); break; } default: break; } } oOpf.WriteStringC(_T("")); } GUID guid; CoCreateGuid(&guid); CString strGuid = _T(""); strGuid.Format(_T("%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x"), guid.Data1, guid.Data2, guid.Data3, guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]); oOpf.WriteStringC(_T("")); oOpf.WriteStringC(strGuid); oOpf.WriteStringC(_T("")); if (m_bIsSaveCover) { LONG _lStartImage = max(m_lCurrentHtml, 1000); CString strCover = _T(""); strCover.Format(_T("id%d"), _lStartImage); m_oWriter.WriteString(_T("")); } oOpf.WriteStringC(_T("\ \ ")); if (m_bIsSaveCover) { oOpf.WriteStringC(_T("")); // теперь сохраним xhtml CFile oFileCover; oFileCover.CreateFile(pFormat->m_oTempManager.m_strTempDirectory + _T("\\cover.xhtml")); BYTE utf8_mem[3]; utf8_mem[0] = 0xEF; utf8_mem[1] = 0xBB; utf8_mem[2] = 0xBF; bool bIsPNG = false; if (0 != pFormat->m_oImageManager.m_listImages.GetCount()) { if (NSCommon::itPNG == pFormat->m_oImageManager.m_listImages.GetHead().m_eType) bIsPNG = true; } oFileCover.WriteFile((void*)utf8_mem, 3); if (!bIsPNG) { CString strCoverXHTML = _T("\ Cover
\ \"Cover\"
"); oFileCover.WriteStringUTF8(strCoverXHTML); } else { CString strCoverXHTML = _T("\ Cover
\ \"Cover\"
"); oFileCover.WriteStringUTF8(strCoverXHTML); } oFileCover.CloseFile(); } for (LONG lStartText = 1; lStartText < m_lCurrentHtml; ++lStartText) { CString strText = _T(""); strText.Format(_T(""), lStartText, lStartText); oOpf.WriteStringC(strText); } LONG lStartImage = max(m_lCurrentHtml, 1000); POSITION posImage = pFormat->m_oImageManager.m_listImages.GetHeadPosition(); while (NULL != posImage) { CImageInfo& info = pFormat->m_oImageManager.m_listImages.GetNext(posImage); if (itJPG == info.m_eType) { CString strText = _T(""); strText.Format(_T(""), info.m_lID, lStartImage); oOpf.WriteStringC(strText); } else { CString strText = _T(""); strText.Format(_T(""), info.m_lID, lStartImage); oOpf.WriteStringC(strText); } ++lStartImage; } oOpf.WriteStringC(m_strFontsItems); oOpf.WriteStringC(_T("
")); if (m_bIsSaveCover) { oOpf.WriteStringC(_T("")); } for (LONG i = 1; i < m_lCurrentHtml; ++i) { CString strText = _T(""); strText.Format(_T(""), i); oOpf.WriteStringC(strText); } if (FALSE) { oOpf.WriteStringC(_T("")); } oOpf.WriteStringC(_T("
")); CFile oFile; oFile.CreateFile(pFormat->m_oTempManager.m_strTempDirectory + _T("\\content.opf")); CString strCont = oOpf.GetCString(); oFile.WriteStringUTF8(strCont); oFile.CloseFile(); // toc.ncx CFile oFileTOC; oFileTOC.CreateFile(pFormat->m_oTempManager.m_strTempDirectory + _T("\\toc.ncx")); CString str1 = _T("\ \ \ \ ") + pFormat->m_oMeta.m_strName + _T("") + pFormat->m_oMeta.m_strAuthor + _T(""); oFileTOC.WriteStringUTF8(str1); m_oWriterTOC.WriteStringC(_T("")); CString str2 = m_oWriterTOC.GetCString(); oFileTOC.WriteStringUTF8(str2); oFileTOC.CloseFile(); CFile oFileBook_toc; oFileBook_toc.CreateFile(pFormat->m_oTempManager.m_strTempDirectory + _T("\\book_toc.xhtml")); CString str11 = _T("\ Table of Content\ \

Table of Contents

"); oFileBook_toc.WriteStringUTF8(str11); m_oWriterTOCReferenses.WriteStringC(_T("
")); CString str22 = m_oWriterTOCReferenses.GetCString(); oFileBook_toc.WriteStringUTF8(str22); oFileBook_toc.CloseFile(); } AVSINLINE void CheckSplitHtml() { if (m_oWriter.GetCurSize() > MAXHTMLSIZE) DumpCurrentHtml(m_pFormat); } AVSINLINE void WriteImage(NSEBook::CEbookGraphicObject* pImage) { CString strImage = _T(""); strImage.Format(_T("
\"\"/
"), pImage->m_oInfo.m_lID, (NSCommon::itJPG == pImage->m_oInfo.m_eType) ? _T("jpg") : _T("png")); m_oWriter.WriteStringC(strImage); if (pImage->m_bIsPageBreakAfter) { m_oWriter.WriteStringC(_T("
")); } CheckSplitHtml(); } AVSINLINE void WriteParagraph(NSEBook::CEbookParagraph* pParagraph) { if (1 == pParagraph->m_lStyle) m_oWriter.WriteStringC(_T("

")); else if (2 == pParagraph->m_lStyle) m_oWriter.WriteStringC(_T("

")); else { if (0 == pParagraph->m_lTextAlign) { m_oWriter.WriteStringC(_T("

")); } else if (1 == pParagraph->m_lTextAlign) { m_oWriter.WriteStringC(_T("

")); } else if (2 == pParagraph->m_lTextAlign) { m_oWriter.WriteStringC(_T("

")); } else { m_oWriter.WriteStringC(_T("

")); } } NSEBook::CEbookParagraph::CSpan* pSpan = NULL; POSITION posLine = pParagraph->m_arLines.GetHeadPosition(); while (NULL != posLine) { NSEBook::CEbookParagraph::CLine& oLine = pParagraph->m_arLines.GetNext(posLine); POSITION posSpan = oLine.m_listSpans.GetHeadPosition(); while (NULL != posSpan) { NSEBook::CEbookParagraph::CSpan& oSpan = oLine.m_listSpans.GetNext(posSpan); if ((NULL == posSpan) && (NULL != posLine)) oSpan.m_oText.CheckLastSpanLine(); if (NULL == pSpan) pSpan = &oSpan; else if (pSpan->m_oFont.IsEqual(&oSpan.m_oFont) && pSpan->m_oBrush.IsEqual(&oSpan.m_oBrush) && (oSpan.m_oImageInfo.m_lID == -1) && (pSpan->m_oImageInfo.m_lID == -1)) { pSpan->m_oText += oSpan.m_oText; } else { WriteSpan(pSpan); pSpan = &oSpan; } } } if (NULL != pSpan) { WriteSpan(pSpan); } m_oWriter.WriteStringC(_T("

")); if (pParagraph->m_bIsPageBreakAfter) { m_oWriter.WriteStringC(_T("
")); //m_oWriter.WriteStringC(_T("

")); } CheckSplitHtml(); } AVSINLINE void WriteSpan(NSEBook::CEbookParagraph::CSpan* pSpan) { if (-1 != pSpan->m_oImageInfo.m_lID) { CString strImage = _T(""); strImage.Format(_T("\"\"/"), pSpan->m_oImageInfo.m_lID, (NSCommon::itJPG == pSpan->m_oImageInfo.m_eType) ? _T("jpg") : _T("png")); m_oWriter.WriteStringC(strImage); return; } CString strStyle1 = _T(""); CString strStyle2 = _T(""); if (m_bIsFontsEmbedded) { CString strName = pSpan->m_oFont.Name; strName.Replace(_T(" "), _T("_avs_space_")); strStyle1 = (_T("m_oFont.Bold) strStyle1 += _T("font-weight:bold;"); else strStyle1 += _T("font-weight:normal;"); if (pSpan->m_oFont.Italic) strStyle1 += _T("font-style:italic;\">"); else strStyle1 += _T("font-style:normal;\">"); strStyle2 = _T(""); } else { if (pSpan->m_oFont.Bold) { strStyle1 += _T(""); strStyle2 += _T(""); } if (pSpan->m_oFont.Italic) { strStyle1 += _T(""); strStyle2 = (_T("") + strStyle2); } if (pSpan->m_oFont.Underline != 0) { strStyle1 += _T(""); strStyle2 = (_T("") + strStyle2); } } if (pSpan->m_dBaselineOffset < 0) { strStyle1 += _T(""); strStyle2 = (_T("") + strStyle2); } if (pSpan->m_dBaselineOffset > 0) { strStyle1 += _T(""); strStyle2 = (_T("") + strStyle2); } m_oWriter.WriteStringC(strStyle1); m_oWriter.WriteTextXML(pSpan->m_oText); m_oWriter.WriteStringC(strStyle2); } AVSINLINE void WriteTable(NSEBook::CEbookTable* pTable) { m_oWriter.WriteString(pTable->m_strTableXml); if (pTable->m_bIsPageBreakAfter) { m_oWriter.WriteStringC(_T("

")); } CheckSplitHtml(); } AVSINLINE void WriteNumbering(NSEBook::CEbookNumbering* pNumbering) { CheckSplitHtml(); } }; }