mirror of
https://github.com/ONLYOFFICE/core.git
synced 2026-03-31 10:21:37 +08:00
Compare commits
10 Commits
feature/pd
...
feature/do
| Author | SHA1 | Date | |
|---|---|---|---|
| d18d3d1bdf | |||
| 920542cd78 | |||
| bd4d5ec1e9 | |||
| b49997e615 | |||
| d4b4fc04d9 | |||
| 78219fcba1 | |||
| fa3ae4e2e2 | |||
| e69b1cf2d6 | |||
| 8870516a8a | |||
| 8fa5f8944e |
@ -505,7 +505,13 @@ public:
|
||||
}
|
||||
|
||||
if (m_nType == 0)
|
||||
{
|
||||
std::vector<CPdfLink*> arrLinks = ((CPdfFile*)m_pFile)->GetPdfLinks(nPageIndex);
|
||||
// TODO Usage
|
||||
for (int i = 0; i < arrLinks.size(); ++i)
|
||||
RELEASEOBJECT(arrLinks[i]);
|
||||
((CPdfFile*)m_pFile)->SetPageFonts(nPageIndex);
|
||||
}
|
||||
|
||||
BYTE* res = oRes.GetBuffer();
|
||||
oRes.ClearWithoutAttack();
|
||||
@ -617,19 +623,6 @@ public:
|
||||
return ((CPdfFile*)m_pFile)->GetEmbeddedFontPath(sName);
|
||||
}
|
||||
|
||||
bool isXFA()
|
||||
{
|
||||
if (0 != m_nType)
|
||||
return false;
|
||||
return ((CPdfFile*)m_pFile)->IsXFA();
|
||||
}
|
||||
BYTE* getXFA()
|
||||
{
|
||||
if (0 != m_nType)
|
||||
return NULL;
|
||||
return ((CPdfFile*)m_pFile)->GetXFA();
|
||||
}
|
||||
|
||||
private:
|
||||
int GetPagesCount()
|
||||
{
|
||||
|
||||
@ -263,15 +263,6 @@ JSSmart<CJSValue> CDrawingFileEmbed::CheckPerm(JSSmart<CJSValue> nPerm)
|
||||
return CJSContext::createBool(m_pFile->CheckPerm(nPerm->toInt32()));
|
||||
}
|
||||
|
||||
JSSmart<CJSValue> CDrawingFileEmbed::IsXFA()
|
||||
{
|
||||
return CJSContext::createBool(m_pFile->isXFA());
|
||||
}
|
||||
JSSmart<CJSValue> CDrawingFileEmbed::GetXFA()
|
||||
{
|
||||
return WasmMemoryToJS(m_pFile->getXFA());
|
||||
}
|
||||
|
||||
bool EmbedDrawingFile(JSSmart<NSJSBase::CJSContext>& context, IOfficeDrawingFile* pFile)
|
||||
{
|
||||
CJSContext::Embed<CDrawingFileEmbed>(false);
|
||||
|
||||
@ -62,9 +62,6 @@ public:
|
||||
JSSmart<CJSValue> CheckOwnerPassword(JSSmart<CJSValue> sPassword);
|
||||
JSSmart<CJSValue> CheckPerm(JSSmart<CJSValue> nPerm);
|
||||
|
||||
JSSmart<CJSValue> IsXFA();
|
||||
JSSmart<CJSValue> GetXFA();
|
||||
|
||||
DECLARE_EMBED_METHODS
|
||||
};
|
||||
|
||||
|
||||
@ -36,8 +36,6 @@
|
||||
-(JSValue*) UndoRedact;
|
||||
-(JSValue*) CheckOwnerPassword : (JSValue*)sPassword;
|
||||
-(JSValue*) CheckPerm : (JSValue*)nPerm;
|
||||
-(JSValue*) IsXFA;
|
||||
-(JSValue*) GetXFA;
|
||||
@end
|
||||
|
||||
@interface CJSCDrawingFileEmbed : NSObject<IJSCDrawingFileEmbed, JSEmbedObjectProtocol>
|
||||
@ -81,8 +79,6 @@ FUNCTION_WRAPPER_JS_3(RedactPage, RedactPage)
|
||||
FUNCTION_WRAPPER_JS_0(UndoRedact, UndoRedact)
|
||||
FUNCTION_WRAPPER_JS_1(CheckOwnerPassword, CheckOwnerPassword)
|
||||
FUNCTION_WRAPPER_JS_1(CheckPerm, CheckPerm)
|
||||
FUNCTION_WRAPPER_JS_0(IsXFA, IsXFA)
|
||||
FUNCTION_WRAPPER_JS_0(GetXFA, GetXFA)
|
||||
@end
|
||||
|
||||
class CDrawingFileEmbedAdapter : public CJSEmbedObjectAdapterJSC
|
||||
|
||||
@ -39,8 +39,6 @@ namespace NSDrawingFileEmbed
|
||||
FUNCTION_WRAPPER_V8_0(_UndoRedact, UndoRedact)
|
||||
FUNCTION_WRAPPER_V8_1(_CheckOwnerPassword, CheckOwnerPassword)
|
||||
FUNCTION_WRAPPER_V8_1(_CheckPerm, CheckPerm)
|
||||
FUNCTION_WRAPPER_V8_0(_IsXFA, IsXFA)
|
||||
FUNCTION_WRAPPER_V8_0(_GetXFA, GetXFA)
|
||||
|
||||
v8::Handle<v8::ObjectTemplate> CreateTemplate(v8::Isolate* isolate)
|
||||
{
|
||||
@ -79,8 +77,6 @@ namespace NSDrawingFileEmbed
|
||||
NSV8Objects::Template_Set(result, "UndoRedact", _UndoRedact);
|
||||
NSV8Objects::Template_Set(result, "CheckOwnerPassword", _CheckOwnerPassword);
|
||||
NSV8Objects::Template_Set(result, "CheckPerm", _CheckPerm);
|
||||
NSV8Objects::Template_Set(result, "IsXFA", _IsXFA);
|
||||
NSV8Objects::Template_Set(result, "GetXFA", _GetXFA);
|
||||
|
||||
return handle_scope.Escape(result);
|
||||
}
|
||||
|
||||
@ -60,8 +60,6 @@
|
||||
"_UndoRedact",
|
||||
"_CheckOwnerPassword",
|
||||
"_CheckPerm",
|
||||
"_IsXFA",
|
||||
"_GetXFA",
|
||||
"_GetImageBase64",
|
||||
"_GetImageBase64Len",
|
||||
"_GetImageBase64Ptr",
|
||||
|
||||
@ -177,30 +177,6 @@ CFile.prototype["UndoRedact"] = function()
|
||||
return this._UndoRedact();
|
||||
};
|
||||
|
||||
// XFA
|
||||
CFile.prototype["isXFA"] = function()
|
||||
{
|
||||
if (!this.nativeFile)
|
||||
return false;
|
||||
return this._isXFA();
|
||||
};
|
||||
CFile.prototype["getXFA"] = function()
|
||||
{
|
||||
if (!this.nativeFile)
|
||||
return {};
|
||||
|
||||
let ptr = this._getXFA();
|
||||
let reader = ptr.getReader();
|
||||
if (!reader) return {};
|
||||
|
||||
let res = {};
|
||||
res["dynamic"] = reader.readByte() ? true : false;
|
||||
res["xfa"] = reader.readString();
|
||||
|
||||
ptr.free();
|
||||
return res;
|
||||
};
|
||||
|
||||
// INFO DOCUMENT
|
||||
CFile.prototype.getInfo = function()
|
||||
{
|
||||
|
||||
@ -184,17 +184,6 @@ CFile.prototype._getInteractiveFormsFonts = function(type)
|
||||
return g_module_pointer;
|
||||
};
|
||||
|
||||
// XFA
|
||||
CFile.prototype._isXFA = function()
|
||||
{
|
||||
return g_native_drawing_file["IsXFA"]();
|
||||
};
|
||||
CFile.prototype._getXFA = function()
|
||||
{
|
||||
g_module_pointer.ptr = g_native_drawing_file["GetXFA"]();
|
||||
return g_module_pointer;
|
||||
};
|
||||
|
||||
// INFO DOCUMENT
|
||||
CFile.prototype._getInfo = function()
|
||||
{
|
||||
|
||||
@ -305,17 +305,6 @@ CFile.prototype._getInteractiveFormsFonts = function(type)
|
||||
return g_module_pointer;
|
||||
};
|
||||
|
||||
// XFA
|
||||
CFile.prototype._isXFA = function()
|
||||
{
|
||||
return Module["_IsXFA"](this.nativeFile) ? true : false;
|
||||
};
|
||||
CFile.prototype._getXFA = function()
|
||||
{
|
||||
g_module_pointer.ptr = Module["_GetXFA"](this.nativeFile);
|
||||
return g_module_pointer;
|
||||
};
|
||||
|
||||
// INFO DOCUMENT
|
||||
CFile.prototype._getInfo = function()
|
||||
{
|
||||
|
||||
@ -210,14 +210,6 @@ WASM_EXPORT int CheckPerm(CDrawingFile* pFile, int nPermFlag)
|
||||
{
|
||||
return pFile->CheckPerm(nPermFlag) ? 1 : 0;
|
||||
}
|
||||
WASM_EXPORT int IsXFA(CDrawingFile* pFile)
|
||||
{
|
||||
return pFile->isXFA() ? 1 : 0;
|
||||
}
|
||||
WASM_EXPORT BYTE* GetXFA(CDrawingFile* pFile)
|
||||
{
|
||||
return pFile->getXFA();
|
||||
}
|
||||
|
||||
WASM_EXPORT void* GetImageBase64(CDrawingFile* pFile, int rId)
|
||||
{
|
||||
|
||||
@ -1194,7 +1194,7 @@ int main(int argc, char* argv[])
|
||||
}
|
||||
|
||||
// RASTER
|
||||
if (true)
|
||||
if (false)
|
||||
{
|
||||
int i = nTestPage;
|
||||
//for (int i = 0; i < nPagesCount; ++i)
|
||||
@ -2333,29 +2333,6 @@ int main(int argc, char* argv[])
|
||||
ReadInteractiveFormsFonts(pGrFile, 2);
|
||||
}
|
||||
|
||||
// XFA
|
||||
if (true && IsXFA(pGrFile))
|
||||
{
|
||||
BYTE* pXFA = GetXFA(pGrFile);
|
||||
nLength = READ_INT(pXFA);
|
||||
int i = 4;
|
||||
nLength -= 4;
|
||||
|
||||
BYTE bD = READ_BYTE(pXFA + i);
|
||||
i += 1;
|
||||
std::cout << " XFA: Dynamic " << (bool)bD << std::endl;
|
||||
|
||||
int nPathLength = READ_INT(pXFA + i);
|
||||
i += 4;
|
||||
NSFile::CFileBinary oFile;
|
||||
if (oFile.CreateFileW(NSFile::GetProcessDirectory() + L"/XFA.xml"))
|
||||
oFile.WriteFile(pXFA + i, nPathLength);
|
||||
oFile.CloseFile();
|
||||
i += nPathLength;
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
Close(pGrFile);
|
||||
|
||||
return 0;
|
||||
|
||||
@ -141,3 +141,8 @@ void IOfficeDrawingFile::ConvertToRaster(int nPageIndex, const std::wstring& pat
|
||||
pFrame->SaveFile(path, nImageType);
|
||||
RELEASEOBJECT(pFrame);
|
||||
}
|
||||
|
||||
std::vector<CPdfLink*> IOfficeDrawingFile::GetPdfLinks(int nPageIndex)
|
||||
{
|
||||
return std::vector<CPdfLink*>();
|
||||
}
|
||||
|
||||
@ -56,6 +56,20 @@ struct COfficeDrawingPageParams
|
||||
}
|
||||
};
|
||||
|
||||
struct CPdfLink
|
||||
{
|
||||
~CPdfLink() { RELEASEOBJECT(pNext); }
|
||||
|
||||
double pRect[4];
|
||||
BYTE nType;
|
||||
BYTE nKind;
|
||||
unsigned int unPage;
|
||||
unsigned int unKindFlag;
|
||||
double pData[4];
|
||||
std::string sData;
|
||||
CPdfLink* pNext = NULL;
|
||||
};
|
||||
|
||||
class GRAPHICS_DECL IOfficeDrawingFile
|
||||
{
|
||||
public:
|
||||
@ -103,6 +117,8 @@ public:
|
||||
virtual std::wstring GetInfo() = 0;
|
||||
virtual unsigned char* GetStructure() = 0;
|
||||
virtual unsigned char* GetLinks(int nPageIndex) = 0;
|
||||
|
||||
virtual std::vector<CPdfLink*> GetPdfLinks(int nPageIndex);
|
||||
};
|
||||
|
||||
#endif // _OFFICE_DRAWING_FILE_H
|
||||
|
||||
@ -204,6 +204,30 @@ void CDocxRenderer::DrawPage(IOfficeDrawingFile* pFile, size_t nPage)
|
||||
put_Width(dWidth);
|
||||
put_Height(dHeight);
|
||||
|
||||
if (pFile->GetType() == OfficeDrawingFileType::odftPDF)
|
||||
{
|
||||
std::vector<CPdfLink*> arrLinks = pFile->GetPdfLinks(nPage);
|
||||
for (int i = 0; i < arrLinks.size(); ++i)
|
||||
{
|
||||
LONG lType = arrLinks[i]->nType;
|
||||
double x1, y1, x2, y2;
|
||||
x1 = arrLinks[i]->pRect[0] / c_dMMToPix;
|
||||
y1 = arrLinks[i]->pRect[1] / c_dMMToPix;
|
||||
x2 = arrLinks[i]->pRect[2] / c_dMMToPix;
|
||||
y2 = arrLinks[i]->pRect[3] / c_dMMToPix;
|
||||
|
||||
std::wstring wsData;
|
||||
if (lType == 1 || lType == 9)
|
||||
continue; // TODO: GoTo bookmarks or anchors
|
||||
if (lType == 6)
|
||||
wsData = NSFile::CUtf8Converter::GetUnicodeStringFromUTF8((BYTE*)arrLinks[i]->sData.c_str(), arrLinks[i]->sData.size());
|
||||
|
||||
m_pInternal->m_oDocument.AddLink(lType, x1, y1, x2, y2, wsData);
|
||||
RELEASEOBJECT(arrLinks[i]);
|
||||
}
|
||||
m_pInternal->m_oDocument.m_oImageManager.UpdateId(arrLinks.size());
|
||||
}
|
||||
|
||||
pFile->DrawPageOnRenderer(this, nPage, nullptr);
|
||||
|
||||
m_pInternal->m_oDocument.m_bIsDisablePageCommand = false;
|
||||
|
||||
@ -30,6 +30,7 @@ LIBS += \
|
||||
HEADERS += \
|
||||
src/logic/elements/BaseItem.h \
|
||||
src/logic/elements/ContText.h \
|
||||
src/logic/elements/Link.h \
|
||||
src/logic/elements/Paragraph.h \
|
||||
src/logic/elements/Shape.h \
|
||||
src/logic/elements/Table.h \
|
||||
@ -55,6 +56,7 @@ HEADERS += \
|
||||
SOURCES += \
|
||||
src/logic/elements/BaseItem.cpp \
|
||||
src/logic/elements/ContText.cpp \
|
||||
src/logic/elements/Link.cpp \
|
||||
src/logic/elements/Paragraph.cpp \
|
||||
src/logic/elements/Shape.cpp \
|
||||
src/logic/elements/Table.cpp \
|
||||
|
||||
@ -744,6 +744,18 @@ namespace NSDocxRenderer
|
||||
m_oCurrentPage.m_lClipMode = lMode;
|
||||
return S_OK;
|
||||
}
|
||||
HRESULT CDocument::AddLink(const LONG& lType, const double& x1, const double y1, const double& x2, const double& y2, const std::wstring& wsData)
|
||||
{
|
||||
CLink oLink;
|
||||
|
||||
UINT nId = m_oImageManager.GetId() + m_arLinks.size();
|
||||
oLink.AddLink(nId, lType, wsData);
|
||||
oLink.AddBBox(x1, y1, x2, y2);
|
||||
m_arLinks.push_back(oLink);
|
||||
m_oCurrentPage.AddLink(oLink);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void CDocument::ApplyTransform(double d1, double d2, double d3, double d4, double d5, double d6)
|
||||
{
|
||||
@ -912,6 +924,17 @@ namespace NSDocxRenderer
|
||||
oWriter.WriteString(L"\"/>");
|
||||
}
|
||||
|
||||
for (const auto& pLink : m_arLinks)
|
||||
{
|
||||
oWriter.WriteString(L"<Relationship Id=\"rId");
|
||||
oWriter.AddUInt(c_iStartingIdForLinks + pLink.m_nId);
|
||||
oWriter.WriteString(L"\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink\" Target=\"");
|
||||
oWriter.WriteString(pLink.m_wsData);
|
||||
oWriter.WriteString(L"\" TargetMode=\"");
|
||||
oWriter.WriteString(pLink.m_eType == eLinkType::ltUri ? L"External" : L"Internal");
|
||||
oWriter.WriteString(L"\"/>");
|
||||
}
|
||||
|
||||
oWriter.WriteString(L"</Relationships>");
|
||||
|
||||
NSFile::CFileBinary::SaveToFile(m_strTempDirectory + L"/word/_rels/document.xml.rels", oWriter.GetData());
|
||||
|
||||
@ -44,6 +44,7 @@ namespace NSDocxRenderer
|
||||
|
||||
NSStringUtils::CStringBuilder m_oPageBuilder;
|
||||
std::list<std::string> m_arXmlString;
|
||||
std::list<CLink> m_arLinks;
|
||||
|
||||
public:
|
||||
CDocument(IRenderer* pRenderer, NSFonts::IApplicationFonts* pFonts);
|
||||
@ -178,6 +179,8 @@ namespace NSDocxRenderer
|
||||
HRESULT get_ClipMode(LONG* plMode);
|
||||
HRESULT put_ClipMode(LONG lMode);
|
||||
|
||||
HRESULT AddLink(const LONG& lType, const double& x1, const double y1, const double& x2, const double& y2, const std::wstring& wsData);
|
||||
|
||||
protected:
|
||||
void ApplyTransform(double d1, double d2, double d3, double d4, double d5, double d6);
|
||||
void ApplyTransform2(double dAngle, double dLeft, double dTop, double dWidth, double dHeight, DWORD lFlags);
|
||||
|
||||
@ -273,6 +273,18 @@ namespace NSDocxRenderer
|
||||
shape->m_oBrush.Color1 == c_iWhiteColor && !info)
|
||||
return;
|
||||
|
||||
for (const auto& link : m_arLinks)
|
||||
{
|
||||
if (fabs(shape->m_dTop - link.m_dTop) <= c_dLINK_X_OFFSET_MM &&
|
||||
fabs(shape->m_dLeft - link.m_dLeft) <= c_dLINK_X_OFFSET_MM &&
|
||||
fabs(shape->m_dBot - link.m_dBottom) <= c_dLINK_X_OFFSET_MM &&
|
||||
fabs(shape->m_dRight - link.m_dRight) <= c_dLINK_X_OFFSET_MM)
|
||||
{
|
||||
shape->m_bIsHyperlink = true;
|
||||
shape->m_nRid = c_iStartingIdForLinks + link.m_nId;
|
||||
}
|
||||
}
|
||||
|
||||
if (!skip_shape)
|
||||
{
|
||||
shape->m_nOrder = ++m_nCurrentOrder;
|
||||
@ -488,6 +500,10 @@ namespace NSDocxRenderer
|
||||
{
|
||||
m_arCompleteObjectsBinBase64.push_back(oBase64);
|
||||
}
|
||||
void CPage::AddLink(const CLink& oLink)
|
||||
{
|
||||
m_arLinks.push_back(oLink);
|
||||
}
|
||||
void CPage::ReorderShapesForPptx()
|
||||
{
|
||||
// переместим nullptr в конец и удалим
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
#include "elements/Paragraph.h"
|
||||
#include "elements/Table.h"
|
||||
#include "elements/Shape.h"
|
||||
#include "elements/Link.h"
|
||||
#include "managers/ImageManager.h"
|
||||
#include "managers/FontStyleManager.h"
|
||||
#include "managers/ParagraphStyleManager.h"
|
||||
@ -91,6 +92,8 @@ namespace NSDocxRenderer
|
||||
void AddCompleteXml(const std::wstring& oXml);
|
||||
void AddCompleteBinBase64(const std::string& oBase64);
|
||||
|
||||
void AddLink(const CLink& pLink);
|
||||
|
||||
private:
|
||||
using shape_ptr_t = std::shared_ptr<CShape>;
|
||||
using cont_ptr_t = std::shared_ptr<CContText>;
|
||||
@ -235,6 +238,8 @@ namespace NSDocxRenderer
|
||||
std::vector<shape_ptr_t> m_arLuminosityShapes;
|
||||
std::vector<shape_ptr_t> m_arOneColorGradientShape;
|
||||
|
||||
std::list<CLink> m_arLinks;
|
||||
|
||||
long m_lLastType = 0;
|
||||
|
||||
size_t m_nCurrentOrder = 0;
|
||||
|
||||
31
DocxRenderer/src/logic/elements/Link.cpp
Normal file
31
DocxRenderer/src/logic/elements/Link.cpp
Normal file
@ -0,0 +1,31 @@
|
||||
#include "Link.h"
|
||||
|
||||
namespace NSDocxRenderer
|
||||
{
|
||||
CLink::~CLink()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
void CLink::Clear()
|
||||
{
|
||||
m_nId = 0;
|
||||
m_eType = eLinkType::ltNone;
|
||||
m_wsData.clear();
|
||||
}
|
||||
|
||||
void CLink::AddLink(BYTE nId, const LONG& lType, const std::wstring& wsData)
|
||||
{
|
||||
m_nId = nId;
|
||||
m_eType = static_cast<eLinkType>(lType);
|
||||
m_wsData = wsData;
|
||||
}
|
||||
|
||||
void CLink::AddBBox(const double& x1, const double& y1, const double& x2, const double& y2)
|
||||
{
|
||||
m_dTop = y1;
|
||||
m_dLeft = x1;
|
||||
m_dBottom = y2;
|
||||
m_dRight = x2;
|
||||
}
|
||||
}
|
||||
34
DocxRenderer/src/logic/elements/Link.h
Normal file
34
DocxRenderer/src/logic/elements/Link.h
Normal file
@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
#include "BaseItem.h"
|
||||
|
||||
namespace NSDocxRenderer
|
||||
{
|
||||
enum class eLinkType
|
||||
{
|
||||
ltNone = 0,
|
||||
ltGoTo = 1,
|
||||
ltUri = 6,
|
||||
ltNamed = 9,
|
||||
};
|
||||
|
||||
class CLink : public CBaseItem
|
||||
{
|
||||
public:
|
||||
CLink() = default;
|
||||
virtual ~CLink();
|
||||
void Clear();
|
||||
|
||||
void AddLink(BYTE nId, const LONG& type, const std::wstring& wsData);
|
||||
void AddBBox(const double& x1, const double& y1, const double& x2, const double& y2);
|
||||
public:
|
||||
UINT m_nId{0};
|
||||
eLinkType m_eType{eLinkType::ltNone};
|
||||
|
||||
double m_dTop{0.0};
|
||||
double m_dLeft{0.0};
|
||||
double m_dBottom{0.0};
|
||||
double m_dRight{0.0};
|
||||
|
||||
std::wstring m_wsData{};
|
||||
};
|
||||
}
|
||||
@ -637,7 +637,14 @@ namespace NSDocxRenderer
|
||||
break;
|
||||
}
|
||||
oWriter.AddUInt(m_nShapeId);
|
||||
oWriter.WriteString(L"\"/>");
|
||||
oWriter.WriteString(L"\">");
|
||||
if (m_bIsHyperlink)
|
||||
{
|
||||
oWriter.WriteString(L"<a:hlinkClick xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\" r:id=\"rId");
|
||||
oWriter.AddUInt(m_nRid);
|
||||
oWriter.WriteString(L"\"/>");
|
||||
}
|
||||
oWriter.WriteString(L"</wp:docPr>");
|
||||
oWriter.WriteString(L"<wp:cNvGraphicFramePr/>");
|
||||
BuildSpecificProperties(oWriter);
|
||||
oWriter.WriteString(L"</wp:anchor>");
|
||||
|
||||
@ -46,11 +46,13 @@ namespace NSDocxRenderer
|
||||
std::wstring m_strDstMedia {};
|
||||
|
||||
double m_dRotation {0.0};
|
||||
int m_nRid {0};
|
||||
|
||||
bool m_bIsNoFill {true};
|
||||
bool m_bIsNoStroke {true};
|
||||
bool m_bIsBehindDoc {true};
|
||||
bool m_bIsUseInTable{false};
|
||||
bool m_bIsHyperlink {false};
|
||||
|
||||
std::shared_ptr<CImageInfo> m_pImageInfo{nullptr};
|
||||
double m_dImageTop{};
|
||||
|
||||
@ -132,10 +132,21 @@ namespace NSDocxRenderer
|
||||
m_strDstMedia = L"";
|
||||
m_lMaxSizeImage = 1200;
|
||||
m_lNextIDImage = 0;
|
||||
m_lFileID = 0;
|
||||
|
||||
m_mapImageData.clear();
|
||||
}
|
||||
|
||||
void CImageManager::UpdateId(int idInc)
|
||||
{
|
||||
m_lNextIDImage += idInc;
|
||||
}
|
||||
|
||||
int CImageManager::GetId() const
|
||||
{
|
||||
return m_lNextIDImage;
|
||||
}
|
||||
|
||||
std::shared_ptr<CImageInfo> CImageManager::WriteImage(Aggplus::CImage* pImage, double& x, double& y, double& width, double& height)
|
||||
{
|
||||
if (height < 0)
|
||||
@ -176,10 +187,11 @@ namespace NSDocxRenderer
|
||||
return find->second;
|
||||
|
||||
++m_lNextIDImage;
|
||||
++m_lFileID;
|
||||
auto pInfo = std::make_shared<CImageInfo>();
|
||||
pInfo->m_nId = m_lNextIDImage;
|
||||
pInfo->m_eType = GetImageType(pImage);
|
||||
pInfo->m_strFileName = L"image" + std::to_wstring(pInfo->m_nId);
|
||||
pInfo->m_strFileName = L"image" + std::to_wstring(m_lFileID);
|
||||
pInfo->m_strFileName += ((pInfo->m_eType == CImageInfo::itJPG) ? L".jpg" : L".png");
|
||||
|
||||
UINT format = (pInfo->m_eType == CImageInfo::itJPG) ? 3 : 4;
|
||||
|
||||
@ -19,6 +19,9 @@ namespace NSDocxRenderer
|
||||
~CImageManager() = default;
|
||||
void Clear();
|
||||
|
||||
void UpdateId(int idInc);
|
||||
int GetId() const;
|
||||
|
||||
std::shared_ptr<CImageInfo> WriteImage(Aggplus::CImage* pImage, double& x, double& y, double& width, double& height);
|
||||
std::shared_ptr<CImageInfo> WriteImage(const std::wstring& strFile);
|
||||
std::shared_ptr<CImageInfo> GenerateImageID(Aggplus::CImage* pImage);
|
||||
@ -30,6 +33,7 @@ namespace NSDocxRenderer
|
||||
std::shared_ptr<CImageInfo> GenerateImageID(const std::wstring& strFileName);
|
||||
int m_lMaxSizeImage {1200};
|
||||
int m_lNextIDImage {0};
|
||||
int m_lFileID {0};
|
||||
CCalculatorCRC32 m_oCRC;
|
||||
};
|
||||
}
|
||||
|
||||
@ -46,6 +46,7 @@ const double c_dLINE_DISTANCE_MAX_MM = 50.0;
|
||||
const double c_dSHAPE_TROUGH_MAX_MM = 80.0;
|
||||
const double c_dLINE_SPLIT_DISTANCE_MM = 10.0;
|
||||
const double c_dSHAPE_X_OFFSET_MM = 1.5;
|
||||
const double c_dLINK_X_OFFSET_MM = 0.1;
|
||||
const double c_dAVERAGE_SPACE_WIDTH_COEF = 0.9;
|
||||
const double c_dSPACE_WIDTH_COEF = 0.4;
|
||||
const double c_dMIN_ROTATION = 0.01;
|
||||
@ -64,6 +65,7 @@ const double c_dSTANDART_FIRSTLINE_INDENT_MM = 12.5;
|
||||
const uint32_t c_SPACE_SYM = 0x20;
|
||||
|
||||
const UINT c_iStartingIdForImages = 6;
|
||||
const UINT c_iStartingIdForLinks = 6;
|
||||
constexpr size_t c_nAntiZero = ~0;
|
||||
const UINT c_iStandartRelativeHeight = 0x0400;
|
||||
|
||||
|
||||
@ -453,12 +453,6 @@ bool CPdfFile::CheckPerm(int nPerm)
|
||||
return false;
|
||||
return m_pInternal->pReader->CheckPerm(nPerm);
|
||||
}
|
||||
bool CPdfFile::IsXFA()
|
||||
{
|
||||
if (!m_pInternal->pReader)
|
||||
return false;
|
||||
return m_pInternal->pReader->isXFA();
|
||||
}
|
||||
int CPdfFile::GetRotate(int nPageIndex)
|
||||
{
|
||||
if (!m_pInternal->pReader)
|
||||
@ -505,12 +499,6 @@ BYTE* CPdfFile::GetLinks(int nPageIndex)
|
||||
return NULL;
|
||||
return m_pInternal->pReader->GetLinks(nPageIndex);
|
||||
}
|
||||
BYTE* CPdfFile::GetXFA()
|
||||
{
|
||||
if (!m_pInternal->pReader)
|
||||
return NULL;
|
||||
return m_pInternal->pReader->GetXFA();
|
||||
}
|
||||
BYTE* CPdfFile::GetWidgets()
|
||||
{
|
||||
if (!m_pInternal->pReader)
|
||||
@ -617,6 +605,12 @@ BYTE* CPdfFile::GetAPAnnots(int nRasterW, int nRasterH, int nBackgroundColor, in
|
||||
return NULL;
|
||||
return m_pInternal->pReader->GetAPAnnots(nRasterW, nRasterH, nBackgroundColor, nPageIndex, nAnnot, sView);
|
||||
}
|
||||
std::vector<CPdfLink*> CPdfFile::GetPdfLinks(int nPageIndex)
|
||||
{
|
||||
if (!m_pInternal->pReader)
|
||||
return std::vector<CPdfLink*>();
|
||||
return m_pInternal->pReader->GetPdfLinks(nPageIndex);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
|
||||
@ -136,6 +136,7 @@ public:
|
||||
virtual std::wstring GetInfo();
|
||||
virtual BYTE* GetStructure();
|
||||
virtual BYTE* GetLinks(int nPageIndex);
|
||||
std::vector<CPdfLink*> GetPdfLinks(int nPageIndex) override;
|
||||
|
||||
bool ValidMetaData();
|
||||
// Захватывает полученную память malloc data
|
||||
@ -145,11 +146,9 @@ public:
|
||||
bool UndoRedact();
|
||||
bool CheckOwnerPassword(const wchar_t* sPassword);
|
||||
bool CheckPerm(int nPerm);
|
||||
bool IsXFA();
|
||||
int GetRotate(int nPageIndex);
|
||||
int GetMaxRefID();
|
||||
void SetPageFonts(int nPageIndex);
|
||||
BYTE* GetXFA();
|
||||
BYTE* GetWidgets();
|
||||
BYTE* GetAnnotEmbeddedFonts();
|
||||
BYTE* GetAnnotStandardFonts();
|
||||
|
||||
@ -56,7 +56,6 @@
|
||||
#include "lib/xpdf/TextOutputDev.h"
|
||||
#include "lib/xpdf/AcroForm.h"
|
||||
#include "lib/xpdf/SecurityHandler.h"
|
||||
#include "lib/xpdf/XFAScanner.h"
|
||||
#include "lib/goo/GList.h"
|
||||
|
||||
NSFonts::IFontManager* InitFontManager(NSFonts::IApplicationFonts* pAppFonts)
|
||||
@ -653,20 +652,6 @@ bool CPdfReader::CheckPerm(int nPerm)
|
||||
|
||||
return ownerPasswordOk || (permFlags & (1 << --nPerm));
|
||||
}
|
||||
bool CPdfReader::isXFA()
|
||||
{
|
||||
PDFDoc* pDoc = m_vPDFContext.front()->m_pDocument;
|
||||
AcroForm* pAcroForms = pDoc->getCatalog()->getForm();
|
||||
if (!pAcroForms)
|
||||
return false;
|
||||
|
||||
Object* oAcroForm = pAcroForms->getAcroFormObj();
|
||||
Object oXFA;
|
||||
|
||||
bool bRes = !oAcroForm->dictLookup("XFA", &oXFA)->isNull();
|
||||
oXFA.free();
|
||||
return bRes;
|
||||
}
|
||||
void CPdfReader::DrawPageOnRenderer(IRenderer* pRenderer, int _nPageIndex, bool* pbBreak)
|
||||
{
|
||||
PDFDoc* pDoc = NULL;
|
||||
@ -1088,40 +1073,6 @@ void getBookmarks(PDFDoc* pdfDoc, OutlineItem* pOutlineItem, NSWasm::CData& out,
|
||||
}
|
||||
pOutlineItem->close();
|
||||
}
|
||||
BYTE* CPdfReader::GetXFA()
|
||||
{
|
||||
PDFDoc* pDoc = m_vPDFContext.front()->m_pDocument;
|
||||
XRef* xref = pDoc->getXRef();
|
||||
AcroForm* pAcroForms = pDoc->getCatalog()->getForm();
|
||||
if (!pAcroForms)
|
||||
return NULL;
|
||||
|
||||
Object* oAcroForm = pAcroForms->getAcroFormObj();
|
||||
Object oXFA, oCatDict, oNR;
|
||||
|
||||
NSWasm::CData oRes;
|
||||
oRes.SkipLen();
|
||||
|
||||
bool bNR = false;
|
||||
if (xref->getCatalog(&oCatDict)->isDict() && oCatDict.dictLookup("NeedsRendering", &oNR)->isBool())
|
||||
bNR = !!oNR.getBool();
|
||||
oRes.WriteBool(bNR);
|
||||
oCatDict.free(); oNR.free();
|
||||
|
||||
if (!oAcroForm->dictLookup("XFA", &oXFA)->isNull())
|
||||
{
|
||||
GString* sXFA = XFAScanner::readXFAStreams(&oXFA);
|
||||
oRes.WriteString((BYTE*)sXFA->getCString(), sXFA->getLength());
|
||||
}
|
||||
else
|
||||
oRes.AddInt(0);
|
||||
oXFA.free();
|
||||
|
||||
oRes.WriteLen();
|
||||
BYTE* bRes = oRes.GetBuffer();
|
||||
oRes.ClearWithoutAttack();
|
||||
return bRes;
|
||||
}
|
||||
BYTE* CPdfReader::GetStructure()
|
||||
{
|
||||
if (m_vPDFContext.empty())
|
||||
@ -1173,7 +1124,6 @@ BYTE* CPdfReader::GetStructure()
|
||||
}
|
||||
BYTE* CPdfReader::GetLinks(int _nPageIndex)
|
||||
{
|
||||
// TODO Links должны стать частью Annots
|
||||
PDFDoc* pDoc = NULL;
|
||||
int nPageIndex = GetPageIndex(_nPageIndex, &pDoc);
|
||||
if (nPageIndex < 0 || !pDoc || !pDoc->getCatalog())
|
||||
@ -1306,6 +1256,64 @@ BYTE* CPdfReader::GetLinks(int _nPageIndex)
|
||||
|
||||
return oLinks.Serialize();
|
||||
}
|
||||
std::vector<CPdfLink*> CPdfReader::GetPdfLinks(int _nPageIndex)
|
||||
{
|
||||
std::vector<CPdfLink*> oRes;
|
||||
if (m_vPDFContext.empty())
|
||||
return oRes;
|
||||
|
||||
PDFDoc* pDoc = NULL;
|
||||
PdfReader::CPdfFontList* pFontList = NULL;
|
||||
int nStartRefID = 0;
|
||||
int nPageIndex = GetPageIndex(_nPageIndex, &pDoc, &pFontList, &nStartRefID);
|
||||
if (nPageIndex < 0 || !pDoc || !pFontList || !pDoc->getCatalog())
|
||||
return oRes;
|
||||
|
||||
Page* pPage = pDoc->getCatalog()->getPage(nPageIndex);
|
||||
if (!pPage)
|
||||
return oRes;
|
||||
|
||||
Object oAnnots;
|
||||
if (!pPage->getAnnots(&oAnnots)->isArray())
|
||||
{
|
||||
oAnnots.free();
|
||||
return oRes;
|
||||
}
|
||||
|
||||
for (int i = 0, nNum = oAnnots.arrayGetLength(); i < nNum; ++i)
|
||||
{
|
||||
Object oAnnot;
|
||||
if (!oAnnots.arrayGet(i, &oAnnot)->isDict())
|
||||
{
|
||||
oAnnot.free();
|
||||
continue;
|
||||
}
|
||||
|
||||
Object oSubtype;
|
||||
std::string sType;
|
||||
if (oAnnot.dictLookup("Subtype", &oSubtype)->isName())
|
||||
sType = oSubtype.getName();
|
||||
oSubtype.free(); oAnnot.free();
|
||||
|
||||
Object oAnnotRef;
|
||||
PdfReader::CAnnotLink* pAnnot = NULL;
|
||||
oAnnots.arrayGetNF(i, &oAnnotRef);
|
||||
|
||||
if (sType == "Link")
|
||||
pAnnot = new PdfReader::CAnnotLink(pDoc, &oAnnotRef, nPageIndex, nStartRefID);
|
||||
|
||||
CPdfLink* pLink = NULL;
|
||||
if (pAnnot)
|
||||
pLink = pAnnot->GetPdfLink();
|
||||
|
||||
if (pLink)
|
||||
oRes.push_back(pLink);
|
||||
RELEASEOBJECT(pAnnot);
|
||||
}
|
||||
|
||||
oAnnots.free();
|
||||
return oRes;
|
||||
}
|
||||
BYTE* CPdfReader::GetWidgets()
|
||||
{
|
||||
NSWasm::CData oRes;
|
||||
|
||||
@ -97,7 +97,6 @@ public:
|
||||
bool UndoRedact();
|
||||
bool CheckOwnerPassword(const wchar_t* sPassword);
|
||||
bool CheckPerm(int nPerm);
|
||||
bool isXFA();
|
||||
void GetPageInfo(int nPageIndex, double* pdWidth, double* pdHeight, double* pdDpiX, double* pdDpiY);
|
||||
void DrawPageOnRenderer(IRenderer* pRenderer, int nPageIndex, bool* pBreak);
|
||||
std::wstring GetInfo();
|
||||
@ -116,7 +115,6 @@ public:
|
||||
int GetPageIndex(int nPageIndex, PDFDoc** pDoc = NULL, PdfReader::CPdfFontList** pFontList = NULL, int* nStartRefID = NULL);
|
||||
|
||||
void SetFonts(int nPageIndex);
|
||||
BYTE* GetXFA();
|
||||
BYTE* GetStructure();
|
||||
BYTE* GetLinks(int nPageIndex);
|
||||
BYTE* GetWidgets();
|
||||
@ -128,6 +126,7 @@ public:
|
||||
BYTE* GetButtonIcon(int nBackgroundColor, int nPageIndex, bool bBase64 = false, int nBWidget = -1, const char* sIView = NULL);
|
||||
BYTE* StreamToCData(BYTE* pSteam, int nLength);
|
||||
const std::map<std::wstring, std::wstring>& GetFonts() { return m_mFonts; }
|
||||
std::vector<CPdfLink*> GetPdfLinks(int nPageIndex);
|
||||
|
||||
private:
|
||||
void Clear();
|
||||
|
||||
@ -533,6 +533,75 @@ CAnnot::CBorderType* getBorder(Object* oBorder, bool bBSorBorder)
|
||||
return pBorderType;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Action
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
void CActionGoTo::GetPdfLink(CPdfLink* pLink)
|
||||
{
|
||||
pLink->nType = 1;
|
||||
pLink->unPage = unPage;
|
||||
pLink->nKind = nKind;
|
||||
switch (nKind)
|
||||
{
|
||||
case destXYZ:
|
||||
case destFitH:
|
||||
case destFitBH:
|
||||
case destFitV:
|
||||
case destFitBV:
|
||||
{
|
||||
pLink->unKindFlag = unKindFlag;
|
||||
if (unKindFlag & (1 << 0))
|
||||
pLink->pData[0] = pRect[0];
|
||||
if (unKindFlag & (1 << 1))
|
||||
pLink->pData[1] = pRect[1];
|
||||
if (unKindFlag & (1 << 2))
|
||||
pLink->pData[2] = pRect[2];
|
||||
break;
|
||||
}
|
||||
case destFitR:
|
||||
{
|
||||
pLink->pData[0] = pRect[0];
|
||||
pLink->pData[1] = pRect[1];
|
||||
pLink->pData[2] = pRect[2];
|
||||
pLink->pData[3] = pRect[3];
|
||||
break;
|
||||
}
|
||||
case destFit:
|
||||
case destFitB:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (pNext)
|
||||
{
|
||||
pLink->pNext = new CPdfLink();
|
||||
GetPdfLink(pLink->pNext);
|
||||
}
|
||||
}
|
||||
void CActionURI::GetPdfLink(CPdfLink* pLink)
|
||||
{
|
||||
pLink->nType = 6;
|
||||
pLink->sData = sURI;
|
||||
|
||||
if (pNext)
|
||||
{
|
||||
pLink->pNext = new CPdfLink();
|
||||
GetPdfLink(pLink->pNext);
|
||||
}
|
||||
}
|
||||
void CActionNamed::GetPdfLink(CPdfLink* pLink)
|
||||
{
|
||||
pLink->nType = 10;
|
||||
pLink->sData = sNamed;
|
||||
|
||||
if (pNext)
|
||||
{
|
||||
pLink->pNext = new CPdfLink();
|
||||
GetPdfLink(pLink->pNext);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Widget
|
||||
//------------------------------------------------------------------------
|
||||
@ -1265,6 +1334,17 @@ CAnnotLink::~CAnnotLink()
|
||||
RELEASEOBJECT(m_pAction);
|
||||
RELEASEOBJECT(m_pPA);
|
||||
}
|
||||
CPdfLink* CAnnotLink::GetPdfLink()
|
||||
{
|
||||
CPdfLink* pRes = new CPdfLink();
|
||||
pRes->pRect[0] = m_pRect[0];
|
||||
pRes->pRect[1] = m_pRect[1];
|
||||
pRes->pRect[2] = m_pRect[2];
|
||||
pRes->pRect[3] = m_pRect[3];
|
||||
if (m_pAction)
|
||||
m_pAction->GetPdfLink(pRes);
|
||||
return pRes;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Screen
|
||||
|
||||
@ -41,6 +41,7 @@
|
||||
#include "../../DesktopEditor/graphics/pro/Fonts.h"
|
||||
#include "../../DesktopEditor/graphics/pro/Graphics.h"
|
||||
#include "../../DesktopEditor/graphics/pro/js/wasm/src/serialize.h"
|
||||
#include "../../DesktopEditor/graphics/pro/officedrawingfile.h"
|
||||
|
||||
#include "RendererOutputDev.h"
|
||||
|
||||
@ -57,6 +58,7 @@ public:
|
||||
virtual ~CAction() { RELEASEOBJECT(pNext); }
|
||||
|
||||
virtual void ToWASM(NSWasm::CData& oRes);
|
||||
virtual void GetPdfLink(CPdfLink* pLink) {};
|
||||
|
||||
std::string sType;
|
||||
CAction* pNext;
|
||||
@ -70,18 +72,21 @@ struct CActionGoTo final : public CAction
|
||||
double pRect[4];
|
||||
BYTE nKind;
|
||||
|
||||
virtual void GetPdfLink(CPdfLink* pLink) override;
|
||||
void ToWASM(NSWasm::CData& oRes) override;
|
||||
};
|
||||
struct CActionURI final : public CAction
|
||||
{
|
||||
std::string sURI;
|
||||
|
||||
virtual void GetPdfLink(CPdfLink* pLink) override;
|
||||
void ToWASM(NSWasm::CData& oRes) override;
|
||||
};
|
||||
struct CActionNamed final : public CAction
|
||||
{
|
||||
std::string sNamed;
|
||||
|
||||
virtual void GetPdfLink(CPdfLink* pLink) override;
|
||||
void ToWASM(NSWasm::CData& oRes) override;
|
||||
};
|
||||
struct CActionJavaScript final : public CAction
|
||||
@ -347,6 +352,8 @@ public:
|
||||
CAnnotLink(PDFDoc* pdfDoc, Object* oAnnotRef, int nPageIndex, int nStartRefID);
|
||||
virtual ~CAnnotLink();
|
||||
|
||||
CPdfLink* GetPdfLink();
|
||||
|
||||
void ToWASM(NSWasm::CData& oRes) override;
|
||||
|
||||
private:
|
||||
|
||||
@ -597,8 +597,9 @@ std::wstring GetFontData(PDFDoc* pdfDoc, NSFonts::IFontManager* pFontManager, CP
|
||||
}
|
||||
else
|
||||
{
|
||||
double dStretch = 1.0;
|
||||
std::wstring wsFBN = wsFontBaseName;
|
||||
NSFonts::CFontInfo* pFontInfo = RendererOutputDev::GetFontByParams(xref, pFontManager, gfxFont, wsFBN);
|
||||
NSFonts::CFontInfo* pFontInfo = RendererOutputDev::GetFontByParams(xref, pFontManager, gfxFont, wsFBN, dStretch);
|
||||
if (pFontInfo && !pFontInfo->m_wsFontPath.empty())
|
||||
{
|
||||
EraseSubsetTag(wsFontBaseName);
|
||||
@ -1064,7 +1065,7 @@ void CollectFontWidths(GfxFont* gfxFont, Dict* pFontDict, std::map<unsigned int,
|
||||
}
|
||||
oDescendantFonts.free();
|
||||
}
|
||||
void CheckFontStylePDF(std::wstring& sName, bool& bBold, bool& bItalic)
|
||||
double CheckFontStylePDF(std::wstring& sName, bool& bBold, bool& bItalic)
|
||||
{
|
||||
EraseSubsetTag(sName);
|
||||
|
||||
@ -1072,16 +1073,18 @@ void CheckFontStylePDF(std::wstring& sName, bool& bBold, bool& bItalic)
|
||||
CheckFontNameStyle(sName, L"semibold");
|
||||
CheckFontNameStyle(sName, L"regular");
|
||||
|
||||
CheckFontNameStyle(sName, L"ultraexpanded");
|
||||
CheckFontNameStyle(sName, L"extraexpanded");
|
||||
CheckFontNameStyle(sName, L"semiexpanded");
|
||||
CheckFontNameStyle(sName, L"expanded");
|
||||
double dStretch = 1.0;
|
||||
|
||||
CheckFontNameStyle(sName, L"ultracondensed");
|
||||
CheckFontNameStyle(sName, L"extracondensed");
|
||||
CheckFontNameStyle(sName, L"semicondensed");
|
||||
CheckFontNameStyle(sName, L"condensedlight");
|
||||
CheckFontNameStyle(sName, L"condensed");
|
||||
if (CheckFontNameStyle(sName, L"ultraexpanded")) dStretch = 2.0;
|
||||
if (CheckFontNameStyle(sName, L"extraexpanded")) dStretch = 1.5;
|
||||
if (CheckFontNameStyle(sName, L"semiexpanded")) dStretch = 1.125;
|
||||
if (CheckFontNameStyle(sName, L"expanded")) dStretch = 1.25;
|
||||
|
||||
if (CheckFontNameStyle(sName, L"ultracondensed")) dStretch = 0.5;
|
||||
if (CheckFontNameStyle(sName, L"extracondensed")) dStretch = 0.625;
|
||||
if (CheckFontNameStyle(sName, L"semicondensed")) dStretch = 0.875;
|
||||
if (CheckFontNameStyle(sName, L"condensedlight")) dStretch = 0.75;
|
||||
if (CheckFontNameStyle(sName, L"condensed")) dStretch = 0.75;
|
||||
//CheckFontNameStyle(sName, L"light");
|
||||
|
||||
if (CheckFontNameStyle(sName, L"bold_italic")) { bBold = true; bItalic = true; }
|
||||
@ -1097,6 +1100,8 @@ void CheckFontStylePDF(std::wstring& sName, bool& bBold, bool& bItalic)
|
||||
//if (CheckFontNameStyle(sName, L"bolditalicmt")) { bBold = true; bItalic = true; }
|
||||
//if (CheckFontNameStyle(sName, L"bolditalic")) { bBold = true; bItalic = true; }
|
||||
//if (CheckFontNameStyle(sName, L"boldoblique")) { bBold = true; bItalic = true; }
|
||||
|
||||
return dStretch;
|
||||
}
|
||||
bool EraseSubsetTag(std::wstring& sFontName)
|
||||
{
|
||||
|
||||
@ -65,7 +65,7 @@ std::vector<CAnnotFontInfo> GetAnnotFontInfos(PDFDoc* pdfDoc, NSFonts::IFontMana
|
||||
std::map<std::wstring, std::wstring> GetFreeTextFont(PDFDoc* pdfDoc, NSFonts::IFontManager* pFontManager, CPdfFontList* pFontList, Object* oAnnotRef, std::vector<CAnnotMarkup::CFontData*>& arrRC);
|
||||
bool FindFonts(Object* oStream, int nDepth, Object* oResFonts);
|
||||
void CollectFontWidths(GfxFont* gfxFont, Dict* pFontDict, std::map<unsigned int, unsigned int>& mGIDToWidth);
|
||||
void CheckFontStylePDF(std::wstring& sName, bool& bBold, bool& bItalic);
|
||||
double CheckFontStylePDF(std::wstring& sName, bool& bBold, bool& bItalic);
|
||||
bool EraseSubsetTag(std::wstring& sFontName);
|
||||
}
|
||||
|
||||
|
||||
@ -77,12 +77,12 @@
|
||||
|
||||
namespace PdfReader
|
||||
{
|
||||
void CheckFontNamePDF(std::wstring& sName, NSFonts::CFontSelectFormat* format)
|
||||
double CheckFontNamePDF(std::wstring& sName, NSFonts::CFontSelectFormat* format)
|
||||
{
|
||||
bool bBold = false;
|
||||
bool bItalic = false;
|
||||
|
||||
CheckFontStylePDF(sName, bBold, bItalic);
|
||||
double dStretch = CheckFontStylePDF(sName, bBold, bItalic);
|
||||
|
||||
if (format)
|
||||
{
|
||||
@ -91,6 +91,20 @@ namespace PdfReader
|
||||
if (bItalic)
|
||||
format->bItalic = new INT(1);
|
||||
}
|
||||
|
||||
return dStretch;
|
||||
}
|
||||
USHORT StretchToWidthClass(double fStretch)
|
||||
{
|
||||
if (fStretch <= 0.50) return 1; // Ultra-condensed
|
||||
if (fStretch <= 0.625) return 2; // Extra-condensed
|
||||
if (fStretch <= 0.75) return 3; // Condensed
|
||||
if (fStretch <= 0.875) return 4; // Semi-condensed
|
||||
if (fStretch <= 1.0) return 5; // Normal
|
||||
if (fStretch <= 1.125) return 6; // Semi-expanded
|
||||
if (fStretch <= 1.25) return 7; // Expanded
|
||||
if (fStretch <= 1.50) return 8; // Extra-expanded
|
||||
return 9; // Ultra-expanded
|
||||
}
|
||||
|
||||
void Transform(double* pMatrix, double dUserX, double dUserY, double* pdDeviceX, double* pdDeviceY)
|
||||
@ -738,7 +752,7 @@ namespace PdfReader
|
||||
{
|
||||
|
||||
}
|
||||
NSFonts::CFontInfo* RendererOutputDev::GetFontByParams(XRef* pXref, NSFonts::IFontManager* pFontManager, GfxFont* pFont, std::wstring& wsFontBaseName)
|
||||
NSFonts::CFontInfo* RendererOutputDev::GetFontByParams(XRef* pXref, NSFonts::IFontManager* pFontManager, GfxFont* pFont, std::wstring& wsFontBaseName, double& dStretch)
|
||||
{
|
||||
NSFonts::CFontInfo* pFontInfo = NULL;
|
||||
if (!pFontManager)
|
||||
@ -751,7 +765,9 @@ namespace PdfReader
|
||||
oRefObject.free();
|
||||
|
||||
NSFonts::CFontSelectFormat oFontSelect;
|
||||
CheckFontNamePDF(wsFontBaseName, &oFontSelect);
|
||||
dStretch = CheckFontNamePDF(wsFontBaseName, &oFontSelect);
|
||||
if (std::abs(dStretch - 1.0f) > 1e-5f)
|
||||
oFontSelect.usWidth = new USHORT(StretchToWidthClass(dStretch));
|
||||
if (oFontObject.isDict())
|
||||
{
|
||||
Dict* pFontDict = oFontObject.getDict();
|
||||
@ -825,7 +841,7 @@ namespace PdfReader
|
||||
oDictItem.free();
|
||||
|
||||
oFontDescriptor.dictLookup("StemV", &oDictItem);
|
||||
if (oDictItem.isNum())
|
||||
if (oDictItem.isNum() && !oFontSelect.usWidth)
|
||||
{
|
||||
double dStemV = oDictItem.getNum();
|
||||
if (dStemV > 50.5)
|
||||
@ -884,6 +900,7 @@ namespace PdfReader
|
||||
wsFontBaseName = L"Helvetica";
|
||||
const BYTE* pData14 = NULL;
|
||||
unsigned int nSize14 = 0;
|
||||
double dStretch = 1.0;
|
||||
#ifdef FONTS_USE_ONLY_MEMORY_STREAMS
|
||||
CMemoryFontStream oMemoryFontStream;
|
||||
#endif
|
||||
@ -1194,7 +1211,7 @@ namespace PdfReader
|
||||
else if (!pFont->locateFont(pXref, false) ||
|
||||
(wsFileName = NSStrings::GetStringFromUTF32(pFont->locateFont(pXref, false)->path)).length() == 0)
|
||||
{
|
||||
NSFonts::CFontInfo* pFontInfo = GetFontByParams(pXref, pFontManager, pFont, wsFontBaseName);
|
||||
NSFonts::CFontInfo* pFontInfo = GetFontByParams(pXref, pFontManager, pFont, wsFontBaseName, dStretch);
|
||||
|
||||
if (pFontInfo && L"" != pFontInfo->m_wsFontPath)
|
||||
{
|
||||
@ -1593,6 +1610,7 @@ namespace PdfReader
|
||||
pEntry->unLenGID = (unsigned int)nLen;
|
||||
pEntry->unLenUnicode = (unsigned int)nToUnicodeLen;
|
||||
pEntry->bAvailable = true;
|
||||
pEntry->dStretch = dStretch;
|
||||
pEntry->bFontSubstitution = bFontSubstitution;
|
||||
pEntry->bIsIdentity = pFont->isCIDFont() == gTrue ? ((GfxCIDFont*)pFont)->usesIdentityEncoding() || ((GfxCIDFont*)pFont)->usesIdentityCIDToGID() || ((GfxCIDFont*)pFont)->ctuUsesCharCodeToUnicode() || pFont->getType() == fontCIDType0C : false;
|
||||
}
|
||||
@ -2493,6 +2511,12 @@ namespace PdfReader
|
||||
}
|
||||
}
|
||||
|
||||
if (oEntry.dStretch != 1.0 && oEntry.bFontSubstitution)
|
||||
{
|
||||
arrMatrix[0] *= oEntry.dStretch;
|
||||
arrMatrix[1] *= oEntry.dStretch;
|
||||
}
|
||||
|
||||
double dShiftX = 0, dShiftY = 0;
|
||||
DoTransform(arrMatrix, &dShiftX, &dShiftY, true);
|
||||
|
||||
|
||||
@ -57,6 +57,7 @@ namespace PdfReader
|
||||
bool bAvailable; // Доступен ли шрифт. Сделано для многопотоковости
|
||||
bool bFontSubstitution = false;
|
||||
bool bIsIdentity = false;
|
||||
double dStretch = 1.0;
|
||||
|
||||
};
|
||||
|
||||
@ -244,7 +245,7 @@ namespace PdfReader
|
||||
{
|
||||
m_pbBreak = pbBreak;
|
||||
}
|
||||
static NSFonts::CFontInfo* GetFontByParams(XRef* pXref, NSFonts::IFontManager* pFontManager, GfxFont* pFont, std::wstring& wsFontBaseName);
|
||||
static NSFonts::CFontInfo* GetFontByParams(XRef* pXref, NSFonts::IFontManager* pFontManager, GfxFont* pFont, std::wstring& wsFontBaseName, double& dStretch);
|
||||
static void GetFont(XRef* pXref, NSFonts::IFontManager* pFontManager, CPdfFontList *pFontList, GfxFont* pFont, std::wstring& wsFileName, std::wstring& wsFontName, bool bNotFullName = true);
|
||||
|
||||
private:
|
||||
|
||||
@ -343,15 +343,13 @@ AcroForm *AcroForm::load(PDFDoc *docA, Catalog *catalog, Object *acroFormObjA) {
|
||||
AcroFormField *field;
|
||||
Object xfaObj, fieldsObj, annotsObj, annotRef, annotObj, obj1, obj2;
|
||||
int pageNum, i, j;
|
||||
GString* sXFA = NULL;
|
||||
|
||||
// this is the normal case: acroFormObj is a dictionary, as expected
|
||||
if (acroFormObjA->isDict()) {
|
||||
acroForm = new AcroForm(docA, acroFormObjA);
|
||||
|
||||
if (!acroFormObjA->dictLookup("XFA", &xfaObj)->isNull()) {
|
||||
sXFA = XFAScanner::readXFAStreams(&xfaObj);
|
||||
acroForm->xfaScanner = NULL;
|
||||
if (!acroFormObjA->dictLookup("XFA", &xfaObj)->isNull()) {
|
||||
acroForm->xfaScanner = XFAScanner::load(&xfaObj);
|
||||
if (!catalog->getNeedsRendering()) {
|
||||
acroForm->isStaticXFA = gTrue;
|
||||
}
|
||||
@ -721,7 +719,7 @@ AcroFormField *AcroFormField::load(AcroForm *acroFormA, Object *fieldRefA) {
|
||||
i0 = i1;
|
||||
}
|
||||
}
|
||||
xfaFieldA = acroFormA->xfaScanner->findField(xfaName);
|
||||
xfaFieldA = acroFormA->xfaScanner->findField(xfaName);
|
||||
delete xfaName;
|
||||
}
|
||||
|
||||
@ -745,9 +743,9 @@ AcroFormField *AcroFormField::load(AcroForm *acroFormA, Object *fieldRefA) {
|
||||
typeA = acroFormFieldCheckbox;
|
||||
}
|
||||
} else if (!typeStr->cmp("Tx")) {
|
||||
if (xfaFieldA && xfaFieldA->getBarcodeInfo()) {
|
||||
typeA = acroFormFieldBarcode;
|
||||
} else if (flagsA & acroFormFlagFileSelect) {
|
||||
if (xfaFieldA && xfaFieldA->getBarcodeInfo()) {
|
||||
typeA = acroFormFieldBarcode;
|
||||
} else if (flagsA & acroFormFlagFileSelect) {
|
||||
typeA = acroFormFieldFileSelect;
|
||||
} else if (flagsA & acroFormFlagMultiline) {
|
||||
typeA = acroFormFieldMultilineText;
|
||||
@ -862,9 +860,9 @@ Unicode *AcroFormField::getValue(int *length) {
|
||||
// from the XFA field (NB: an XFA field with no value overrides the
|
||||
// AcroForm value)
|
||||
if (xfaField) {
|
||||
if (xfaField->getValue()) {
|
||||
u = utf8ToUnicode(xfaField->getValue(), length);
|
||||
}
|
||||
if (xfaField->getValue()) {
|
||||
u = utf8ToUnicode(xfaField->getValue(), length);
|
||||
}
|
||||
|
||||
// no XFA form - take the AcroForm value
|
||||
} else {
|
||||
@ -1223,7 +1221,7 @@ void AcroFormField::drawAnnot(int pageNum, Gfx *gfx, GBool printing,
|
||||
if (acroForm->needAppearances) {
|
||||
render = gTrue;
|
||||
} else if (xfaField && xfaField->getValue()) {
|
||||
render = gTrue;
|
||||
render = gTrue;
|
||||
} else {
|
||||
if (!annotObj->dictLookup("AP", &obj1)->isDict()) {
|
||||
render = gTrue;
|
||||
|
||||
@ -125,7 +125,6 @@ class XFAScanner {
|
||||
public:
|
||||
|
||||
static XFAScanner *load(Object *xfaObj);
|
||||
static GString *readXFAStreams(Object *xfaObj);
|
||||
|
||||
virtual ~XFAScanner();
|
||||
|
||||
@ -136,6 +135,7 @@ public:
|
||||
private:
|
||||
|
||||
XFAScanner();
|
||||
static GString *readXFAStreams(Object *xfaObj);
|
||||
GHash *scanFormValues(ZxElement *xmlRoot);
|
||||
void scanFormNode(ZxElement *elem, GString *fullName,
|
||||
GHash *formValues);
|
||||
|
||||
@ -293,7 +293,7 @@ Object *ObjectStream::getObject(int objIdx, int objNum, Object *obj) {
|
||||
|
||||
XRef::XRef(BaseStream *strA, GBool repair) {
|
||||
GFileOffset pos;
|
||||
Object obj;
|
||||
Object obj, root, rootType;
|
||||
XRefPosSet *posSet;
|
||||
int i;
|
||||
|
||||
@ -370,6 +370,17 @@ XRef::XRef(BaseStream *strA, GBool repair) {
|
||||
if (obj.isRef()) {
|
||||
rootNum = obj.getRefNum();
|
||||
rootGen = obj.getRefGen();
|
||||
|
||||
fetch(rootNum, rootGen, &root);
|
||||
if (!root.isDict() || !root.dictLookup("Type", &rootType)->isName("Catalog"))
|
||||
{
|
||||
root.free(); rootType.free();
|
||||
errCode = errDamaged;
|
||||
ok = gFalse;
|
||||
return;
|
||||
}
|
||||
root.free(); rootType.free();
|
||||
|
||||
obj.free();
|
||||
} else {
|
||||
obj.free();
|
||||
@ -972,6 +983,39 @@ GBool XRef::constructXRef() {
|
||||
error(errSyntaxError, -1, "Couldn't find trailer dictionary");
|
||||
return gFalse;
|
||||
}
|
||||
|
||||
// validate the catalog object found by the initial xref scan
|
||||
if (!quickCheckCatalog(str, entries[rootNum].offset + start)) {
|
||||
error(errSyntaxWarning, -1, "invalid Catalog, trying repair scan");
|
||||
// reset state before repair scan
|
||||
rootNum = -1;
|
||||
rootGen = -1;
|
||||
|
||||
gfree(entries);
|
||||
entries = NULL;
|
||||
size = 0;
|
||||
last = -1;
|
||||
|
||||
for (int i = 0; i < xrefCacheSize; ++i) {
|
||||
if (cache[i].num >= 0) {
|
||||
cache[i].num = -1;
|
||||
cache[i].obj.free();
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < objStrCacheLength; ++i) {
|
||||
delete objStrs[i];
|
||||
objStrs[i] = NULL;
|
||||
}
|
||||
objStrCacheLength = 0;
|
||||
|
||||
gfree(xrefTablePos);
|
||||
xrefTablePos = NULL;
|
||||
xrefTablePosLen = 0;
|
||||
|
||||
if (!trailerDict.isNone()) trailerDict.free();
|
||||
return constructXRefRepair();
|
||||
}
|
||||
|
||||
return gTrue;
|
||||
}
|
||||
|
||||
@ -1016,6 +1060,316 @@ GBool XRef::saveTrailerDict(Dict *dict, GBool isXRefStream) {
|
||||
return bRes;
|
||||
}
|
||||
|
||||
// quick check: is the object at the given offset a /Type /Catalog dict?
|
||||
GBool XRef::quickCheckCatalog(BaseStream *str, GFileOffset pos) {
|
||||
if (pos < 0) return gFalse;
|
||||
char buf[512];
|
||||
str->setPos(pos);
|
||||
int n = str->getBlock(buf, sizeof(buf) - 1);
|
||||
if (n <= 0) return gFalse;
|
||||
buf[n] = '\0';
|
||||
|
||||
// skip "N G obj"
|
||||
char *p = strstr(buf, " obj");
|
||||
if (!p) return gFalse;
|
||||
p += 4;
|
||||
|
||||
// look for /Type key
|
||||
char *t = strstr(p, "/Type");
|
||||
if (!t || t - buf > 450) return gFalse;
|
||||
t += 5;
|
||||
|
||||
// skip whitespace between /Type and its value
|
||||
while (*t == ' ' || *t == '\t' || *t == '\r' || *t == '\n') ++t;
|
||||
|
||||
// value may be "/Catalog" or "/ Catalog" — skip the slash
|
||||
if (*t == '/') ++t;
|
||||
while (*t == ' ' || *t == '\t') ++t;
|
||||
|
||||
return strncmp(t, "Catalog", 7) == 0;
|
||||
}
|
||||
|
||||
GFileOffset XRef::findValidCutoff(XRefTempEntry *tempEntries, int tempSize, std::vector<XRefTrailerCandidate> &candidates) {
|
||||
for (auto it = candidates.rbegin(); it != candidates.rend(); ++it) {
|
||||
XRefTrailerCandidate &c = *it;
|
||||
|
||||
GFileOffset rootPos = c.rootObjPos;
|
||||
if (rootPos < 0 && c.rootNum < tempSize && tempEntries[c.rootNum].used)
|
||||
rootPos = tempEntries[c.rootNum].offset;
|
||||
|
||||
if (rootPos < 0) continue;
|
||||
|
||||
if (quickCheckCatalog(str, rootPos + start)) {
|
||||
return (c.sectionEnd >= 0) ? c.sectionEnd : c.trailerPos;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
GBool XRef::constructXRefRepair() {
|
||||
int tempSize = 0;
|
||||
XRefTempEntry *tempEntries = NULL;
|
||||
|
||||
auto ensureTemp = [&](int num) {
|
||||
if (num >= tempSize) {
|
||||
int newSize = num + 256;
|
||||
tempEntries = (XRefTempEntry *)greallocn(
|
||||
tempEntries, newSize, sizeof(XRefTempEntry));
|
||||
for (int i = tempSize; i < newSize; ++i) {
|
||||
tempEntries[i].offset = -1;
|
||||
tempEntries[i].gen = 0;
|
||||
tempEntries[i].used = gFalse;
|
||||
}
|
||||
tempSize = newSize;
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<XRefTrailerCandidate> candidates;
|
||||
|
||||
int tmpStreamEndsSize = 0;
|
||||
int tmpStreamEndsLen = 0;
|
||||
GFileOffset *tmpStreamEnds = NULL;
|
||||
|
||||
// ---------- PASS 1 ----------
|
||||
{
|
||||
char buf[4096 + 1];
|
||||
str->reset();
|
||||
GFileOffset bufPos = start;
|
||||
char *p = buf;
|
||||
char *end = buf;
|
||||
GBool startOfLine = gTrue;
|
||||
GBool eof = gFalse;
|
||||
|
||||
GFileOffset sectionStart = start;
|
||||
|
||||
while (1) {
|
||||
if (end - p < 256 && !eof) {
|
||||
memmove(buf, p, end - p);
|
||||
bufPos += p - buf;
|
||||
p = buf + (end - p);
|
||||
int n = (int)(buf + 4096 - p);
|
||||
int m = str->getBlock(p, n);
|
||||
end = p + m;
|
||||
*end = '\0';
|
||||
p = buf;
|
||||
eof = m < n;
|
||||
}
|
||||
if (p == end && eof) break;
|
||||
|
||||
GFileOffset curPos = (GFileOffset)(bufPos + (p - buf));
|
||||
|
||||
// %%EOF — close current section
|
||||
if (startOfLine && p[0] == '%' && !strncmp(p, "%%EOF", 5)) {
|
||||
for (auto &c : candidates)
|
||||
if (c.sectionEnd < 0 && c.sectionStart == sectionStart)
|
||||
c.sectionEnd = curPos;
|
||||
sectionStart = curPos + 5;
|
||||
p += 5;
|
||||
startOfLine = gFalse;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (startOfLine && !strncmp(p, "endstream", 9)) {
|
||||
if (tmpStreamEndsLen == tmpStreamEndsSize) {
|
||||
tmpStreamEndsSize += 64;
|
||||
tmpStreamEnds = (GFileOffset *)greallocn(
|
||||
tmpStreamEnds, tmpStreamEndsSize, sizeof(GFileOffset));
|
||||
}
|
||||
tmpStreamEnds[tmpStreamEndsLen++] = curPos;
|
||||
p += 9;
|
||||
startOfLine = gFalse;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (startOfLine && !strncmp(p, "trailer", 7)) {
|
||||
GFileOffset tPos = (GFileOffset)(bufPos + (p + 7 - buf));
|
||||
Object tDict, obj;
|
||||
obj.initNull();
|
||||
Parser *parser = new Parser(
|
||||
NULL,
|
||||
new Lexer(NULL, str->makeSubStream(tPos, gFalse, 0, &obj)),
|
||||
gFalse);
|
||||
parser->getObj(&tDict);
|
||||
if (tDict.isDict()) {
|
||||
Object rootRef;
|
||||
tDict.getDict()->lookupNF("Root", &rootRef);
|
||||
if (rootRef.isRef()) {
|
||||
int rNum = rootRef.getRefNum();
|
||||
ensureTemp(rNum);
|
||||
XRefTrailerCandidate c;
|
||||
c.trailerPos = tPos;
|
||||
c.sectionStart = sectionStart;
|
||||
c.sectionEnd = -1;
|
||||
c.rootNum = rNum;
|
||||
c.rootGen = rootRef.getRefGen();
|
||||
// rootObjPos — берём то что уже видели к этому моменту
|
||||
c.rootObjPos = tempEntries[rNum].used
|
||||
? tempEntries[rNum].offset
|
||||
: -1;
|
||||
candidates.push_back(c);
|
||||
}
|
||||
rootRef.free();
|
||||
}
|
||||
tDict.free();
|
||||
delete parser;
|
||||
p += 7;
|
||||
startOfLine = gFalse;
|
||||
continue;
|
||||
}
|
||||
|
||||
// N G obj — write to tempEntries only
|
||||
if (startOfLine && *p >= '0' && *p <= '9') {
|
||||
char *q = p;
|
||||
int num = 0, gen = 0;
|
||||
do { num = num * 10 + (*q - '0'); ++q; }
|
||||
while (*q >= '0' && *q <= '9' && num < 100000000);
|
||||
if (*q == '\t' || *q == '\x0c' || *q == ' ') {
|
||||
do { ++q; } while (*q == '\t' || *q == '\x0c' || *q == ' ');
|
||||
if (*q >= '0' && *q <= '9') {
|
||||
do { gen = gen * 10 + (*q - '0'); ++q; }
|
||||
while (*q >= '0' && *q <= '9' && gen < 100000000);
|
||||
if ((*q == '\t' || *q == '\x0c' || *q == ' ') &&
|
||||
!strncmp(q + 1, "obj", 3)) {
|
||||
ensureTemp(num);
|
||||
// will be overwritten — pass 2 is bounded by cutoff
|
||||
tempEntries[num].offset = curPos - start;
|
||||
tempEntries[num].gen = gen;
|
||||
tempEntries[num].used = gTrue;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (*p && *p != '\n' && *p != '\r') ++p;
|
||||
startOfLine = gFalse;
|
||||
continue;
|
||||
}
|
||||
|
||||
startOfLine = (*p == '\n' || *p == '\r');
|
||||
++p;
|
||||
}
|
||||
} // end of pass 1
|
||||
|
||||
// ---------- VALIDATION ----------
|
||||
GFileOffset cutoffPos = findValidCutoff(tempEntries, tempSize, candidates);
|
||||
gfree(tempEntries);
|
||||
gfree(tmpStreamEnds);
|
||||
|
||||
if (cutoffPos < 0) {
|
||||
error(errSyntaxWarning, -1, "no valid Catalog found, scanning entire file");
|
||||
cutoffPos = str->getPos();
|
||||
}
|
||||
|
||||
// ---------- PASS 2 ----------
|
||||
// identical to original constructXRef, but stops at curPos >= cutoffPos
|
||||
|
||||
int streamObjNumsSize = 0;
|
||||
int streamObjNumsLen = 0;
|
||||
int *streamObjNums = NULL;
|
||||
int lastObjNum = -1;
|
||||
rootNum = -1;
|
||||
|
||||
gfree(streamEnds);
|
||||
streamEnds = NULL;
|
||||
streamEndsLen = 0;
|
||||
int streamEndsSize = 0;
|
||||
|
||||
{
|
||||
char buf[4096 + 1];
|
||||
str->reset();
|
||||
GFileOffset bufPos = start;
|
||||
char *p = buf;
|
||||
char *end = buf;
|
||||
GBool startOfLine = gTrue;
|
||||
GBool eof = gFalse;
|
||||
|
||||
while (1) {
|
||||
if (end - p < 256 && !eof) {
|
||||
memmove(buf, p, end - p);
|
||||
bufPos += p - buf;
|
||||
p = buf + (end - p);
|
||||
int n = (int)(buf + 4096 - p);
|
||||
int m = str->getBlock(p, n);
|
||||
end = p + m;
|
||||
*end = '\0';
|
||||
p = buf;
|
||||
eof = m < n;
|
||||
}
|
||||
if (p == end && eof) break;
|
||||
|
||||
GFileOffset curPos = (GFileOffset)(bufPos + (p - buf));
|
||||
|
||||
if (curPos - start >= cutoffPos)
|
||||
break;
|
||||
|
||||
if (startOfLine && !strncmp(p, "trailer", 7)) {
|
||||
constructTrailerDict((GFileOffset)(bufPos + (p + 7 - buf)));
|
||||
p += 7;
|
||||
startOfLine = gFalse;
|
||||
} else if (startOfLine && !strncmp(p, "endstream", 9)) {
|
||||
if (streamEndsLen == streamEndsSize) {
|
||||
streamEndsSize += 64;
|
||||
streamEnds = (GFileOffset *)greallocn(
|
||||
streamEnds, streamEndsSize, sizeof(GFileOffset));
|
||||
}
|
||||
streamEnds[streamEndsLen++] = curPos;
|
||||
p += 9;
|
||||
startOfLine = gFalse;
|
||||
} else if (startOfLine && *p >= '0' && *p <= '9') {
|
||||
p = constructObjectEntry(p, (GFileOffset)(bufPos + (p - buf)),
|
||||
&lastObjNum);
|
||||
startOfLine = gFalse;
|
||||
} else if (p[0] == '>' && p[1] == '>') {
|
||||
p += 2;
|
||||
startOfLine = gFalse;
|
||||
while (*p == '\t' || *p == '\n' || *p == '\x0c' ||
|
||||
*p == '\r' || *p == ' ') {
|
||||
startOfLine = (*p == '\n' || *p == '\r');
|
||||
++p;
|
||||
}
|
||||
if (!strncmp(p, "stream", 6)) {
|
||||
if (lastObjNum >= 0) {
|
||||
if (streamObjNumsLen == streamObjNumsSize) {
|
||||
streamObjNumsSize += 64;
|
||||
streamObjNums = (int *)greallocn(
|
||||
streamObjNums, streamObjNumsSize, sizeof(int));
|
||||
}
|
||||
streamObjNums[streamObjNumsLen++] = lastObjNum;
|
||||
}
|
||||
p += 6;
|
||||
startOfLine = gFalse;
|
||||
}
|
||||
} else {
|
||||
startOfLine = (*p == '\n' || *p == '\r');
|
||||
++p;
|
||||
}
|
||||
}
|
||||
} // end of pass 2
|
||||
|
||||
GBool bRoot = gFalse;
|
||||
for (int i = 0; i < streamObjNumsLen; ++i) {
|
||||
Object obj;
|
||||
fetch(streamObjNums[i], entries[streamObjNums[i]].gen, &obj);
|
||||
if (obj.isStream()) {
|
||||
Dict *dict = obj.streamGetDict();
|
||||
Object type;
|
||||
dict->lookup("Type", &type);
|
||||
if (type.isName("XRef") && !bRoot) {
|
||||
bRoot = saveTrailerDict(dict, gTrue);
|
||||
} else if (type.isName("ObjStm")) {
|
||||
constructObjectStreamEntries(&obj, streamObjNums[i]);
|
||||
}
|
||||
type.free();
|
||||
}
|
||||
obj.free();
|
||||
}
|
||||
gfree(streamObjNums);
|
||||
|
||||
if (rootNum < 0) {
|
||||
error(errSyntaxError, -1, "Couldn't find trailer dictionary");
|
||||
return gFalse;
|
||||
}
|
||||
return gTrue;
|
||||
}
|
||||
|
||||
// Look for an object header ("nnn ggg obj") at [p]. The first
|
||||
// character at *[p] is a digit. [pos] is the position of *[p].
|
||||
char *XRef::constructObjectEntry(char *p, GFileOffset pos, int *objNum) {
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
#define XREF_H
|
||||
|
||||
#include <aconf.h>
|
||||
#include <vector>
|
||||
|
||||
#ifdef USE_GCC_PRAGMAS
|
||||
#pragma interface
|
||||
@ -50,6 +51,21 @@ struct XRefCacheEntry {
|
||||
Object obj;
|
||||
};
|
||||
|
||||
struct XRefTempEntry {
|
||||
GFileOffset offset;
|
||||
int gen;
|
||||
GBool used;
|
||||
};
|
||||
|
||||
struct XRefTrailerCandidate {
|
||||
GFileOffset trailerPos;
|
||||
GFileOffset sectionStart;
|
||||
GFileOffset sectionEnd;
|
||||
GFileOffset rootObjPos; // Root object offset at the time the trailer was encountered
|
||||
int rootNum;
|
||||
int rootGen;
|
||||
};
|
||||
|
||||
#define xrefCacheSize 16
|
||||
|
||||
#define objStrCacheSize 128
|
||||
@ -179,6 +195,9 @@ private:
|
||||
void constructObjectStreamEntries(Object *objStr, int objStrObjNum);
|
||||
GBool constructXRefEntry(int num, int gen, GFileOffset pos,
|
||||
XRefEntryType type);
|
||||
GBool constructXRefRepair();
|
||||
GFileOffset findValidCutoff(XRefTempEntry *tempEntries, int tempSize, std::vector<XRefTrailerCandidate> &candidates);
|
||||
static GBool quickCheckCatalog(BaseStream *str, GFileOffset pos);
|
||||
GBool getObjectStreamObject(int objStrNum, int objIdx,
|
||||
int objNum, Object *obj);
|
||||
ObjectStream *getObjectStream(int objStrNum);
|
||||
|
||||
Reference in New Issue
Block a user