Files
Yajbir Singh f1b860b25c
Some checks failed
check / markdownlint (push) Has been cancelled
check / spellchecker (push) Has been cancelled
updated
2025-12-11 19:03:17 +05:30

1373 lines
35 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* (c) Copyright Ascensio System SIA 2010-2023
*
* This program is a free software product. You can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License (AGPL)
* version 3 as published by the Free Software Foundation. In accordance with
* Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
* that Ascensio System SIA expressly excludes the warranty of non-infringement
* of any third-party rights.
*
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
* details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
*
* You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish
* street, Riga, Latvia, EU, LV-1050.
*
* The interactive user interfaces in modified source and object code versions
* of the Program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU AGPL version 3.
*
* Pursuant to Section 7(b) of the License you must retain the original Product
* logo when distributing the program. Pursuant to Section 7(e) we decline to
* grant you any rights under trademark law for use of our trademarks.
*
* All the Product's GUI elements, including illustrations and icon sets, as
* well as technical writing content are licensed under the terms of the
* Creative Commons Attribution-ShareAlike 4.0 International. See the License
* terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
*
*/
#ifndef DOC_BUILDER_PRIVATE
#define DOC_BUILDER_PRIVATE
#include "./editors.h"
#include "docbuilder.h"
#include "doctrenderer.h"
#include <iostream>
#include <list>
#include "../../Common/OfficeFileFormats.h"
#include "../../Common/OfficeFileFormatChecker.h"
#include "js_internal/js_base.h"
#include "embed/NativeBuilderEmbed.h"
#include "embed/NativeBuilderDocumentEmbed.h"
#include "embed/NativeControlEmbed.h"
#include "embed/GraphicsEmbed.h"
#include "embed/Default.h"
#ifdef LINUX
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
#endif
#ifdef BUIDLER_OPEN_DOWNLOAD_ENABLED
#include "../../Common/Network/FileTransporter/include/FileTransporter.h"
#endif
#include "../fontengine/ApplicationFontsWorker.h"
#include "../../OfficeUtils/src/OfficeUtils.h"
#include "../common/ProcessEnv.h"
#include "docbuilder_addon.h"
#ifdef CreateFile
#undef CreateFile
#endif
namespace NSDoctRenderer
{
static int GetFormatByTexExtention(const std::wstring& sExt)
{
int nFormat = AVS_OFFICESTUDIO_FILE_DOCUMENT_DOCX;
if (L"docx" == sExt)
nFormat = AVS_OFFICESTUDIO_FILE_DOCUMENT_DOCX;
else if (L"doc" == sExt)
nFormat = AVS_OFFICESTUDIO_FILE_DOCUMENT_DOC;
else if (L"odt" == sExt)
nFormat = AVS_OFFICESTUDIO_FILE_DOCUMENT_ODT;
else if (L"rtf" == sExt)
nFormat = AVS_OFFICESTUDIO_FILE_DOCUMENT_RTF;
else if (L"txt" == sExt)
nFormat = AVS_OFFICESTUDIO_FILE_DOCUMENT_TXT;
else if (L"pptx" == sExt)
nFormat = AVS_OFFICESTUDIO_FILE_PRESENTATION_PPTX;
else if (L"odp" == sExt)
nFormat = AVS_OFFICESTUDIO_FILE_PRESENTATION_ODP;
else if (L"xlsx" == sExt)
nFormat = AVS_OFFICESTUDIO_FILE_SPREADSHEET_XLSX;
else if (L"xls" == sExt)
nFormat = AVS_OFFICESTUDIO_FILE_SPREADSHEET_XLS;
else if (L"ods" == sExt)
nFormat = AVS_OFFICESTUDIO_FILE_SPREADSHEET_ODS;
else if (L"csv" == sExt)
nFormat = AVS_OFFICESTUDIO_FILE_SPREADSHEET_CSV;
else if (L"pdf" == sExt)
nFormat = AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_PDF;
else if (L"image" == sExt)
nFormat = AVS_OFFICESTUDIO_FILE_IMAGE_PNG;
else if (L"jpg" == sExt)
nFormat = AVS_OFFICESTUDIO_FILE_IMAGE_JPG;
else if (L"png" == sExt)
nFormat = AVS_OFFICESTUDIO_FILE_IMAGE_PNG;
else if (L"vsdx" == sExt)
nFormat = AVS_OFFICESTUDIO_FILE_DRAW_VSDX;
else if (L"docxf" == sExt)
nFormat = AVS_OFFICESTUDIO_FILE_DOCUMENT_DOCXF;
else if (L"oform" == sExt)
nFormat = AVS_OFFICESTUDIO_FILE_DOCUMENT_OFORM;
else if (L"html" == sExt)
nFormat = AVS_OFFICESTUDIO_FILE_DOCUMENT_HTML_IN_CONTAINER;
else if (L"form" == sExt)
nFormat = AVS_OFFICESTUDIO_FILE_DOCUMENT_OFORM_PDF;
return nFormat;
}
}
namespace NSDoctRenderer
{
class CString_Private
{
public:
wchar_t* m_data;
public:
CString_Private()
{
m_data = NULL;
}
~CString_Private()
{
delete[] m_data;
}
void Attach(wchar_t* data)
{
delete[] m_data;
m_data = data;
}
void Copy(CString_Private* copy)
{
if (copy->m_data)
{
delete[] copy->m_data;
copy->m_data = NULL;
}
if (m_data == NULL)
return;
size_t len = wcslen(m_data);
copy->m_data = new wchar_t[len + 1];
memcpy(copy->m_data, m_data, (len + 1) * sizeof(wchar_t));
}
void MakeEmpty()
{
delete[] m_data;
m_data = new wchar_t[1];
m_data[0] = '\0';
}
};
}
class CJSContextData;
namespace NSDoctRenderer
{
class CDocBuilderContextScopeWrap
{
public:
JSSmart<CJSContextScope> m_scope;
public:
CDocBuilderContextScopeWrap() : m_scope() {}
~CDocBuilderContextScopeWrap() { Close(); }
void Close() { m_scope.Release(); }
};
class CDocBuilderContextScope_Private
{
public:
JSSmart<CDocBuilderContextScopeWrap> m_scope_wrap;
CJSContextData* m_context_data;
public:
CDocBuilderContextScope_Private() : m_scope_wrap() { m_context_data = NULL; }
~CDocBuilderContextScope_Private() {}
};
class CDocBuilderContext_Private
{
public:
JSSmart<CJSContext> m_context;
CJSContextData* m_context_data;
CDocBuilderContext_Private() : m_context() { m_context_data = NULL; }
~CDocBuilderContext_Private() { m_context.Release(); }
};
}
namespace NSDoctRenderer
{
class CDocBuilderValue_Private
{
public:
class CParentValueInfo
{
public:
JSSmart<CJSValue> m_parent;
int m_parent_index;
std::string m_parent_prop_name;
public:
CParentValueInfo() : m_parent(), m_parent_index(-1), m_parent_prop_name("")
{
}
};
public:
JSSmart<CJSContext> m_context;
JSSmart<CJSValue> m_value;
// for operator [index]/["name"] and setter without references
JSSmart<CParentValueInfo> m_parent;
enum PrimitiveType
{
ptUndefined = 0,
ptNull = 1,
ptBool = 2,
ptInt = 3,
ptUInt = 4,
ptDouble = 5,
ptString = 6
};
union PrimitiveValue
{
bool bValue;
int nValue;
unsigned int unValue;
double dValue;
wchar_t* sValue;
};
PrimitiveType m_nativeType;
PrimitiveValue m_nativeValue;
public:
CDocBuilderValue_Private() : m_context(NULL)
{
m_nativeType = ptUndefined;
}
~CDocBuilderValue_Private()
{
}
void Clear()
{
m_value.Release();
ClearNative();
}
// native
void CreateUndefined()
{
m_nativeType = ptUndefined;
}
void CreateNull()
{
m_nativeType = ptNull;
}
void CreateBool(const bool& value)
{
m_nativeType = ptBool;
m_nativeValue.bValue = value;
}
void CreateInt(const int& value)
{
m_nativeType = ptInt;
m_nativeValue.nValue = value;
}
void CreateUInt(const unsigned int& value)
{
m_nativeType = ptUInt;
m_nativeValue.unValue = value;
}
void CreateDouble(const double& value)
{
m_nativeType = ptDouble;
m_nativeValue.dValue = value;
}
void CreateString(const wchar_t*& value)
{
size_t len = wcslen(value) + 1;
m_nativeType = ptString;
m_nativeValue.sValue = new wchar_t[len];
memcpy(m_nativeValue.sValue, value, len * sizeof(wchar_t));
}
void CreateString(const char*& value)
{
std::wstring sValue = NSFile::CUtf8Converter::GetUnicodeStringFromUTF8((BYTE*)value, strlen(value));
const wchar_t* strTmp = sValue.c_str();
CreateString(strTmp);
}
void ClearNative()
{
if (m_nativeType == ptString)
{
delete [] m_nativeValue.sValue;
}
m_nativeType = ptUndefined;
}
void CheckNative()
{
if (m_value.is_init())
return;
switch (m_nativeType)
{
case ptUndefined:
{
m_value = NSJSBase::CJSContext::createUndefined();
break;
}
case ptNull:
{
m_value = NSJSBase::CJSContext::createNull();
break;
}
case ptBool:
{
m_value = NSJSBase::CJSContext::createBool(m_nativeValue.bValue);
break;
}
case ptInt:
{
m_value = NSJSBase::CJSContext::createInt(m_nativeValue.nValue);
break;
}
case ptUInt:
{
m_value = NSJSBase::CJSContext::createUInt(m_nativeValue.unValue);
break;
}
case ptDouble:
{
m_value = NSJSBase::CJSContext::createDouble(m_nativeValue.dValue);
break;
}
case ptString:
{
m_value = NSJSBase::CJSContext::createString(m_nativeValue.sValue);
break;
}
default:
break;
}
ClearNative();
}
};
}
class CJSContextData
{
private:
std::vector<JSSmart<NSDoctRenderer::CDocBuilderContextScopeWrap>> m_scopes;
public:
CJSContextData() : m_scopes()
{
}
~CJSContextData()
{
Clear();
}
void Clear()
{
for (std::vector<JSSmart<NSDoctRenderer::CDocBuilderContextScopeWrap>>::iterator iter = m_scopes.begin(); iter != m_scopes.end(); iter++)
{
(*iter)->Close();
}
m_scopes.clear();
}
void RemoveScope(JSSmart<NSDoctRenderer::CDocBuilderContextScopeWrap>& scope)
{
if (!scope.is_init())
return;
for (std::vector<JSSmart<NSDoctRenderer::CDocBuilderContextScopeWrap>>::iterator iter = m_scopes.begin(); iter != m_scopes.end(); iter++)
{
if (scope.GetPointer() == iter->GetPointer())
{
m_scopes.erase(iter);
return;
}
}
}
void AddScope(JSSmart<NSDoctRenderer::CDocBuilderContextScopeWrap>& scope)
{
m_scopes.push_back(scope);
}
void AddNewScope(NSDoctRenderer::CDocBuilderContextScopeWrap* scope)
{
m_scopes.emplace_back(scope);
}
};
class CV8RealTimeWorker
{
public:
JSSmart<CJSContext> m_context;
int m_nFileType;
std::string m_sUtf8ArgumentJSON;
std::string m_sGlobalVariable;
std::string m_sJSCodeStart;
CJSContextData m_oContextData;
public:
CV8RealTimeWorker(NSDoctRenderer::CDocBuilder* pBuilder, const NSDoctRenderer::DoctRendererEditorType& type, NSDoctRenderer::CDoctRendererConfig* config);
~CV8RealTimeWorker();
public:
static void _LOGGING_ERROR_(const std::wstring& strType, const std::wstring& strError);
bool ExecuteCommand(const std::wstring& command, NSDoctRenderer::CDocBuilderValue* retValue = NULL, const bool& isEnterContext = true);
std::string GetGlobalVariable();
std::wstring GetJSVariable(std::wstring sParam);
bool OpenFile(const std::wstring& sBasePath, const std::wstring& path, const NSDoctRenderer::DoctRendererEditorType& editorType, NSDoctRenderer::CDoctRendererConfig* config, CV8Params* pParams = NULL);
bool SaveFileWithChanges(int type, const std::wstring& _path, const std::wstring& sJsonParams = L"", const bool& isEnterContext = true);
bool InitVariables();
bool NewSimpleJSInstance();
bool IsSimpleJSInstance();
};
namespace NSDoctRenderer
{
class CDocBuilder_Private : public CDoctRendererConfig
{
public:
std::wstring m_strEditorType;
std::wstring m_strFilePath;
std::wstring m_sTmpFolder;
std::wstring m_sFileDir;
int m_nFileType;
std::wstring m_sCommandsBeforeContextCreated;
std::wstring m_sX2tPath;
CV8RealTimeWorker* m_pWorker;
CAdditionalData* m_pAdditionalData;
CDocBuilderParams m_oParams;
bool m_bIsInit;
bool m_bIsServerSafeVersion;
std::wstring m_sFolderForSaveOnlyUseNames;
std::string m_sGlobalVariable;
bool m_bIsGlobalVariableUse;
NSDoctRenderer::CDocBuilder* m_pParent;
bool m_bIsOpenedFromSimpleJS;
static std::wstring m_sExternalDirectory;
public:
CDocBuilder_Private() : CDoctRendererConfig(), m_sTmpFolder(NSFile::CFileBinary::GetTempPath()), m_nFileType(-1),
m_pWorker(NULL), m_pAdditionalData(NULL), m_bIsInit(false), m_bIsServerSafeVersion(false),
m_sGlobalVariable(""), m_bIsGlobalVariableUse(false), m_pParent(NULL), m_sCommandsBeforeContextCreated(L""), m_bIsOpenedFromSimpleJS(false)
{
}
void Init()
{
if (m_bIsInit)
return;
std::wstring sWorkDir = m_oParams.m_sWorkDir;
if (sWorkDir.empty() || !NSDirectory::Exists(sWorkDir))
{
sWorkDir = NSFile::GetProcessDirectory();
if (!m_oParams.m_sWorkDir.empty())
{
std::wstring sCheck = sWorkDir;
if (0 != m_oParams.m_sWorkDir.find('/'))
sCheck += L"/";
sCheck += m_oParams.m_sWorkDir;
if (NSDirectory::Exists(sCheck))
sWorkDir = sCheck;
}
}
else
{
std::wstring sNatural = NSFile::GetProcessDirectory();
if (0 != sWorkDir.find('/'))
sNatural += L"/";
sNatural += sWorkDir;
if (NSDirectory::Exists(sNatural))
sWorkDir = sNatural;
}
m_sX2tPath = sWorkDir;
CDoctRendererConfig::Parse(sWorkDir);
CheckFonts(m_oParams.m_bCheckFonts);
m_bIsInit = true;
}
~CDocBuilder_Private()
{
CloseFile();
RELEASEOBJECT(m_pAdditionalData);
}
void CheckFonts(bool bIsCheckFonts)
{
std::wstring sDirectory = NSFile::GetDirectoryName(m_strAllFonts);
std::wstring strFontsSelectionBin = sDirectory + L"/font_selection.bin";
if (!bIsCheckFonts && NSFile::CFileBinary::Exists(strFontsSelectionBin))
return;
CApplicationFontsWorker oWorker;
oWorker.m_bIsUseSystemFonts = m_oParams.m_bIsSystemFonts;
oWorker.m_arAdditionalFolders = m_oParams.m_arFontDirs;
oWorker.m_arAdditionalFolders.push_back(NSFile::GetProcessDirectory() + L"/fonts");
oWorker.m_bIsNeedThumbnails = false;
oWorker.m_sDirectory = sDirectory;
// это не рабочая папка, где только шрифты
oWorker.m_bIsCleanDirectory = false;
NSFonts::IApplicationFonts* pFonts = oWorker.Check();
if(pFonts)
pFonts->Release();
}
void CheckFileDir()
{
m_sFileDir = NSFile::CFileBinary::CreateTempFileWithUniqueName(m_sTmpFolder, L"DE_");
if (NSFile::CFileBinary::Exists(m_sFileDir))
NSFile::CFileBinary::Remove(m_sFileDir);
NSStringUtils::string_replace(m_sFileDir, L"\\", L"/");
std::wstring::size_type nPosPoint = m_sFileDir.rfind('.');
if (nPosPoint != std::wstring::npos && nPosPoint > m_sTmpFolder.length())
{
m_sFileDir = m_sFileDir.substr(0, nPosPoint);
}
m_nFileType = -1;
NSDirectory::CreateDirectory(m_sFileDir);
}
bool CreateFile(int type)
{
Init();
#if 1
CheckFileDir();
std::wstring sEmptyPath = m_sX2tPath + L"/empty/";
#if 0
if (type & AVS_OFFICESTUDIO_FILE_DOCUMENT)
{
sEmptyPath = sEmptyPath + L"docx.bin";
m_nFileType = 0;
}
else if (type & AVS_OFFICESTUDIO_FILE_PRESENTATION)
{
sEmptyPath = sEmptyPath + L"pptx.bin";
m_nFileType = 1;
}
else if (type & AVS_OFFICESTUDIO_FILE_SPREADSHEET)
{
sEmptyPath = sEmptyPath + L"xlsx.bin";
m_nFileType = 2;
}
else if (type & AVS_OFFICESTUDIO_FILE_DRAW)
{
sEmptyPath = sEmptyPath + L"vsdx.bin";
m_nFileType = 7;
}
else
return false;
bool bRet = NSFile::CFileBinary::Copy(sEmptyPath, m_sFileDir + L"/Editor.bin");
if (bRet)
{
NSDirectory::CreateDirectory(m_sFileDir + L"/media");
NSDirectory::CreateDirectory(m_sFileDir + L"/changes");
}
#endif
if (type & AVS_OFFICESTUDIO_FILE_DOCUMENT)
{
if (type == AVS_OFFICESTUDIO_FILE_DOCUMENT_OFORM_PDF)
sEmptyPath = sEmptyPath + L"new.pdf";
else
sEmptyPath = sEmptyPath + L"new.docx";
m_nFileType = 0;
}
else if (type & AVS_OFFICESTUDIO_FILE_PRESENTATION)
{
sEmptyPath = sEmptyPath + L"new.pptx";
m_nFileType = 1;
}
else if (type & AVS_OFFICESTUDIO_FILE_SPREADSHEET)
{
sEmptyPath = sEmptyPath + L"new.xlsx";
m_nFileType = 2;
}
else if (type & AVS_OFFICESTUDIO_FILE_DRAW)
{
sEmptyPath = sEmptyPath + L"new.vsdx";
m_nFileType = 7;
}
else
return false;
bool bRet = (0 == ConvertToInternalFormat(m_sFileDir, sEmptyPath, L"")) ? true : false;
if (bRet)
{
NSDirectory::CreateDirectory(m_sFileDir + L"/media");
NSDirectory::CreateDirectory(m_sFileDir + L"/changes");
if (m_pWorker && m_pWorker->IsSimpleJSInstance() && !m_bIsOpenedFromSimpleJS)
{
RELEASEOBJECT(m_pWorker);
CheckWorker();
}
return bRet;
}
return bRet;
#else
std::wstring sPath = m_sX2tPath + L"/empty/new.";
if (type & AVS_OFFICESTUDIO_FILE_DOCUMENT)
sPath += L"docx";
else if (type & AVS_OFFICESTUDIO_FILE_PRESENTATION)
sPath += L"pptx";
else if (type & AVS_OFFICESTUDIO_FILE_SPREADSHEET)
sPath += L"xlsx";
else if (type & AVS_OFFICESTUDIO_FILE_DRAW)
sPath += L"vsdx";
return this->OpenFile(sPath, L"");
#endif
}
void MoveFileOpen(const std::wstring& from, const std::wstring& to)
{
#ifdef BUIDLER_OPEN_DOWNLOAD_ENABLED
int n1 = (int)from.find (L"www");
int n2 = (int)from.find (L"http");
int n3 = (int)from.find (L"ftp");
int n4 = (int)from.find (L"https");
//если nI сранивать не с 0, то будут проблемы
//потому что в инсталяции мы кладем файлы в /var/www...
if (0 == n1 || 0 == n2 || 0 == n3 || 0 == n4)
{
NSNetwork::NSFileTransport::CFileDownloader oDownloader(from, false);
oDownloader.SetFilePath(to);
if (oDownloader.DownloadSync())
return;
}
#endif
#ifdef BUIDLER_OPEN_BASE64_ENABLED
if (0 == from.find(L"data:"))
{
std::wstring::size_type findBase64 = from.find(L"base64,");
if (std::wstring::npos != findBase64)
{
int nStartBase64 = (int)findBase64;
if (50 > nStartBase64)
{
nStartBase64 += 7;
const wchar_t* pStart = from.c_str() + nStartBase64;
int nDataLen = (int)from.length() - nStartBase64;
std::string sBase64 = NSFile::CUtf8Converter::GetUtf8StringFromUnicode2(pStart, (LONG)nDataLen, false);
BYTE* pDataDst = NULL;
int nDataDstLen = 0;
if (NSFile::CBase64Converter::Decode(sBase64.c_str(), (int)sBase64.length(), pDataDst, nDataLen))
{
NSFile::CFileBinary oFileDst;
if (oFileDst.CreateFileW(to))
{
oFileDst.WriteFile(pDataDst, (DWORD)nDataDstLen);
oFileDst.CloseFile();
RELEASEARRAYOBJECTS(pDataDst);
return;
}
RELEASEARRAYOBJECTS(pDataDst);
}
}
}
}
#endif
// не открываем локальные файлы в серверной версии.
if (m_bIsServerSafeVersion)
return;
NSFile::CFileBinary::Copy(from, to);
}
int ConvertToInternalFormat(const std::wstring& sFolder, const std::wstring& sFile, const std::wstring& sParams)
{
NSStringUtils::CStringBuilder oBuilder;
oBuilder.WriteString(L"<?xml version=\"1.0\" encoding=\"utf-8\"?><TaskQueueDataConvert><m_sFileFrom>");
oBuilder.WriteEncodeXmlString(sFile);
oBuilder.WriteString(L"</m_sFileFrom><m_sFileTo>");
oBuilder.WriteEncodeXmlString(sFolder);
oBuilder.WriteString(L"/Editor.bin</m_sFileTo><m_nFormatTo>8192</m_nFormatTo>");
oBuilder.WriteString(L"<m_sFontDir>");
oBuilder.WriteEncodeXmlString(NSFile::GetDirectoryName(m_strAllFonts));
oBuilder.WriteString(L"</m_sFontDir>");
oBuilder.WriteString(L"<m_sAllFontsPath>");
oBuilder.WriteEncodeXmlString(m_strAllFonts);
oBuilder.WriteString(L"</m_sAllFontsPath>");
oBuilder.WriteString(L"<m_bIsNoBase64>true</m_bIsNoBase64>");
oBuilder.WriteString(L"<m_sThemeDir>./sdkjs/slide/themes</m_sThemeDir><m_bDontSaveAdditional>true</m_bDontSaveAdditional>");
oBuilder.WriteString(sParams);
std::string sOptions = NSProcessEnv::Save();
if (!sOptions.empty())
oBuilder.WriteString(UTF8_TO_U(sOptions));
oBuilder.WriteString(L"</TaskQueueDataConvert>");
std::wstring sXmlConvert = oBuilder.GetData();
std::wstring sConverterExe = m_sX2tPath + L"/x2t";
int nReturnCode = 0;
std::wstring sTempFileForParams = sFolder + L"/params_from.xml";
NSFile::CFileBinary::SaveToFile(sTempFileForParams, sXmlConvert, true);
#ifdef WIN32
std::wstring sApp = L"x2t32 ";
if (NSFile::CFileBinary::Exists(sConverterExe + L".exe"))
{
sApp = L"x2t ";
sConverterExe += L".exe";
}
else
sConverterExe += L"32.exe";
STARTUPINFO sturtupinfo;
ZeroMemory(&sturtupinfo,sizeof(STARTUPINFO));
sturtupinfo.cb = sizeof(STARTUPINFO);
sApp += (L"\"" + sTempFileForParams + L"\"");
wchar_t* pCommandLine = NULL;
if (true)
{
pCommandLine = new wchar_t[sApp.length() + 1];
memcpy(pCommandLine, sApp.c_str(), sApp.length() * sizeof(wchar_t));
pCommandLine[sApp.length()] = (wchar_t)'\0';
}
PROCESS_INFORMATION processinfo;
ZeroMemory(&processinfo,sizeof(PROCESS_INFORMATION));
BOOL bResult = CreateProcessW(sConverterExe.c_str(), pCommandLine,
NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &sturtupinfo, &processinfo);
::WaitForSingleObject(processinfo.hProcess, INFINITE);
RELEASEARRAYOBJECTS(pCommandLine);
//get exit code
DWORD dwExitCode = 0;
if (GetExitCodeProcess(processinfo.hProcess, &dwExitCode))
{
nReturnCode = (int)dwExitCode;
}
CloseHandle(processinfo.hProcess);
CloseHandle(processinfo.hThread);
#endif
#ifdef LINUX
pid_t pid = fork(); // create child process
int status;
std::string sProgramm = U_TO_UTF8(sConverterExe);
std::string sXmlA = U_TO_UTF8(sTempFileForParams);
switch (pid)
{
case -1: // error
break;
case 0: // child process
{
std::string sLibraryDir = sProgramm;
std::string sPATH = sProgramm;
if (std::string::npos != sProgramm.find_last_of('/'))
{
sLibraryDir = "LD_LIBRARY_PATH=" + sProgramm.substr(0, sProgramm.find_last_of('/'));
sPATH = "PATH=" + sProgramm.substr(0, sProgramm.find_last_of('/'));
}
#ifdef _MAC
sLibraryDir = "DY" + sLibraryDir;
#endif
const char* nargs[3];
nargs[0] = sProgramm.c_str();
nargs[1] = sXmlA.c_str();
nargs[2] = NULL;
#ifndef _MAC
const char* nenv[2];
nenv[0] = sLibraryDir.c_str();
nenv[1] = NULL;
#else
const char* nenv[3];
nenv[0] = sLibraryDir.c_str();
nenv[1] = sPATH.c_str();
nenv[2] = NULL;
#endif
execve(sProgramm.c_str(),
(char * const *)nargs,
(char * const *)nenv);
exit(EXIT_SUCCESS);
break;
}
default: // parent process, pid now contains the child pid
while (-1 == waitpid(pid, &status, 0)); // wait for child to complete
if (WIFEXITED(status))
{
nReturnCode = WEXITSTATUS(status);
}
break;
}
#endif
NSFile::CFileBinary::Remove(sTempFileForParams);
return nReturnCode;
}
std::wstring GetFileCopyExt(const std::wstring& path)
{
std::wstring sExtCopy = NSFile::GetFileExtention(path);
if (true)
{
// для файлов по ссылке - расширение может быть плохим.
const wchar_t* sExtCopyPtr = sExtCopy.c_str();
int nExtCopyLen = sExtCopy.length();
int nValidIndex = 0;
while (nValidIndex < nExtCopyLen)
{
wchar_t c = sExtCopyPtr[nValidIndex];
if ((c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') ||
(c >= '0' && c <= '9'))
{
++nValidIndex;
}
else
break;
}
if (nValidIndex > 0)
{
sExtCopy = sExtCopy.substr(0, nValidIndex);
}
else
{
sExtCopy = L"tmp";
}
}
return sExtCopy;
}
int OpenFile(const std::wstring& path, const std::wstring& params)
{
Init();
LOGGER_SPEED_START();
CheckFileDir();
NSDirectory::CreateDirectory(m_sFileDir + L"/changes");
std::wstring sExtCopy = GetFileCopyExt(path);
std::wstring sFileCopy = m_sFileDir + L"/origin." + sExtCopy;
MoveFileOpen(path, sFileCopy);
COfficeFileFormatChecker oChecker;
if (!oChecker.isOfficeFile(sFileCopy))
return 1;
if (oChecker.nFileType & AVS_OFFICESTUDIO_FILE_DOCUMENT)
m_nFileType = 0;
if (oChecker.nFileType & AVS_OFFICESTUDIO_FILE_PRESENTATION)
m_nFileType = 1;
if (oChecker.nFileType & AVS_OFFICESTUDIO_FILE_SPREADSHEET)
m_nFileType = 2;
if (oChecker.nFileType & AVS_OFFICESTUDIO_FILE_DRAW)
m_nFileType = 7;
int nReturnCode = ConvertToInternalFormat(m_sFileDir, sFileCopy, params);
LOGGER_SPEED_LAP("open_convert");
if (0 == nReturnCode)
{
if (m_pWorker && m_pWorker->IsSimpleJSInstance() && !m_bIsOpenedFromSimpleJS)
{
RELEASEOBJECT(m_pWorker);
CheckWorker();
}
return 0;
}
NSDirectory::DeleteDirectory(m_sFileDir);
m_sFileDir = L"";
m_nFileType = -1;
std::wstring sErrorLog = L"open file error (" + std::to_wstring(nReturnCode) + L")";
CV8RealTimeWorker::_LOGGING_ERROR_(L"error: ", sErrorLog);
return nReturnCode;
}
void CloseFile(bool bIsDestroyJS = true)
{
Init();
if (NSDirectory::Exists(m_sFileDir))
NSDirectory::DeleteDirectory(m_sFileDir);
m_sFileDir = L"";
m_nFileType = -1;
if (m_pWorker)
m_sGlobalVariable = m_pWorker->GetGlobalVariable();
if (bIsDestroyJS)
RELEASEOBJECT(m_pWorker);
}
std::wstring GetSaveFilePath(const std::wstring& path)
{
std::wstring _path = path;
if (!m_sFolderForSaveOnlyUseNames.empty())
{
_path = m_sFolderForSaveOnlyUseNames;
wchar_t last = m_sFolderForSaveOnlyUseNames.c_str()[m_sFolderForSaveOnlyUseNames.length() - 1];
if (last != '/' && last != '\\')
_path += L"/";
_path += NSFile::GetFileName(path);
}
std::wstring sDstFileDir = NSFile::GetDirectoryName(_path);
if ((sDstFileDir != _path) && !NSDirectory::Exists(sDstFileDir))
NSDirectory::CreateDirectories(sDstFileDir);
return _path;
}
int SaveFile(const int& type, const std::wstring& path, const wchar_t* params = NULL, const bool& isEnterContext = true)
{
Init();
CDocBuilderAddon oSaveAddon(m_sX2tPath);
int nPreSaveError = oSaveAddon.GetX2tPreSaveError(m_pParent, m_nFileType);
if (0 != nPreSaveError)
return nPreSaveError;
if (-1 == m_nFileType)
{
CV8RealTimeWorker::_LOGGING_ERROR_(L"error (save)", L"file not opened!");
return 1;
}
LOGGER_SPEED_START();
std::wstring sConvertionParams = L"";
if (NULL != params)
{
sConvertionParams = std::wstring(params);
NSStringUtils::string_replace(sConvertionParams, L"\'", L"&quot;");
}
std::wstring sFileBin = L"/Editor.bin";
if (!m_oParams.m_bSaveWithDoctrendererMode && m_pWorker)
{
std::wstring sJsonParams = sConvertionParams;
if (!sJsonParams.empty())
{
std::wstring::size_type pos1 = sJsonParams.find(L">");
std::wstring::size_type pos2 = sJsonParams.find(L"</");
if (std::wstring::npos != pos1 && std::wstring::npos != pos2)
{
sJsonParams = sJsonParams.substr(pos1 + 1, pos2 - pos1 - 1);
NSStringUtils::string_replace(sJsonParams, L"&quot;", L"\"");
if (0 != sJsonParams.find(L"{"))
sJsonParams = L"";
}
else
{
sJsonParams = L"";
}
}
this->m_pWorker->SaveFileWithChanges(type, m_sFileDir + L"/Editor2.bin", sJsonParams, isEnterContext);
sFileBin = L"/Editor2.bin";
}
NSStringUtils::CStringBuilder oBuilder;
std::wstring _path = GetSaveFilePath(path);
oBuilder.WriteString(L"<?xml version=\"1.0\" encoding=\"utf-8\"?><TaskQueueDataConvert><m_sFileFrom>");
oBuilder.WriteEncodeXmlString(m_sFileDir);
oBuilder.WriteString(sFileBin + L"</m_sFileFrom><m_sFileTo>");
oBuilder.WriteEncodeXmlString(_path);
oBuilder.WriteString(L"</m_sFileTo><m_nFormatTo>");
oBuilder.WriteString(std::to_wstring(type));
oBuilder.WriteString(L"</m_nFormatTo><m_sThemeDir>");
oBuilder.WriteEncodeXmlString(L"./sdkjs/slide/themes");
if (!m_oParams.m_bSaveWithDoctrendererMode)
oBuilder.WriteString(L"</m_sThemeDir><m_bDontSaveAdditional>true</m_bDontSaveAdditional>");
else
oBuilder.WriteString(L"</m_sThemeDir><m_bFromChanges>true</m_bFromChanges><m_bDontSaveAdditional>true</m_bDontSaveAdditional>");
oBuilder.WriteString(L"<m_nCsvTxtEncoding>46</m_nCsvTxtEncoding><m_nCsvDelimiter>4</m_nCsvDelimiter>");
oBuilder.WriteString(L"<m_sFontDir>");
oBuilder.WriteEncodeXmlString(NSFile::GetDirectoryName(m_strAllFonts));
oBuilder.WriteString(L"</m_sFontDir>");
oBuilder.WriteString(L"<m_sAllFontsPath>");
oBuilder.WriteEncodeXmlString(m_strAllFonts);
oBuilder.WriteString(L"</m_sAllFontsPath>");
if (!sConvertionParams.empty())
{
oBuilder.WriteString(sConvertionParams);
}
std::wstring sDstTmpDir = NSDirectory::CreateDirectoryWithUniqueName(m_sFileDir);
oBuilder.WriteString(L"<m_sTempDir>");
oBuilder.WriteEncodeXmlString(sDstTmpDir);
oBuilder.WriteString(L"</m_sTempDir>");
std::string sOptions = NSProcessEnv::Save();
if (!sOptions.empty())
oBuilder.WriteString(UTF8_TO_U(sOptions));
oBuilder.WriteString(oSaveAddon.GetX2tSaveAddon(m_pParent, m_nFileType));
oBuilder.WriteString(L"</TaskQueueDataConvert>");
std::wstring sXmlConvert = oBuilder.GetData();
std::wstring sConverterExe = m_sX2tPath + L"/x2t";
int nReturnCode = 0;
std::wstring sTempFileForParams = m_sFileDir + L"/params_to.xml";
NSFile::CFileBinary::SaveToFile(sTempFileForParams, sXmlConvert, true);
#ifdef WIN32
std::wstring sApp = L"x2t32 ";
if (NSFile::CFileBinary::Exists(sConverterExe + L".exe"))
{
sApp = L"x2t ";
sConverterExe += L".exe";
}
else
sConverterExe += L"32.exe";
STARTUPINFO sturtupinfo;
ZeroMemory(&sturtupinfo,sizeof(STARTUPINFO));
sturtupinfo.cb = sizeof(STARTUPINFO);
sApp += (L"\"" + sTempFileForParams + L"\"");
wchar_t* pCommandLine = NULL;
if (true)
{
pCommandLine = new wchar_t[sApp.length() + 1];
memcpy(pCommandLine, sApp.c_str(), sApp.length() * sizeof(wchar_t));
pCommandLine[sApp.length()] = (wchar_t)'\0';
}
PROCESS_INFORMATION processinfo;
ZeroMemory(&processinfo,sizeof(PROCESS_INFORMATION));
BOOL bResult = CreateProcessW(sConverterExe.c_str(), pCommandLine,
NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &sturtupinfo, &processinfo);
::WaitForSingleObject(processinfo.hProcess, INFINITE);
RELEASEARRAYOBJECTS(pCommandLine);
//get exit code
DWORD dwExitCode = 0;
if (GetExitCodeProcess(processinfo.hProcess, &dwExitCode))
{
nReturnCode = (int)dwExitCode;
}
CloseHandle(processinfo.hProcess);
CloseHandle(processinfo.hThread);
#endif
#ifdef LINUX
pid_t pid = fork(); // create child process
int status;
std::string sProgramm = U_TO_UTF8(sConverterExe);
std::string sXmlA = U_TO_UTF8(sTempFileForParams);
switch (pid)
{
case -1: // error
break;
case 0: // child process
{
std::string sLibraryDir = sProgramm;
std::string sPATH = sProgramm;
if (std::string::npos != sProgramm.find_last_of('/'))
{
sLibraryDir = "LD_LIBRARY_PATH=" + sProgramm.substr(0, sProgramm.find_last_of('/'));
sPATH = "PATH=" + sProgramm.substr(0, sProgramm.find_last_of('/'));
}
#ifdef _MAC
sLibraryDir = "DY" + sLibraryDir;
#endif
const char* nargs[3];
nargs[0] = sProgramm.c_str();
nargs[1] = sXmlA.c_str();
nargs[2] = NULL;
#ifndef _MAC
const char* nenv[2];
nenv[0] = sLibraryDir.c_str();
nenv[1] = NULL;
#else
const char* nenv[3];
nenv[0] = sLibraryDir.c_str();
nenv[1] = sPATH.c_str();
nenv[2] = NULL;
#endif
execve(sProgramm.c_str(),
(char * const *)nargs,
(char * const *)nenv);
exit(EXIT_SUCCESS);
break;
}
default: // parent process, pid now contains the child pid
while (-1 == waitpid(pid, &status, 0)); // wait for child to complete
if (WIFEXITED(status))
{
nReturnCode = WEXITSTATUS(status);
}
break;
}
#endif
// html correct (TODO: move to x2t)
if (0 == nReturnCode && type == AVS_OFFICESTUDIO_FILE_DOCUMENT_HTML_IN_CONTAINER)
{
COfficeUtils oUtils;
if (S_OK == oUtils.IsArchive(_path))
{
std::wstring sTmpFile = sDstTmpDir + L"/tmp_html";
NSDirectory::CreateDirectory(sTmpFile);
if (S_OK == oUtils.ExtractToDirectory(_path, sTmpFile, NULL, 0))
{
std::vector<std::wstring> arFiles = NSDirectory::GetFiles(sTmpFile);
if (arFiles.size() == 1)
{
NSFile::CFileBinary::Remove(_path);
NSFile::CFileBinary::Move(arFiles[0], _path);
}
}
}
}
NSDirectory::DeleteDirectory(sDstTmpDir);
NSFile::CFileBinary::Remove(sTempFileForParams);
LOGGER_SPEED_LAP("save_convert");
if (0 == nReturnCode)
return 0;
std::wstring sErrorLog = L"save file error (" + std::to_wstring(nReturnCode) + L")";
CV8RealTimeWorker::_LOGGING_ERROR_(L"error: ", sErrorLog);
return nReturnCode;
}
bool CheckWorker()
{
if (NULL == m_pWorker)
{
NSDoctRenderer::DoctRendererEditorType editorType = GetEditorType();
m_pWorker = new CV8RealTimeWorker(m_pParent, editorType, this);
m_pWorker->m_sUtf8ArgumentJSON = m_oParams.m_sArgumentJSON;
m_pWorker->m_sGlobalVariable = m_sGlobalVariable;
m_pWorker->m_sJSCodeStart = U_TO_UTF8(m_sCommandsBeforeContextCreated);
m_pWorker->m_nFileType = m_nFileType;
if (-1 != m_nFileType)
m_sCommandsBeforeContextCreated = L"";
else
{
m_pWorker->NewSimpleJSInstance();
return true;
}
CV8Params oParams;
oParams.IsServerSaveVersion = m_bIsServerSafeVersion;
oParams.DocumentDirectory = m_sFileDir;
return m_pWorker->OpenFile(m_sX2tPath, m_sFileDir, editorType, this, &oParams);
}
return true;
}
int SaveFile(const std::wstring& ext, const std::wstring& path, const wchar_t* params = NULL)
{
int nType = GetFormatByTexExtention(ext);
return SaveFile(nType, path, params);
}
bool ExecuteCommand(const std::wstring& command, CDocBuilderValue* retValue = NULL, const bool& forceExecute = false, const bool& isEnterContext = true)
{
if (command.length() < 7 && !retValue) // minimum command (!!!)
return true;
if (m_nFileType == -1 && !forceExecute)
{
m_sCommandsBeforeContextCreated += command;
return true;
}
Init();
if (CheckWorker())
{
bool bIsOpenedFromSimpleJSOld = m_bIsOpenedFromSimpleJS;
bool bResult = m_pWorker->ExecuteCommand(command, retValue, isEnterContext);
if (!bResult && !bIsOpenedFromSimpleJSOld && m_bIsOpenedFromSimpleJS)
{
RELEASEOBJECT(m_pWorker);
CheckWorker();
return m_pWorker->ExecuteCommand(command, retValue, isEnterContext);
}
else
{
return bResult;
}
}
return false;
}
CDocBuilderContext GetContext(bool enterContext)
{
CDocBuilderContext ctx;
if (!CheckWorker())
return ctx;
ctx.m_internal->m_context = m_pWorker->m_context;
ctx.m_internal->m_context_data = &m_pWorker->m_oContextData;
if (enterContext)
{
CDocBuilderContextScopeWrap* scopeWrap = new CDocBuilderContextScopeWrap();
scopeWrap->m_scope = new CJSContextScope(m_pWorker->m_context);
m_pWorker->m_oContextData.AddNewScope(scopeWrap);
}
return ctx;
}
NSDoctRenderer::DoctRendererEditorType GetEditorType()
{
switch (m_nFileType)
{
case 0:
return NSDoctRenderer::DoctRendererEditorType::WORD;
case 1:
return NSDoctRenderer::DoctRendererEditorType::SLIDE;
case 2:
return NSDoctRenderer::DoctRendererEditorType::CELL;
case 7:
return NSDoctRenderer::DoctRendererEditorType::VISIO;
default:
break;
}
return NSDoctRenderer::DoctRendererEditorType::INVALID;
}
void WriteData(const wchar_t* path, const wchar_t* value, const bool& append)
{
std::wstring sValue(value);
std::string sValueA = U_TO_UTF8(sValue);
NSStringUtils::string_replaceA(sValueA, "%", "%%");
std::wstring _sFile(path);
std::wstring sFile = GetSaveFilePath(_sFile);
if (!append && NSFile::CFileBinary::Exists(sFile))
NSFile::CFileBinary::Remove(sFile);
NSFile::CFileBinary oFile;
FILE* pFile = oFile.OpenFileNative(sFile, append ? L"a+" : L"a");
if (pFile)
{
fprintf(pFile, sValueA.c_str());
fclose(pFile);
}
}
};
}
#endif // DOC_BUILDER_PRIVATE