Merge branch 'develop' into feature/add-xls-writing

This commit is contained in:
Viktor Andreev
2025-06-19 20:52:27 +06:00
228 changed files with 9318 additions and 3001 deletions

View File

@ -74,6 +74,7 @@ CV8RealTimeWorker::CV8RealTimeWorker(NSDoctRenderer::CDocBuilder* pBuilder, cons
global->set("native", oNativeCtrl);
CBuilderEmbed* pBuilderJSNative = static_cast<CBuilderEmbed*>(oBuilderJS->getNative());
pBuilderJSNative->SetExternalize(true);
pBuilderJSNative->m_pBuilder = pBuilder;
}
CV8RealTimeWorker::~CV8RealTimeWorker()
@ -1241,13 +1242,13 @@ namespace NSDoctRenderer
while (true)
{
while (_currentPos < _commandsLen && !(_commandsPtr[_currentPos] == '\"' && _commandsPtr[_currentPos - 1] != '\\'))
while (_currentPos < _commandsLen && !((_commandsPtr[_currentPos] == '\"' || _commandsPtr[_currentPos] == '\'') && _commandsPtr[_currentPos - 1] != '\\'))
++_currentPos;
++_currentPos;
size_t _start = _currentPos;
while (_currentPos < _commandsLen && !(_commandsPtr[_currentPos] == '\"' && _commandsPtr[_currentPos - 1] != '\\'))
while (_currentPos < _commandsLen && !((_commandsPtr[_currentPos] == '\"' || _commandsPtr[_currentPos] == '\'') && _commandsPtr[_currentPos - 1] != '\\'))
++_currentPos;
if (_currentPos > _start)

View File

@ -289,10 +289,20 @@ public:
return ((CPdfFile*)m_pFile)->SplitPages(arrPageIndex, nLength, data, size);
return NULL;
}
bool MergePages(BYTE* data, LONG size, int nMaxID, const std::string& sPrefixForm)
bool MergePages(BYTE* data, LONG size, int nMaxID, const std::string& sPrefixForm, bool bCopy = false)
{
if (m_nType == 0)
{
// Память из CDrawingFileEmbed освобождается сразу после вызова функции, поэтому копируем
if (bCopy)
{
BYTE* pCopy = (BYTE*)malloc(size);
memcpy(pCopy, data, size);
data = pCopy;
}
// Захватывает полученную память, будет освобождена либо в деструкторе MemStream, либо free в случае неудачи
return ((CPdfFile*)m_pFile)->MergePages(data, size, nMaxID, sPrefixForm);
}
return false;
}
bool UnmergePages()
@ -420,22 +430,32 @@ public:
oRenderer.SetExternalImageStorage(m_pImageStorage);
oRenderer.SetTextAssociationType(NSDocxRenderer::TextAssociationType::tatParagraphToShape);
std::vector<std::wstring> arShapes;
if (0 == mode)
arShapes = oRenderer.ScanPage(m_pFile, nPageIndex);
else
arShapes = oRenderer.ScanPagePptx(m_pFile, nPageIndex);
int nLen = (int)arShapes.size();
NSWasm::CData oRes;
oRes.SkipLen();
oRes.AddInt(nLen);
switch (mode)
{
case 0:
case 1:
{
std::vector<std::wstring> arShapes = (0 == mode) ? oRenderer.ScanPage(m_pFile, nPageIndex) : oRenderer.ScanPagePptx(m_pFile, nPageIndex);
int nLen = (int)arShapes.size();
for (int i = 0; i < nLen; ++i)
oRes.WriteString(arShapes[i]);
oRes.SkipLen();
oRes.AddInt(nLen);
oRes.WriteLen();
for (int i = 0; i < nLen; ++i)
oRes.WriteString(arShapes[i]);
oRes.WriteLen();
break;
}
case 2:
{
oRes = oRenderer.ScanPageBin(m_pFile, nPageIndex);
break;
}
default:
return NULL;
}
BYTE* res = oRes.GetBuffer();
oRes.ClearWithoutAttack();

View File

@ -195,7 +195,7 @@ JSSmart<CJSValue> CDrawingFileEmbed::MergePages(JSSmart<CJSValue> data, JSSmart<
int maxID = nMaxID->toInt32();
std::string prefix = sPrefixForm->toStringA();
CJSDataBuffer buffer = dataPtr->getData();
result = m_pFile->MergePages(buffer.Data, (LONG)buffer.Len, maxID, prefix);
result = m_pFile->MergePages(buffer.Data, (LONG)buffer.Len, maxID, prefix, true);
if (buffer.IsExternalize)
buffer.Free();
}

View File

@ -196,7 +196,9 @@ JSSmart<CJSValue> CGraphicsEmbed::create(JSSmart<CJSValue> Native, JSSmart<CJSVa
}
JSSmart<CJSValue> CGraphicsEmbed::Destroy()
{
// For save image bits, if needed.
m_pInternal->Destroy();
RELEASEOBJECT(m_pInternal);
return NULL;
}
JSSmart<CJSValue> CGraphicsEmbed::EndDraw()

View File

@ -45,7 +45,7 @@ public:
public:
CBuilderDocumentEmbed() : m_pBuilder(NULL), m_bIsValid(false) {}
~CBuilderDocumentEmbed() { if(m_pBuilder) RELEASEOBJECT(m_pBuilder); }
~CBuilderDocumentEmbed() { if(m_pBuilder && !m_isExternalize) RELEASEOBJECT(m_pBuilder); }
virtual void* getObject() { return (void*)m_pBuilder; }
NSDoctRenderer::CDocBuilder_Private* GetPrivate(NSDoctRenderer::CDocBuilder* pBuilder) { return pBuilder->GetPrivate(); }

View File

@ -88,6 +88,7 @@ JSSmart<CJSValue> CBuilderEmbed::OpenTmpFile(JSSmart<CJSValue> path, JSSmart<CJS
JSSmart<CJSObject> oBuilderTmpDoc = CJSContext::createEmbedObject("CBuilderDocumentEmbed");
CBuilderDocumentEmbed* pBuilderTmpDocNative = static_cast<CBuilderDocumentEmbed*>(oBuilderTmpDoc->getNative());
pBuilderTmpDocNative->m_pBuilder = m_pBuilder;
pBuilderTmpDocNative->SetExternalize(true);
pBuilderTmpDocNative->_OpenFile(sPath, sParams);
return oBuilderTmpDoc->toValue();
}

View File

@ -47,7 +47,7 @@ public:
NSDoctRenderer::CDocBuilder* m_pBuilder;
CBuilderEmbed() : m_pBuilder(NULL) {}
~CBuilderEmbed() { if(m_pBuilder) RELEASEOBJECT(m_pBuilder); }
~CBuilderEmbed() { if(m_pBuilder && !m_isExternalize) RELEASEOBJECT(m_pBuilder); }
virtual void* getObject() { return (void*)m_pBuilder; }
NSDoctRenderer::CDocBuilder_Private* GetPrivate() { return m_pBuilder->GetPrivate(); }

View File

@ -42,6 +42,7 @@ namespace NSGraphics
m_pRenderer = NSGraphics::Create();
m_pRenderer->SetFontManager(pManager);
RELEASEINTERFACE(pManager);
int nRasterW = (int)width_px;
int nRasterH = (int)height_px;

View File

@ -115,17 +115,16 @@ namespace NSGraphics
class CGraphics
{
public:
CGraphicsAppImage* m_pAppImage;
CGraphicsAppImage* m_pAppImage = nullptr;
CBgraFrame m_oFrame;
private:
NSGraphics::IGraphicsRenderer* m_pRenderer;
NSGraphics::IGraphicsRenderer* m_pRenderer = nullptr;
CGrState m_oGrState;
public:
CGraphics()
{
m_pAppImage = NULL;
}
~CGraphics()
{

View File

@ -31,6 +31,7 @@ namespace NSJSBase {
{
embed_native_internal = nullptr;
m_pAdapter = nullptr;
m_isExternalize = false;
}
CJSEmbedObject::~CJSEmbedObject()
@ -44,6 +45,16 @@ namespace NSJSBase {
return nullptr;
}
void CJSEmbedObject::SetExternalize(const bool& isExternalize)
{
m_isExternalize = isExternalize;
}
bool CJSEmbedObject::GetExternalize()
{
return m_isExternalize;
}
CJSEmbedObjectAdapterBase* CJSEmbedObject::getAdapter()
{
return nullptr;

View File

@ -194,10 +194,18 @@ namespace NSJSBase
*/
virtual CJSEmbedObjectAdapterBase* getAdapter();
/**
* Use the externalize flag if you are monitoring the object's destruction yourself.
*/
virtual void SetExternalize(const bool& isExternalize = true);
virtual bool GetExternalize();
protected:
CJSEmbedObjectPrivateBase* embed_native_internal;
CJSEmbedObjectAdapterBase* m_pAdapter;
bool m_isExternalize;
friend class CJSEmbedObjectPrivateBase;
friend class CJSEmbedObjectPrivate;
};

View File

@ -10,6 +10,7 @@
@protocol JSEmbedObjectProtocol
-(void*) getNative;
-(void) freeNative;
@end
#if __has_feature(objc_arc)
@ -41,6 +42,10 @@
-(void*) getNative \
{ \
return m_internal; \
} \
-(void) freeNative \
{ \
RELEASEOBJECT(m_internal); \
}
namespace NSJSBase

View File

@ -34,6 +34,7 @@ namespace NSJSBase
// embed
id CreateEmbedNativeObject(NSString* name);
void FreeNativeObject(id embedded_object);
}
namespace NSJSBase

View File

@ -232,10 +232,14 @@ namespace NSJSBase
{
[m_internal->context evaluateScript:@"function jsc_toBase64(r){for(var o=[\"A\",\"B\",\"C\",\"D\",\"E\",\"F\",\"G\",\"H\",\"I\",\"J\",\"K\",\"L\",\"M\",\"N\",\"O\",\"P\",\"Q\",\"R\",\"S\",\"T\",\"U\",\"V\",\"W\",\"X\",\"Y\",\"Z\",\"a\",\"b\",\"c\",\"d\",\"e\",\"f\",\"g\",\"h\",\"i\",\"j\",\"k\",\"l\",\"m\",\"n\",\"o\",\"p\",\"q\",\"r\",\"s\",\"t\",\"u\",\"v\",\"w\",\"x\",\"y\",\"z\",\"0\",\"1\",\"2\",\"3\",\"4\",\"5\",\"6\",\"7\",\"8\",\"9\",\"+\",\"/\"],a=r.length,f=4*(a/3>>0),n=f/76>>0,t=19,v=0,e=[],i=\"\",s=0;s<=n;s++){s==n&&(t=f%76/4>>0);for(var u=0;u<t;u++){for(var c=0,h=0;h<3;h++)c|=r[0+v++],c<<=8;i=\"\";for(var A=0;A<4;A++){i+=o[c>>>26&255],c<<=6,c&=4294967295}e.push(i)}}if(n=a%3!=0?a%3+1:0){for(c=0,h=0;h<3;h++)h<a%3&&(c|=r[0+v++]),c<<=8;i=\"\";for(A=0;A<n;A++){i+=o[c>>>26&255],c<<=6}t=0!=n?4-n:0;for(u=0;u<t;u++)i+=\"=\";e.push(i)}return e.join(\"\")}function jsc_fromBase64(r,o){for(var a,f=r.length,n=0,t=new Array(void 0===o?f:o),v=t,e=0,i=0;e<f;){for(var s=0,u=0,c=0;c<4&&!(f<=e);c++){var h=65<=(a=r.charCodeAt(e++))&&a<=90?a-65:97<=a&&a<=122?a-71:48<=a&&a<=57?a+4:43==a?62:47==a?63:-1;-1!=h?(s<<=6,s|=h,u+=6):c--}for(s<<=24-u,i=u>>>3,c=0;c<i;c++)v[n++]=(16711680&s)>>>16,s<<=8}return t}\n"];
}
// insert CreateEmbedObject() function to global object of this context
// insert embed functions to global object of this context
m_internal->context[@"CreateEmbedObject"] = ^(NSString* name) {
return CreateEmbedNativeObject(name);
};
m_internal->context[@"FreeEmbedObject"] = ^(id embedded_object) {
FreeNativeObject(embedded_object);
};
JSValue* global_js = [m_internal->context globalObject];
[global_js setValue:global_js forProperty:[[NSString alloc] initWithUTF8String:"window"]];
@ -246,6 +250,8 @@ namespace NSJSBase
{
CGlobalContext::GetInstance().UnregisterContextForId(*i);
}
// remove any exceptions pending to not prevent any JSValue deallocations
m_internal->context.exception = nil;
m_internal->context = nil;
}
@ -503,6 +509,15 @@ namespace NSJSBase
return pEmbedObj;
}
void FreeNativeObject(id embedded_object)
{
// check if the object was actually embedded and do nothing if it wasn't
if ([embedded_object conformsToProtocol:@protocol(JSEmbedObjectProtocol)])
{
[embedded_object freeNative];
}
}
JSSmart<CJSValue> CJSEmbedObjectAdapterJSC::Native2Value(JSValue* value)
{
return js_value(value);

View File

@ -214,12 +214,41 @@ namespace NSJSBase
m_internal->m_contextPersistent.Reset(isolate, v8::Context::New(isolate));
// create temporary local handle to context
m_internal->m_context = v8::Local<v8::Context>::New(isolate, m_internal->m_contextPersistent);
// insert CreateEmbedObject() function to global object of this context
// insert embed functions to global object of this context
m_internal->InsertToGlobal("CreateEmbedObject", CreateEmbedNativeObject);
m_internal->InsertToGlobal("FreeEmbedObject", FreeNativeObject);
// clear temporary local handle
m_internal->m_context.Clear();
}
}
class WeakHandleVisitor : public v8::PersistentHandleVisitor
{
private:
WeakHandleVisitor() = default;
public:
void VisitPersistentHandle(v8::Persistent<v8::Value>* value, uint16_t class_id) override
{
if (class_id == CJSEmbedObjectPrivate::kWeakHandleId)
{
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::HandleScope scope(isolate);
v8::Local<v8::Object> handle = value->Get(isolate).As<v8::Object>();
v8::Local<v8::External> field = v8::Local<v8::External>::Cast(handle->GetInternalField(0));
CJSEmbedObject* native = static_cast<CJSEmbedObject*>(field->Value());
delete native;
}
}
public:
static WeakHandleVisitor* getInstance()
{
static WeakHandleVisitor visitor;
return &visitor;
}
};
void CJSContext::Dispose()
{
#ifdef V8_INSPECTOR
@ -228,7 +257,13 @@ namespace NSJSBase
#endif
m_internal->m_contextPersistent.Reset();
m_internal->m_isolate->Dispose();
// destroy native object in the weak handles before isolate disposal
v8::Isolate* isolate = m_internal->m_isolate;
{
v8::Isolate::Scope scope(isolate);
isolate->VisitHandlesWithClassIds(WeakHandleVisitor::getInstance());
}
isolate->Dispose();
m_internal->m_isolate = NULL;
}
@ -655,4 +690,22 @@ namespace NSJSBase
NSJSBase::CJSEmbedObjectPrivate::CreateWeaker(obj);
args.GetReturnValue().Set(obj);
}
void FreeNativeObject(const v8::FunctionCallbackInfo<v8::Value>& args)
{
v8::Isolate* isolate = args.GetIsolate();
v8::HandleScope scope(isolate);
if (args.Length() != 1)
{
args.GetReturnValue().Set(v8::Undefined(isolate));
return;
}
v8::Local<v8::Object> obj = args[0].As<v8::Object>();
v8::Local<v8::External> field = v8::Local<v8::External>::Cast(obj->GetInternalField(0));
CJSEmbedObject* native = static_cast<CJSEmbedObject*>(field->Value());
delete native;
// weak persistent handle will be cleared and removed in CJSEmbedObjectPrivate destructor
}
}

View File

@ -883,6 +883,7 @@ namespace NSJSBase
// embed
void CreateEmbedNativeObject(const v8::FunctionCallbackInfo<v8::Value>& args);
void FreeNativeObject(const v8::FunctionCallbackInfo<v8::Value>& args);
class CJSEmbedObjectAdapterV8Template : public CJSEmbedObjectAdapterBase
{
@ -900,6 +901,8 @@ namespace NSJSBase
{
public:
v8::Persistent<v8::Object> handle;
// contstant id for all weak native handles
static const uint16_t kWeakHandleId = 1;
CJSEmbedObjectPrivate(v8::Local<v8::Object> obj)
{
@ -918,6 +921,8 @@ namespace NSJSBase
handle.Reset(CV8Worker::GetCurrent(), obj);
handle.SetWeak(pEmbedObject, EmbedObjectWeakCallback, v8::WeakCallbackType::kParameter);
// set class_id for being able to iterate over all these handles to destroy them on isolate disposal
handle.SetWrapperClassId(kWeakHandleId);
pEmbedObject->embed_native_internal = this;
}
@ -931,8 +936,6 @@ namespace NSJSBase
static void EmbedObjectWeakCallback(const v8::WeakCallbackInfo<CJSEmbedObject>& data)
{
v8::Isolate* isolate = data.GetIsolate();
v8::HandleScope scope(isolate);
CJSEmbedObject* wrap = data.GetParameter();
((CJSEmbedObjectPrivate*)wrap->embed_native_internal)->handle.Reset();
delete wrap;

View File

@ -1,4 +1,15 @@
#include "Embed.h"
#include <iostream>
CTestEmbed::CTestEmbed()
{
std::cout << "debug: CTestEmbed constructed" << std::endl;
}
CTestEmbed::~CTestEmbed()
{
std::cout << "debug: CTestEmbed destroyed" << std::endl;
}
#ifdef ENABLE_SUM_DEL
JSSmart<CJSValue> CTestEmbed::FunctionSum(JSSmart<CJSValue> param1, JSSmart<CJSValue> param2)

View File

@ -1,5 +1,5 @@
#ifndef _BUILD_NATIVE_HASH_EMBED_H_
#define _BUILD_NATIVE_HASH_EMBED_H_
#ifndef CTESTEMBED_H_
#define CTESTEMBED_H_
#include "js_internal/js_base.h"
@ -10,13 +10,8 @@ using namespace NSJSBase;
class CTestEmbed : public CJSEmbedObject
{
public:
CTestEmbed()
{
}
~CTestEmbed()
{
}
CTestEmbed();
~CTestEmbed();
virtual void* getObject() override { return NULL; }
@ -33,4 +28,4 @@ public:
DECLARE_EMBED_METHODS
};
#endif // _BUILD_NATIVE_HASH_EMBED_H_
#endif // CTESTEMBED_H_

View File

@ -1,278 +1,14 @@
/*
* (c) Copyright Ascensio System SIA 2010-2019
*
* 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-12 Ernesta Birznieka-Upisha
* 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
*
*/
#include "test_functions.h"
#include <iostream>
#include "embed/Default.h"
#include "js_internal/js_base.h"
#include "Embed.h"
using namespace NSJSBase;
int main(int argc, char *argv[])
int main()
{
#if 0
// Primitives example
// TODO: test
JSSmart<CJSContext> oContext1 = new CJSContext(false);
oContext1->Initialize();
JSSmart<CJSContext> oContext2 = new CJSContext;
// oContext2->Initialize();
// Work with first context
oContext1->Enter();
{
CJSContextScope scope(oContext1);
CJSLocalScope local_scope;
JSSmart<CJSValue> oResLocal = oContext1->runScript("function f() { return 'Local scope test'; }; f();");
std::cout << oResLocal->toStringA() << std::endl;
}
JSSmart<CJSObject> oGlobal1 = oContext1->GetGlobal();
JSSmart<CJSValue> oVar2 = oContext1->createString("Hel");
oGlobal1->set("v1", oVar2.GetPointer());
oContext1->runScript("var res = v1 + 'lo'");
oContext1->Exit();
// Work with second context with CJSContextScope usage
{
CJSContextScope scope(oContext2);
JSSmart<CJSObject> oGlobal2 = oContext2->GetGlobal();
JSSmart<CJSValue> oVar4 = oContext2->createString("Wor");
oGlobal2->set("v1", oVar4.GetPointer());
oContext2->runScript("var res = v1 + 'ld!'");
}
// Print result from first context
oContext1->Enter();
JSSmart<CJSValue> oRes1 = oContext1->runScript("function f() { return res; }; f();");
std::string strRes1 = oRes1->toStringA();
std::cout << strRes1 << std::endl;
// Print second variable
oContext2->Enter();
JSSmart<CJSValue> oRes2 = oContext1->runScript("function f() { return res; }; f();");
std::string strRes2 = oRes2->toStringA();
std::cout << strRes2 << std::endl;
oContext2->Exit();
oContext1->Exit();
// oContext1->Dispose();
oContext2->Dispose();
#endif
#if 0
// External embed example
JSSmart<CJSContext> oContext1 = new CJSContext();
// Embedding
CJSContextScope scope(oContext1);
CJSContext::Embed<CTestEmbed>();
JSSmart<CJSValue> oResTestEmbed1 = oContext1->runScript("(function() { var value = CreateEmbedObject('CTestEmbed'); return value.FunctionSum(10, 5); })();");
std::cout << "FunctionSum(10, 5) = " << oResTestEmbed1->toInt32() << std::endl;
JSSmart<CJSValue> oResTestEmbed2 = oContext1->runScript("(function() { var value = CreateEmbedObject('CTestEmbed'); return value.FunctionSquare(4); })();");
std::cout << "FunctionSquare(4) = " << oResTestEmbed2->toInt32() << std::endl;
JSSmart<CJSValue> oResTestEmbed3 = oContext1->runScript("(function() { var value = CreateEmbedObject('CTestEmbed'); return value.FunctionDel(30, 3); })();");
std::cout << "FunctionDel(30, 3) = " << oResTestEmbed3->toInt32() << std::endl;
JSSmart<CJSValue> oResTestEmbed4 = oContext1->runScript("(function() { var value = CreateEmbedObject('CTestEmbed'); return value.FunctionGet(); })();");
std::cout << "FunctionGet() = " << oResTestEmbed4->toInt32() << std::endl;
#endif
#if 0
// CZipEmbed example
JSSmart<CJSContext> oContext1 = new CJSContext();
JSSmart<CJSContext> oContext2 = new CJSContext();
// Work with first context
oContext1->Enter();
CreateDefaults();
JSSmart<CJSValue> oRes1 = oContext1->runScript(
"var oZip = CreateEmbedObject('CZipEmbed');\n"
"var files = oZip.open('" CURR_DIR "');\n"
"oZip.close();");
oContext1->Exit();
// Work with second context
{
CJSContextScope scope(oContext2);
// CreateDefaults();
JSSmart<CJSValue> oRes2 = oContext2->runScript(
"var oZip = CreateEmbedObject('CZipEmbed');\n"
"var files = oZip.open('" CURR_DIR "/../embed');\n"
"oZip.close();");
}
// Print first result
oContext1->Enter();
JSSmart<CJSObject> oGlobal1 = oContext1->GetGlobal();
JSSmart<CJSArray> oFiles1 = oGlobal1->get("files")->toArray();
std::cout << "\nRESULT FROM CONTEXT 1:\n";
for (int i = 0; i < oFiles1->getCount(); i++)
{
std::cout << oFiles1->get(i)->toStringA() << std::endl;
}
// Print second result
oContext2->Enter();
JSSmart<CJSObject> oGlobal2 = oContext2->GetGlobal();
JSSmart<CJSArray> oFiles2 = oGlobal2->get("files")->toArray();
std::cout << "\nRESULT FROM CONTEXT 2:\n";
for (int i = 0; i < oFiles2->getCount(); i++)
{
std::cout << oFiles2->get(i)->toStringA() << std::endl;
}
oContext2->Exit();
oContext1->Exit();
#endif
#if 0
// CHashEmbed example
JSSmart<CJSContext> oContext1 = new CJSContext();
// Call hash() on first context
CJSContextScope scope(oContext1);
CreateDefaults();
JSSmart<CJSValue> oRes1 = oContext1->runScript(
"var oHash = CreateEmbedObject('CHashEmbed');\n"
"var str = 'test';\n"
"var hash = oHash.hash(str, str.length, 0);");
// Print first result
JSSmart<CJSObject> oGlobal1 = oContext1->GetGlobal();
JSSmart<CJSTypedArray> oHash = oGlobal1->get("hash")->toTypedArray();
std::cout << "\nRESULTED HASH:\n";
for (int i = 0; i < oHash->getCount(); i++)
{
std::cout << std::hex << static_cast<unsigned>(oHash->getData().Data[i]);
}
std::cout << std::endl;
// Call hash2() on first context
JSSmart<CJSValue> oRes2 = oContext1->runScript(
"var str2 = 'test';\n"
"var hash2 = oHash.hash2(str2, 'yrGivlyCImiWnryRee1OJw==', 100000, 7);");
// Print first result
JSSmart<CJSTypedArray> oHash2 = oGlobal1->get("hash2")->toTypedArray();
std::cout << "\nRESULTED HASH2:\n";
for (int i = 0; i < oHash2->getCount(); i++)
{
std::cout << std::hex << static_cast<unsigned>(oHash2->getData().Data[i]);
}
std::cout << std::endl;
#endif
#if 1
// Mixed embed example
JSSmart<CJSContext> oContext1 = new CJSContext();
// External CTestEmbed
CJSContextScope scope(oContext1);
CJSContext::Embed<CTestEmbed>(false);
JSSmart<CJSValue> oResTestEmbed1 = oContext1->runScript("(function() { var value = CreateEmbedObject('CTestEmbed'); return value.FunctionSum(10, 5); })();");
if (oResTestEmbed1->isNumber())
std::cout << "FunctionSum(10, 5) = " << oResTestEmbed1->toInt32() << std::endl;
JSSmart<CJSObject> oTestEmbed = CJSContext::createEmbedObject("CTestEmbed");
// JSSmart<CJSValue> oResTestEmbed2 = oContext1->runScript("(function() { var value = CreateEmbedObject('CTestEmbed'); return value.FunctionSquare(4); })();");
JSSmart<CJSValue> args2[1];
args2[0] = CJSContext::createInt(4);
JSSmart<CJSValue> oResTestEmbed2 = oTestEmbed->call_func("FunctionSquare", 1, args2);
if (oResTestEmbed2->isNumber())
std::cout << "FunctionSquare(4) = " << oResTestEmbed2->toInt32() << std::endl;
// JSSmart<CJSValue> oResTestEmbed3 = oContext1->runScript("(function() { var value = CreateEmbedObject('CTestEmbed'); return value.FunctionDel(30, 3); })();");
JSSmart<CJSValue> args3[2];
args3[0] = CJSContext::createInt(30);
args3[1] = CJSContext::createInt(3);
JSSmart<CJSValue> oResTestEmbed3 = oTestEmbed->call_func("FunctionDel", 2, args3);
if (oResTestEmbed3->isNumber())
std::cout << "FunctionDel(30, 3) = " << oResTestEmbed3->toInt32() << std::endl;
JSSmart<CJSValue> oResTestEmbed4 = oContext1->runScript("(function() { var value = CreateEmbedObject('CTestEmbed'); return value.FunctionGet(); })();");
if (oResTestEmbed4->isNumber())
std::cout << "FunctionGet() = " << oResTestEmbed4->toInt32() << std::endl;
// Internal CHashEmbed
CreateDefaults();
oContext1->runScript(
"var oHash = CreateEmbedObject('CHashEmbed');\n"
"var str = 'test';\n"
"var hash = oHash.hash(str, str.length, 0);");
// Print hash
JSSmart<CJSObject> oGlobal = oContext1->GetGlobal();
JSSmart<CJSTypedArray> oHash = oGlobal->get("hash")->toTypedArray();
std::cout << "\nRESULTED HASH:\n";
for (int i = 0; i < oHash->getCount(); i++)
{
std::cout << std::hex << static_cast<unsigned>(oHash->getData().Data[i]);
}
std::cout << std::endl;
// Internal CZipEmbed
oContext1->runScript(
"var oZip = CreateEmbedObject('CZipEmbed');\n"
"var files = oZip.open('" CURR_DIR "');\n"
"oZip.close();");
// Print files
JSSmart<CJSArray> oFiles1 = oGlobal->get("files")->toArray();
std::cout << "\nFILES IN CURRENT DIRECTORY:\n";
for (int i = 0; i < oFiles1->getCount(); i++)
{
std::cout << oFiles1->get(i)->toStringA() << std::endl;
}
#endif
// testMultipleContexts();
testEmbedExternal();
// testEmbedInternal();
// testHashEmbed();
// testEmbedMixed();
return 0;
}

View File

@ -0,0 +1,14 @@
#include "test_functions.h"
int main()
{
// all test functions should be called inside the `@autoreleasepool` block!
@autoreleasepool
{
testEmbedExternal();
// testHashEmbed();
// testEmbedMixed();
}
return 0;
}

View File

@ -29,10 +29,18 @@ core_linux {
LIBS += -ldl
}
SOURCES += main.cpp \
Embed.cpp
HEADERS += \
Embed.h
Embed.h \
test_functions.h
SOURCES += \
Embed.cpp \
test_functions.cpp
use_javascript_core {
OBJECTIVE_SOURCES += main.mm
} else {
SOURCES += main.cpp
}
ADD_FILES_FOR_EMBEDDED_CLASS_HEADER(Embed.h)

View File

@ -0,0 +1,286 @@
#include "test_functions.h"
#include <iostream>
#include "embed/Default.h"
#include "js_internal/js_base.h"
#include "Embed.h"
using namespace NSJSBase;
void testMultipleContexts()
{
// passing `false` when creating CJSContext means that we need to initialize it manually
JSSmart<CJSContext> context1 = new CJSContext(false);
context1->Initialize();
// while creating CJSContext without any arguments will create initialized CJSContext
JSSmart<CJSContext> context2 = new CJSContext;
// we don't need it:
// oContext2->Initialize();
// entering the first context
context1->Enter();
{
// entering the first context the second time in scope creation - it's allowed and the scopes stack correctly
CJSContextScope scope(context1);
// allocate new local variables inside a custom local scope instead of
// the one that is provided by CJSContextScope by default
CJSLocalScope local_scope;
JSSmart<CJSValue> res_local = context1->runScript("(function() { return 'Local scope test'; })();");
std::cout << res_local->toStringA() << std::endl;
// the first context is going to be exited at the end of the scope
}
// at this moment we are still inside the first context, since we have entered it twices
JSSmart<CJSObject> global1 = context1->GetGlobal();
JSSmart<CJSValue> var = context1->createString("Hel");
global1->set("v1", var);
// here `res` is set to be "Hello"
context1->runScript("var res = v1 + 'lo'");
// exit from the first context
context1->Exit();
// now we are going to work with the second context
{
// enter the second context via context scope
CJSContextScope scope(context2);
JSSmart<CJSObject> global2 = context2->GetGlobal();
JSSmart<CJSValue> var = context2->createString("Wor");
global2->set("v1", var);
// `res` is "World!"
context2->runScript("var res = v1 + 'ld!'");
// the second context is going to be exited at the end of the scope
}
// enter the first context
context1->Enter();
// print `res` variable from the first context
JSSmart<CJSValue> res1 = context1->runScript("(function() { return res; })();");
std::string str_res1 = res1->toStringA();
std::cout << str_res1 << ", ";
// make new variable `v2` in first context
// important to note, that accessing previous `global1` object is undefined behaviour and can lead to crashes!
// that is because when we exited from the first context, every local handle inside CJSValue and CJSObject was invalidated
global1 = context1->GetGlobal();
global1->set("v2", CJSContext::createInt(42));
// enter from the second context (notice, we haven't exited the first context before)
context2->Enter();
// print `res` variable from the second context
JSSmart<CJSValue> res2 = context1->runScript("(function() { return res; })();");
std::string str_res2 = res2->toStringA();
std::cout << str_res2 << std::endl;
// exit from the second context
context2->Exit();
// at this moment we are still in the first context
// we can validate that accessing `v2` variable, which exists only in the first context
global1 = context1->GetGlobal();
std::cout << global1->get("v2")->toInt32() << std::endl;
// exit from the first context
context1->Exit();
// manual disposing is not necessary, since it's going to be called in CJSContext's destructor anyway
// so we don't need to explicitly write:
// oContext1->Dispose();
// but still nothing wrong will happen if we do:
context2->Dispose();
}
void testEmbedExternal()
{
JSSmart<CJSContext> context = new CJSContext();
// Embedding
CJSContextScope scope(context);
CJSContext::Embed<CTestEmbed>();
JSSmart<CJSValue> res1 = context->runScript("(function() { let value = CreateEmbedObject('CTestEmbed'); let ret = value.FunctionSum(10, 5); FreeEmbedObject(value); return ret; })();");
std::cout << "FunctionSum(10, 5) = " << res1->toInt32() << std::endl;
JSSmart<CJSValue> res2 = context->runScript("(function() { let value = CreateEmbedObject('CTestEmbed'); let ret = value.FunctionSquare(4); FreeEmbedObject(value); return ret; })();");
std::cout << "FunctionSquare(4) = " << res2->toInt32() << std::endl;
JSSmart<CJSValue> res3 = context->runScript("(function() { let value = CreateEmbedObject('CTestEmbed'); let ret = value.FunctionDel(30, 3); FreeEmbedObject(value); return ret; })();");
std::cout << "FunctionDel(30, 3) = " << res3->toInt32() << std::endl;
JSSmart<CJSValue> res4 = context->runScript("(function() { let value = CreateEmbedObject('CTestEmbed'); let ret = value.FunctionGet(); FreeEmbedObject(value); return ret; })();");
std::cout << "FunctionGet() = " << res4->toInt32() << std::endl;
}
void testEmbedInternal()
{
// create both contexts
JSSmart<CJSContext> context1 = new CJSContext();
JSSmart<CJSContext> context2 = new CJSContext();
// work with the first context
context1->Enter();
// create embedding info for internally embedded objects (CZipEmbed is the one of them)
CreateDefaults();
context1->runScript(
"var oZip = CreateEmbedObject('CZipEmbed');\n"
"var files = oZip.open('" CURR_DIR "');\n"
"oZip.close();"
);
context1->Exit();
// work with the second context via context scope
{
CJSContextScope scope(context2);
// function CJSContext::Embed() is context-independent, so we don't actually need to call it in another context
// CreateDefaults();
context2->runScript(
"var oZip = CreateEmbedObject('CZipEmbed');\n"
"var files = oZip.open('" CURR_DIR "/../../../embed');\n"
"oZip.close();"
);
}
// print the files from the first context
context1->Enter();
JSSmart<CJSObject> global1 = context1->GetGlobal();
JSSmart<CJSArray> file_list1 = global1->get("files")->toArray();
std::cout << "\nRESULT FROM CONTEXT 1:\n";
for (int i = 0; i < file_list1->getCount(); i++)
{
std::cout << file_list1->get(i)->toStringA() << std::endl;
}
// print the files from the second result (note, we haven't exited the first context before)
context2->Enter();
JSSmart<CJSObject> global2 = context2->GetGlobal();
JSSmart<CJSArray> file_list2 = global2->get("files")->toArray();
std::cout << "\nRESULT FROM CONTEXT 2:\n";
for (int i = 0; i < file_list2->getCount(); i++)
{
std::cout << file_list2->get(i)->toStringA() << std::endl;
}
// exit the contexts in reverse order
context2->Exit();
context1->Exit();
}
void testHashEmbed()
{
JSSmart<CJSContext> context = new CJSContext();
// test hash()
CJSContextScope scope(context);
CreateDefaults();
context->runScript(
"var oHash = CreateEmbedObject('CHashEmbed');\n"
"var str = 'test';\n"
"var hash = oHash.hash(str, str.length, 0);"
);
JSSmart<CJSObject> global = context->GetGlobal();
JSSmart<CJSTypedArray> res_hash = global->get("hash")->toTypedArray();
std::cout << "\nRESULTED HASH:\n";
for (int i = 0; i < res_hash->getCount(); i++)
{
std::cout << std::hex << static_cast<unsigned>(res_hash->getData().Data[i]);
}
std::cout << std::endl;
// test hash2()
context->runScript(
"var str2 = 'test';\n"
"var hash2 = oHash.hash2(str2, 'yrGivlyCImiWnryRee1OJw==', 100000, 7);"
);
JSSmart<CJSTypedArray> res_hash2 = global->get("hash2")->toTypedArray();
std::cout << "\nRESULTED HASH2:\n";
for (int i = 0; i < res_hash2->getCount(); i++)
{
std::cout << std::hex << static_cast<unsigned>(res_hash2->getData().Data[i]);
}
std::cout << std::endl;
}
void testEmbedMixed()
{
JSSmart<CJSContext> context = new CJSContext();
CJSContextScope scope(context);
// --- test external embedding with CTestEmbed ---
// embed with `false` - means we are not able to create the object directly from JavaScript.
CJSContext::Embed<CTestEmbed>(false);
// example of incorrect usage:
JSSmart<CJSValue> res1 = context->runScript("(function() { var value = CreateEmbedObject('CTestEmbed'); return value.FunctionSum(10, 5); })();");
if (res1->isNumber())
{
// this wouldn't print anything, since `res1` not a number - embedded object was not created in JS and exception was thrown.
std::cout << "FunctionSum(10, 5) = " << res1->toInt32() << std::endl;
}
// example of correct usage:
JSSmart<CJSObject> embedded_object = CJSContext::createEmbedObject("CTestEmbed");
JSSmart<CJSValue> args2[1];
args2[0] = CJSContext::createInt(4);
JSSmart<CJSValue> res2 = embedded_object->call_func("FunctionSquare", 1, args2);
if (res2->isNumber())
{
// should print: "FunctionSquare(4) = 16"
std::cout << "FunctionSquare(4) = " << res2->toInt32() << std::endl;
}
// another example of correct usage:
JSSmart<CJSValue> args3[2];
args3[0] = CJSContext::createInt(30);
args3[1] = CJSContext::createInt(3);
JSSmart<CJSValue> oResTestEmbed3 = embedded_object->call_func("FunctionDel", 2, args3);
if (oResTestEmbed3->isNumber())
{
// should print: "FunctionDel(30, 3) = 10"
std::cout << "FunctionDel(30, 3) = " << oResTestEmbed3->toInt32() << std::endl;
}
// another example of incorrect usage:
JSSmart<CJSValue> oResTestEmbed4 = context->runScript("(function() { var value = CreateEmbedObject('CTestEmbed'); return value.FunctionGet(); })();");
if (oResTestEmbed4->isNumber())
{
// again, this won't be executed and nothing will be printed
std::cout << "FunctionGet() = " << oResTestEmbed4->toInt32() << std::endl;
}
// --- test internal embedding with CHashEmbed ---
CreateDefaults();
context->runScript(
"var oHash = CreateEmbedObject('CHashEmbed');\n"
"var str = 'test';\n"
"var hash = oHash.hash(str, str.length, 0);"
);
// print hash
JSSmart<CJSObject> global = context->GetGlobal();
JSSmart<CJSTypedArray> hash = global->get("hash")->toTypedArray();
std::cout << "\nRESULTED HASH:\n";
for (int i = 0; i < hash->getCount(); i++)
{
std::cout << std::hex << static_cast<unsigned>(hash->getData().Data[i]);
}
std::cout << std::endl;
// --- test internal embedding with CZipEmbed ---
context->runScript(
"var oZip = CreateEmbedObject('CZipEmbed');\n"
"var files = oZip.open('" CURR_DIR "');\n"
"oZip.close();"
);
// print files
JSSmart<CJSArray> file_list = global->get("files")->toArray();
std::cout << "\nFILES IN CURRENT DIRECTORY:\n";
for (int i = 0; i < file_list->getCount(); i++)
{
std::cout << file_list->get(i)->toStringA() << std::endl;
}
}

View File

@ -0,0 +1,34 @@
#ifndef TEST_FUNCTIONS_H_
#define TEST_FUNCTIONS_H_
/**
* NOTE: V8 ONLY!
* The function tests the work of two CJSContexts in one thread.
* Current working context is managed with Enter() and Exit() functions, or with CJSContextScope.
*/
void testMultipleContexts();
/**
* The function tests external embedding functionality by embedding CTestEmbed class.
*/
void testEmbedExternal();
/**
* NOTE: V8 ONLY!
* The function tests internal embedding functionality by using CZipEmbed class.
* It also shows how embedding works for two CJSContext in the same thread (similar to testMultipleContexts()).
*/
void testEmbedInternal();
/**
* The function tests CHashEmbed class that is embedded internally.
*/
void testHashEmbed();
/**
* The function tests both internal and external embedding in a more complicated way.
*/
void testEmbedMixed();
#endif // TEST_FUNCTIONS_H_

View File

@ -40,7 +40,7 @@ var UpdateFontsSource = {
function CFile()
{
this.nativeFile = 0;
this.stream = [];
this.stream = -1;
this.stream_size = 0;
this.type = -1;
this.pages = [];
@ -128,17 +128,17 @@ CFile.prototype["close"] = function()
this.pages = [];
this.info = null;
this.StartID = null;
for (let i = 0; i < this.stream.length; i++)
this._free(this.stream[i]);
this.stream = [];
if (this.stream > 0)
this._free(this.stream);
this.stream = -1;
self.drawingFile = null;
};
CFile.prototype["getFileBinary"] = function()
{
if (this.stream.length == 0)
if (0 >= this.stream)
return "";
return new Uint8Array(Module["HEAP8"].buffer, this.stream[0], this.stream_size);
return new Uint8Array(Module["HEAP8"].buffer, this.stream, this.stream_size);
};
CFile.prototype["isNeedPassword"] = function()
@ -1566,8 +1566,13 @@ CFile.prototype["readAnnotationsInfoFromBinary"] = function(AnnotInfo)
CFile.prototype["scanPage"] = function(page, mode)
{
let ptr = this._scanPage(page, mode);
let reader = ptr.getReader();
if (mode == 2) {
data = ptr.getMemory(true);
ptr.free();
return data;
}
let reader = ptr.getReader();
if (!reader) return [];
let shapesCount = reader.readInt();

View File

@ -101,9 +101,8 @@ CFile.prototype._openFile = function(buffer, password)
{
let data = new Uint8Array(buffer);
this.stream_size = data.length;
let stream = Module["_malloc"](this.stream_size);
Module["HEAP8"].set(data, stream);
this.stream.push(stream);
this.stream = Module["_malloc"](this.stream_size);
Module["HEAP8"].set(data, this.stream);
}
let passwordPtr = 0;
@ -114,7 +113,7 @@ CFile.prototype._openFile = function(buffer, password)
Module["HEAP8"].set(passwordBuf, passwordPtr);
}
this.nativeFile = Module["_Open"](this.stream[0], this.stream_size, passwordPtr);
this.nativeFile = Module["_Open"](this.stream, this.stream_size, passwordPtr);
if (passwordPtr)
Module["_free"](passwordPtr);
@ -128,7 +127,7 @@ CFile.prototype._closeFile = function()
CFile.prototype._getType = function()
{
return Module["_GetType"](this.stream[0], this.stream_size);
return Module["_GetType"](this.nativeFile);
};
CFile.prototype._getError = function()
@ -180,10 +179,7 @@ CFile.prototype._MergePages = function(buffer, maxID, prefixForm)
}
let bRes = Module["_MergePages"](this.nativeFile, stream2, data.length, maxID, prefixPtr);
if (bRes == 1)
this.stream.push(stream2);
else
Module["_free"](stream2);
stream2 = 0; // Success or not, stream2 is either taken or freed
if (prefixPtr)
Module["_free"](prefixPtr);
@ -193,13 +189,7 @@ CFile.prototype._MergePages = function(buffer, maxID, prefixForm)
CFile.prototype._UndoMergePages = function()
{
let bRes = Module["_UnmergePages"](this.nativeFile);
if (bRes == 1)
{
let str = this.stream.pop();
Module["_free"](str);
}
return bRes == 1;
return Module["_UnmergePages"](this.nativeFile) == 1;
};
// FONTS

View File

@ -68,25 +68,6 @@ WASM_EXPORT int IsFontBinaryExist(char* path)
return 0;
}
WASM_EXPORT int GetType(BYTE* data, LONG size)
{
// 0 - PDF
// 1 - DJVU
// 2 - XPS
LONG nHeaderSearchSize = 1024;
LONG nSize = size < nHeaderSearchSize ? size : nHeaderSearchSize;
char* pData = (char*)data;
for (int i = 0; i < nSize - 5; ++i)
{
int nPDF = strncmp(&pData[i], "%PDF-", 5);
if (!nPDF)
return 0;
}
if ( (8 <= size) && (0x41 == data[0] && 0x54 == data[1] && 0x26 == data[2] && 0x54 == data[3] &&
0x46 == data[4] && 0x4f == data[5] && 0x52 == data[6] && 0x4d == data[7]))
return 1;
return 2;
}
WASM_EXPORT CDrawingFile* Open(BYTE* data, LONG size, const char* password)
{
if (!g_applicationFonts)
@ -102,6 +83,13 @@ WASM_EXPORT CDrawingFile* Open(BYTE* data, LONG size, const char* password)
pFile->OpenFile(data, size, sPassword);
return pFile;
}
WASM_EXPORT int GetType(CDrawingFile* pFile)
{
// 0 - PDF
// 1 - DJVU
// 2 - XPS
return pFile->GetType();
}
WASM_EXPORT int GetErrorCode(CDrawingFile* pFile)
{
if (!pFile)

View File

@ -1022,9 +1022,9 @@ int main(int argc, char* argv[])
}
}
RELEASEARRAYOBJECTS(pFileData);
// SPLIT & MERGE
BYTE* pSplitPages = NULL;
BYTE* pFileMerge = NULL;
if (false)
{
int nBufferLen = NULL;
@ -1036,12 +1036,19 @@ int main(int argc, char* argv[])
BYTE* pSplitPages = SplitPages(pGrFile, arrPages.data(), arrPages.size(), pBuffer, nBufferLen);
int nLength = READ_INT(pSplitPages);
NSFile::CFileBinary oFile;
if (oFile.CreateFileW(NSFile::GetProcessDirectory() + L"/split1.pdf"))
oFile.WriteFile(pSplitPages + 4, nLength - 4);
oFile.CloseFile();
if (nLength > 4)
{
NSFile::CFileBinary oFile;
if (oFile.CreateFileW(NSFile::GetProcessDirectory() + L"/split1.pdf"))
oFile.WriteFile(pSplitPages + 4, nLength - 4);
oFile.CloseFile();
MergePages(pGrFile, pSplitPages + 4, nLength - 4, 0, "merge1");
BYTE* pMallocData = (BYTE*)malloc(nLength - 4);
memcpy(pMallocData, pSplitPages + 4, nLength - 4);
MergePages(pGrFile, pMallocData, nLength - 4, 0, "merge1");
}
RELEASEARRAYOBJECTS(pSplitPages);
}
RELEASEARRAYOBJECTS(pBuffer);
@ -1051,12 +1058,19 @@ int main(int argc, char* argv[])
BYTE* pSplitPages = SplitPages(pGrFile, arrPages.data(), arrPages.size(), pBuffer, nBufferLen);
int nLength = READ_INT(pSplitPages);
NSFile::CFileBinary oFile;
if (oFile.CreateFileW(NSFile::GetProcessDirectory() + L"/split2.pdf"))
oFile.WriteFile(pSplitPages + 4, nLength - 4);
oFile.CloseFile();
if (nLength > 4)
{
NSFile::CFileBinary oFile;
if (oFile.CreateFileW(NSFile::GetProcessDirectory() + L"/split2.pdf"))
oFile.WriteFile(pSplitPages + 4, nLength - 4);
oFile.CloseFile();
MergePages(pGrFile, pSplitPages + 4, nLength - 4, 0, "merge2");
BYTE* pMallocData = (BYTE*)malloc(nLength - 4);
memcpy(pMallocData, pSplitPages + 4, nLength - 4);
MergePages(pGrFile, pMallocData, nLength - 4, 0, "merge2");
}
RELEASEARRAYOBJECTS(pSplitPages);
}
RELEASEARRAYOBJECTS(pBuffer);
}
@ -2053,10 +2067,6 @@ int main(int argc, char* argv[])
}
Close(pGrFile);
RELEASEARRAYOBJECTS(pFileData);
RELEASEARRAYOBJECTS(pSplitPages);
RELEASEARRAYOBJECTS(pFileMerge);
RELEASEARRAYOBJECTS(pCMapData);
return 0;
}

View File

@ -2,8 +2,11 @@
#define _WASM_SERIALIZE_H
#include <vector>
#include <stack>
#include "../../../../../common/File.h"
#define CLEAR_STACK(stack) while (!(stack).empty()) (stack).pop()
namespace NSWasm
{
class CData
@ -15,6 +18,8 @@ namespace NSWasm
BYTE* m_pDataCur;
size_t m_lSizeCur;
std::stack<size_t> m_lStack;
public:
CData()
{
@ -24,10 +29,70 @@ namespace NSWasm
m_pDataCur = m_pData;
m_lSizeCur = m_lSize;
}
CData(const CData& other)
{
m_lSize = other.m_lSize;
m_lSizeCur = other.m_lSizeCur;
m_pData = (BYTE*)malloc(m_lSize * sizeof(BYTE));
memcpy(m_pData, other.m_pData, other.m_lSizeCur * sizeof(BYTE));
m_pDataCur = m_pData + m_lSizeCur;
m_lStack = other.m_lStack;
}
CData(CData&& other)
{
m_lSize = other.m_lSize;
m_lSizeCur = other.m_lSizeCur;
m_pData = other.m_pData;
m_pDataCur = other.m_pDataCur;
m_lStack = std::move(other.m_lStack);
other.ClearWithoutAttack();
}
virtual ~CData()
{
Clear();
}
CData& operator= (const CData& other)
{
if (this == &other)
return *this;
Clear();
m_lSize = other.m_lSize;
m_lSizeCur = other.m_lSizeCur;
m_pData = (BYTE*)malloc(m_lSize * sizeof(BYTE));
memcpy(m_pData, other.m_pData, other.m_lSizeCur * sizeof(BYTE));
m_pDataCur = m_pData + m_lSizeCur;
m_lStack = other.m_lStack;
return *this;
}
CData& operator= (CData&& other)
{
if (this == &other)
return *this;
Clear();
m_lSize = other.m_lSize;
m_lSizeCur = other.m_lSizeCur;
m_pData = other.m_pData;
m_pDataCur = other.m_pDataCur;
other.ClearWithoutAttack();
m_lStack = std::move(other.m_lStack);
return *this;
}
inline void AddSize(size_t nSize)
{
@ -68,6 +133,20 @@ namespace NSWasm
}
public:
void StartRecord(BYTE type)
{
AddSize(5); // sizeof (BYTE + unsigned int)
WriteBYTE(type);
AddInt(0);
m_lStack.push(m_lSizeCur);
}
void EndRecord()
{
size_t start = m_lStack.top();
unsigned int len = m_lSizeCur - start;
memcpy(m_pData + start - 4, &len, sizeof(unsigned int));
m_lStack.pop();
}
void AddInt(unsigned int value)
{
AddSize(4);
@ -75,6 +154,13 @@ namespace NSWasm
m_pDataCur += 4;
m_lSizeCur += 4;
}
void AddSInt(int value)
{
AddSize(4);
memcpy(m_pDataCur, &value, sizeof(int));
m_pDataCur += 4;
m_lSizeCur += 4;
}
void AddInt(unsigned int value, size_t pos)
{
if (pos < m_lSizeCur)
@ -93,6 +179,10 @@ namespace NSWasm
m_pDataCur += sizeof(BYTE);
m_lSizeCur += sizeof(BYTE);
}
void WriteBool(bool value)
{
WriteBYTE(value ? 1 : 0);
}
void WriteDouble(double value)
{
int nV = value * 10000;
@ -151,6 +241,37 @@ namespace NSWasm
WriteString(pDataUtf8, (unsigned int)lDataUtf8);
RELEASEARRAYOBJECTS(pDataUtf8);
}
void WriteStringUtf16(const std::wstring& sStr, const bool& isBytes = false)
{
unsigned int size = static_cast<unsigned int>(sStr.length());
int len = 0;
size_t posLen = m_lSizeCur;
// len reserve
AddInt(0);
if (sizeof(wchar_t) == 4)
{
AddSize(4 * size + 2/*'\0'*/);
NSFile::CUtf8Converter::GetUtf16StringFromUnicode_4bytes(sStr.c_str(), (LONG)size, m_pDataCur, len, false);
}
else
{
size_t bufferLen = 2 * size;
AddSize(bufferLen);
len = (int)(bufferLen);
memcpy(m_pDataCur, sStr.c_str(), bufferLen);
}
m_pDataCur += static_cast<unsigned int>(len);
m_lSizeCur += static_cast<unsigned int>(len);
if (!isBytes)
len /= 2;
AddInt((unsigned int)len, posLen);
}
void Write(BYTE* value, unsigned int len)
{
if (!value || len == 0)
@ -165,6 +286,13 @@ namespace NSWasm
return m_pData;
}
BYTE* MoveBuffer()
{
BYTE* pData = m_pData;
ClearWithoutAttack();
return pData;
}
void Clear()
{
if (m_pData)
@ -175,6 +303,8 @@ namespace NSWasm
m_pDataCur = m_pData;
m_lSizeCur = 0;
CLEAR_STACK(m_lStack);
}
void ClearWithoutAttack()
{
@ -183,11 +313,15 @@ namespace NSWasm
m_pDataCur = m_pData;
m_lSizeCur = 0;
CLEAR_STACK(m_lStack);
}
void ClearNoAttack()
{
m_pDataCur = m_pData;
m_lSizeCur = 0;
CLEAR_STACK(m_lStack);
}
unsigned int GetSize()
{