Skip to content
This repository was archived by the owner on Aug 31, 2021. It is now read-only.

Commit bf6f3e4

Browse files
committed
Merge pull request #3647 from runrevmark/feature-license_check-6_7-new
[[ LicenseCheck ]] Implement the ExternalV1 license check API (6.7)
2 parents 1b524d2 + b952540 commit bf6f3e4

File tree

6 files changed

+246
-13
lines changed

6 files changed

+246
-13
lines changed

engine/src/capsule.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,10 @@ enum MCCapsuleSectionType
106106
// AL-2015-02-10: [[ Standalone Inclusions ]] Library consists of the mappings from universal names
107107
// of resources to their platform-specific paths relative to the executable.
108108
kMCCapsuleSectionTypeLibrary,
109+
110+
// MW-2016-02-17: [[ LicenseChecks ]] License consists of the array-encoded
111+
// 'revLicenseInfo' array in use at the point the standalone was built.
112+
kMCCapsuleSectionTypeLicense,
109113
};
110114

111115
// Each section begins with a header that defines its type and length. This is

engine/src/deploy.cpp

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,16 +152,51 @@ static bool MCDeployWriteDefinePrologueSection(const MCDeployParameters& p_param
152152
return MCDeployCapsuleDefine(p_capsule, kMCCapsuleSectionTypePrologue, &t_prologue, sizeof(t_prologue));
153153
}
154154

155+
static bool MCDeployWriteDefineLicenseSection(const MCDeployParameters& p_params, MCDeployCapsuleRef p_capsule)
156+
{
157+
// The edition byte encoding is development/standalone engine pair
158+
// specific.
159+
unsigned char t_edition;
160+
switch(MClicenseparameters . license_class)
161+
{
162+
case kMCLicenseClassNone:
163+
t_edition = 0;
164+
break;
165+
166+
case kMCLicenseClassCommunity:
167+
t_edition = 1;
168+
break;
169+
170+
case kMCLicenseClassCommercial:
171+
t_edition = 2;
172+
break;
173+
174+
case kMCLicenseClassProfessional:
175+
t_edition = 3;
176+
break;
177+
}
178+
179+
return MCDeployCapsuleDefine(p_capsule,
180+
kMCCapsuleSectionTypeLicense,
181+
&t_edition,
182+
sizeof(t_edition));
183+
}
184+
155185
// This method generates the standalone specific capsule elements. This is
156186
// just a Standalone Prologue section at the moment.
157187
static bool MCDeployWriteCapsuleDefineStandaloneSections(const MCDeployParameters& p_params, MCDeployCapsuleRef p_capsule)
158188
{
159189
bool t_success;
160190
t_success = true;
161-
191+
192+
// First emit the prologue.
162193
if (t_success)
163194
t_success = MCDeployWriteDefinePrologueSection(p_params, p_capsule);
164-
195+
196+
// Next emit the license info.
197+
if (t_success)
198+
t_success = MCDeployWriteDefineLicenseSection(p_params, p_capsule);
199+
165200
return t_success;
166201
}
167202

engine/src/executionerrors.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2472,6 +2472,9 @@ enum Exec_errors
24722472
// SN-2014-12-15: [[ Bug 14211 ]] put ... into the next line of ... should return an error
24732473
// {EE-0810} Chunk: bad extents provided
24742474
EE_CHUNK_BADEXTENTS,
2475+
2476+
// {EE-0811} external: unlicensed
2477+
EE_EXTERNAL_UNLICENSED,
24752478
};
24762479

24772480
extern const char *MCexecutionerrors;

engine/src/externalv1.cpp

Lines changed: 164 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ typedef void (*MCExternalThreadOptionalCallback)(void *state);
5353
typedef void (*MCExternalThreadRequiredCallback)(void *state, int flags);
5454

5555
// MW-2013-06-14: [[ ExternalsApiV5 ]] Update the interface version.
56+
// MW-2016-02-25: [[ LicenseCheck ]] We cannot bump the interface version without
57+
// breaking existing built externals. Instead, we keep the version at 5 for 6.7
58+
// and add a HasLicenseCheck tag to the Query call.
5659
#define kMCExternalInterfaceVersion 5
5760

5861
enum
@@ -162,6 +165,8 @@ enum MCExternalError
162165
kMCExternalErrorNoObjectPropertyValue = 35,
163166

164167
kMCExternalErrorInvalidInterfaceQuery = 36,
168+
169+
kMCExternalErrorUnlicensed = 42,
165170
};
166171

167172
enum MCExternalContextQueryTag
@@ -185,6 +190,17 @@ enum MCExternalContextQueryTag
185190

186191
// MW-2013-06-14: [[ ExternalsApiV5 ]] Accessor to fetch 'the wholeMatches'.
187192
kMCExternalContextQueryWholeMatches,
193+
194+
// SN-2014-07-01: [[ ExternalsApiV6 ]] These return a UTF16CString.
195+
// These are unimplemented in 6.7.
196+
kMCExternalContextQueryUnicodeItemDelimiter,
197+
kMCExternalContextQueryUnicodeLineDelimiter,
198+
kMCExternalContextQueryUnicodeColumnDelimiter,
199+
kMCExternalContextQueryUnicodeRowDelimiter,
200+
201+
// If fetching this accessor works, and it returns true then
202+
// the license check API is present.
203+
kMCExternalContextQueryHasLicenseCheck,
188204
};
189205

190206
enum MCExternalVariableQueryTag
@@ -245,6 +261,14 @@ enum MCExternalDispatchStatus
245261
kMCExternalDispatchStatusAbort,
246262
};
247263

264+
enum MCExternalLicenseType
265+
{
266+
kMCExternalLicenseTypeNone = 0,
267+
kMCExternalLicenseTypeCommunity = 1000,
268+
kMCExternalLicenseTypeIndy = 2000,
269+
kMCExternalLicenseTypeBusiness = 3000,
270+
};
271+
248272
enum MCExternalHandlerType
249273
{
250274
kMCExternalHandlerTypeNone,
@@ -277,7 +301,7 @@ struct MCExternalInterface
277301

278302
//////////
279303

280-
MCExternalError (*context_query)(MCExternalContextQueryTag op, void *result);
304+
MCExternalError (*context_query_legacy)(MCExternalContextQueryTag op, void *result);
281305

282306
//////////
283307

@@ -338,6 +362,14 @@ struct MCExternalInterface
338362
// in the current context.
339363
// MW-2013-06-21: [[ ExternalsApiV5 ]] Added binds parameters for future extension.
340364
MCExternalError (*context_execute)(const char *p_expression, unsigned int options, MCExternalVariableRef *binds, unsigned int bind_count); // V5
365+
366+
// SN-2015-01-26: [[ Bug 14057 ]] Update context query, to allow the user to set the return type
367+
MCExternalError (*context_query)(MCExternalContextQueryTag op, MCExternalValueOptions p_options, void *r_result); // V6
368+
369+
// MW-2016-02-17: [[ LicenseCheck ]] Method to check the licensing of the engine. This is
370+
// present either if interface version is V7, or the HasLicenseCheck query call returns
371+
// true.
372+
MCExternalError (*license_check_edition)(unsigned int options, unsigned int min_edition); // V7
341373
};
342374

343375
typedef MCExternalInfo *(*MCExternalDescribeProc)(void);
@@ -360,20 +392,39 @@ class MCExternalV1: public MCExternal
360392
virtual Handler_type GetHandlerType(uint32_t index) const;
361393
virtual bool ListHandlers(MCExternalListHandlersCallback callback, void *state);
362394
virtual Exec_stat Handle(MCObject *p_context, Handler_type p_type, uint32_t p_index, MCParameter *p_parameters);
363-
395+
396+
void SetWasLicensed(bool p_value);
397+
364398
private:
365399
virtual bool Prepare(void);
366400
virtual bool Initialize(void);
367401
virtual void Finalize(void);
368402

369403
MCExternalInfo *m_info;
404+
405+
// This is true if startup succeeded (returned true) and license_fail was
406+
// not called.
407+
bool m_licensed : 1;
408+
409+
// This is set to true if the last external handler call on this external
410+
// did not call license_fail.
411+
bool m_was_licensed : 1;
370412
};
371413

372414
////////////////////////////////////////////////////////////////////////////////
373415

416+
// This static variable is set to the currently executing external during
417+
// any calls to its exported functions (startup, shutdown etc.). It is used by
418+
// the license fail API to mark the external's was_licensed member as false.
419+
static MCExternalV1 *s_current_external = nil;
420+
421+
////////////////////////////////////////////////////////////////////////////////
422+
374423
MCExternalV1::MCExternalV1(void)
375424
{
376425
m_info = nil;
426+
m_licensed = false;
427+
m_was_licensed = false;
377428
}
378429

379430
MCExternalV1::~MCExternalV1(void)
@@ -387,8 +438,15 @@ bool MCExternalV1::Prepare(void)
387438
MCExternalDescribeProc t_describe;
388439
t_describe = (MCExternalDescribeProc)MCS_resolvemodulesymbol(m_module, "MCExternalDescribe");
389440

441+
// Update the current external var.
442+
s_current_external = this;
443+
390444
// Query the info record - if this returns nil something odd is going on!
391445
m_info = t_describe();
446+
447+
// Unset the current external var.
448+
s_current_external = nil;
449+
392450
if (m_info == nil)
393451
return false;
394452

@@ -402,11 +460,28 @@ bool MCExternalV1::Initialize(void)
402460
t_initialize = (MCExternalInitializeProc)MCS_resolvemodulesymbol(m_module, "MCExternalInitialize");
403461
if (t_initialize == nil)
404462
return true;
405-
463+
464+
// Make sure the 'was_licensed' instance var is true. A call to LicenseFail
465+
// during startup will set it to false.
466+
m_was_licensed = true;
467+
468+
// Update the current external var.
469+
s_current_external = this;
470+
406471
// See if initialization succeeds.
407-
if (!t_initialize(&g_external_interface))
472+
bool t_success;
473+
t_success = t_initialize(&g_external_interface);
474+
475+
// Unset the current external var.
476+
s_current_external = nil;
477+
478+
if (!t_success)
408479
return false;
409-
480+
481+
// If license fail was invoked during startup, we mark the whole external
482+
// as unlicensed which means all calls to it will throw an error.
483+
m_licensed = m_was_licensed;
484+
410485
return true;
411486
}
412487

@@ -417,8 +492,14 @@ void MCExternalV1::Finalize(void)
417492
t_finalize = (MCExternalFinalizeProc)MCS_resolvemodulesymbol(m_module, "MCExternalFinalize");
418493
if (t_finalize == nil)
419494
return;
420-
495+
496+
// Update the current external var.
497+
s_current_external = this;
498+
421499
t_finalize();
500+
501+
// Unset the current external var.
502+
s_current_external = nil;
422503
}
423504

424505
const char *MCExternalV1::GetName(void) const
@@ -454,7 +535,14 @@ Exec_stat MCExternalV1::Handle(MCObject *p_context, Handler_type p_type, uint32_
454535
t_handler = &m_info -> handlers[p_index];
455536
if (t_handler -> type != t_type)
456537
return ES_NOT_HANDLED;
457-
538+
539+
// If the external is not licensed (as a whole) then we throw the unlicensed error.
540+
if (!m_licensed)
541+
{
542+
MCeerror -> add(EE_EXTERNAL_UNLICENSED, 0, 0, m_info -> name);
543+
return ES_ERROR;
544+
}
545+
458546
Exec_stat t_stat;
459547
t_stat = ES_NORMAL;
460548

@@ -508,10 +596,25 @@ Exec_stat MCExternalV1::Handle(MCObject *p_context, Handler_type p_type, uint32_
508596
MCVariableValue t_result;
509597
t_result . set_temporary();
510598
t_result . assign_empty();
511-
599+
600+
// Update the current external var.
601+
s_current_external = this;
602+
512603
// Invoke the external handler. If 'false' is returned, treat the result as a
513604
// string value containing an error hint.
514-
if ((t_handler -> handler)(t_parameter_vars, t_parameter_count, &t_result))
605+
bool t_success;
606+
t_success = (t_handler -> handler)(t_parameter_vars, t_parameter_count, &t_result);
607+
608+
// Unset the current external var.
609+
s_current_external = nil;
610+
611+
// If a license check failed during the call, then we always throw an error.
612+
if (!m_was_licensed)
613+
{
614+
MCeerror -> add(EE_EXTERNAL_UNLICENSED, 0, 0, m_info -> name);
615+
t_stat = ES_ERROR;
616+
}
617+
else if (t_success)
515618
MCresult -> getvalue() . exchange(t_result);
516619
else
517620
{
@@ -530,6 +633,11 @@ Exec_stat MCExternalV1::Handle(MCObject *p_context, Handler_type p_type, uint32_
530633
return t_stat;
531634
}
532635

636+
void MCExternalV1::SetWasLicensed(bool p_value)
637+
{
638+
m_was_licensed = p_value;
639+
}
640+
533641
////////////////////////////////////////////////////////////////////////////////
534642

535643
MCExternal *MCExternalCreateV1(void)
@@ -1033,6 +1141,9 @@ static MCExternalError MCExternalContextQuery(MCExternalContextQueryTag op, void
10331141
*(MCObjectHandle **)result = t_handle;
10341142
}
10351143
break;
1144+
case kMCExternalContextQueryHasLicenseCheck:
1145+
*(bool *)result = true;
1146+
break;
10361147
default:
10371148
return kMCExternalErrorInvalidContextQuery;
10381149
}
@@ -2046,6 +2157,44 @@ static MCExternalError MCExternalInterfaceQuery(MCExternalInterfaceQueryTag op,
20462157
return kMCExternalErrorNone;
20472158
}
20482159

2160+
2161+
////////////////////////////////////////////////////////////////////////////////
2162+
2163+
MCExternalError MCExternalLicenseCheckEdition(unsigned int p_options, unsigned int p_min_edition)
2164+
{
2165+
unsigned int t_current_edition;
2166+
switch(MClicenseparameters . license_class)
2167+
{
2168+
case kMCLicenseClassNone:
2169+
t_current_edition = kMCExternalLicenseTypeNone;
2170+
break;
2171+
2172+
case kMCLicenseClassCommunity:
2173+
t_current_edition = kMCExternalLicenseTypeCommunity;
2174+
break;
2175+
2176+
case kMCLicenseClassCommercial:
2177+
t_current_edition = kMCExternalLicenseTypeIndy;
2178+
break;
2179+
2180+
case kMCLicenseClassProfessional:
2181+
t_current_edition = kMCExternalLicenseTypeBusiness;
2182+
break;
2183+
2184+
default:
2185+
abort();
2186+
break;
2187+
}
2188+
2189+
if (t_current_edition < p_min_edition)
2190+
{
2191+
s_current_external -> SetWasLicensed(false);
2192+
return kMCExternalErrorUnlicensed;
2193+
}
2194+
2195+
return kMCExternalErrorNone;
2196+
}
2197+
20492198
////////////////////////////////////////////////////////////////////////////////
20502199

20512200
MCExternalInterface g_external_interface =
@@ -2092,6 +2241,12 @@ MCExternalInterface g_external_interface =
20922241
// for the outside world.
20932242
MCExternalContextEvaluate,
20942243
MCExternalContextExecute,
2244+
2245+
// This is the new 'ContextQuery' call in 7+, it is unimplemented in 6.7.
2246+
nil,
2247+
2248+
// MW-2016-02-17: [[ LicenseCheck ]] Declare the check call.
2249+
MCExternalLicenseCheckEdition,
20952250
};
20962251

20972252
////////////////////////////////////////////////////////////////////////////////

0 commit comments

Comments
 (0)