GCC Code Coverage Report


Directory: avs_core/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 1.1% 14 / 0 / 1329
Functions: 1.3% 3 / 0 / 236
Branches: 0.6% 14 / 0 / 2491

core/parser/script.cpp
Line Branch Exec Source
1 // Avisynth v2.5. Copyright 2002 Ben Rudiak-Gould et al.
2 // http://avisynth.nl
3
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 2 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit
17 // http://www.gnu.org/copyleft/gpl.html .
18 //
19 // Linking Avisynth statically or dynamically with other modules is making a
20 // combined work based on Avisynth. Thus, the terms and conditions of the GNU
21 // General Public License cover the whole combination.
22 //
23 // As a special exception, the copyright holders of Avisynth give you
24 // permission to link Avisynth with independent modules that communicate with
25 // Avisynth solely through the interfaces defined in avisynth.h, regardless of the license
26 // terms of these independent modules, and to copy and distribute the
27 // resulting combined work under terms of your choice, provided that
28 // every copy of the combined work is accompanied by a complete copy of
29 // the source code of Avisynth (the version of Avisynth used to produce the
30 // combined work), being distributed under the terms of the GNU General
31 // Public License plus this exception. An independent module is a module
32 // which is not derived from or based on Avisynth, such as 3rd-party filters,
33 // import and export plugins, or graphical user interfaces.
34
35
36 #include "script.h"
37 #include <time.h>
38 #include <cstdio>
39 #include <cstdlib>
40 #include <cmath>
41 #include <vector>
42 #include <fstream>
43 #include <memory>
44 #include <limits>
45 #include <bitset>
46
47 #ifdef AVS_WINDOWS
48 #include <io.h>
49 #include <avs/win.h>
50 #else
51 #include <avs/posix.h>
52 #include "os/win32_string_compat.h"
53 #include <dirent.h>
54 #endif
55
56 #include <avs/filesystem.h>
57 #include <avs/minmax.h>
58 #include <new>
59 #include "../internal.h"
60 #include "../Prefetcher.h"
61 #include "../InternalEnvironment.h"
62 #include "../strings.h"
63 #include <map>
64 #include <string>
65 #include <utility>
66 #define __STDC_FORMAT_MACROS
67 #include <inttypes.h>
68 #include <algorithm>
69 #include <cstring>
70 #include <cctype>
71
72 #ifndef MINGW_HAS_SECURE_API
73 #define sprintf_s sprintf
74 #endif
75
76
77
78 /********************************************************************
79 ***** Declare index of new filters for Avisynth's filter engine *****
80 ********************************************************************/
81
82
83 extern const AVSFunction Script_functions[] = {
84 { "muldiv", BUILTIN_FUNC_PREFIX, "iii", Muldiv },
85
86 { "floor", BUILTIN_FUNC_PREFIX, "f", Floor },
87 { "ceil", BUILTIN_FUNC_PREFIX, "f", Ceil },
88 { "round", BUILTIN_FUNC_PREFIX, "f", Round },
89
90 { "acos", BUILTIN_FUNC_PREFIX, "f", Acos },
91 { "asin", BUILTIN_FUNC_PREFIX, "f", Asin },
92 { "atan", BUILTIN_FUNC_PREFIX, "f", Atan },
93 { "atan2", BUILTIN_FUNC_PREFIX, "ff", Atan2 },
94 { "cos", BUILTIN_FUNC_PREFIX, "f", Cos },
95 { "cosh", BUILTIN_FUNC_PREFIX, "f", Cosh },
96 { "exp", BUILTIN_FUNC_PREFIX, "f", Exp },
97 { "fmod", BUILTIN_FUNC_PREFIX, "ff", Fmod },
98 { "log", BUILTIN_FUNC_PREFIX, "f", Log },
99 { "log10", BUILTIN_FUNC_PREFIX, "f", Log10 },
100 { "pow", BUILTIN_FUNC_PREFIX, "ff", Pow },
101 { "sin", BUILTIN_FUNC_PREFIX, "f", Sin },
102 { "sinh", BUILTIN_FUNC_PREFIX, "f", Sinh },
103 { "tan", BUILTIN_FUNC_PREFIX, "f", Tan },
104 { "tanh", BUILTIN_FUNC_PREFIX, "f", Tanh },
105 { "sqrt", BUILTIN_FUNC_PREFIX, "f", Sqrt },
106
107
108 { "abs", BUILTIN_FUNC_PREFIX, "i", Abs },
109 { "abs", BUILTIN_FUNC_PREFIX, "f", FAbs },
110 { "pi", BUILTIN_FUNC_PREFIX, "", Pi },
111 #ifdef OPT_ScriptFunctionTau
112 { "tau", BUILTIN_FUNC_PREFIX, "", Tau },
113 #endif
114 { "sign", BUILTIN_FUNC_PREFIX, "f",Sign},
115
116 { "bitand", BUILTIN_FUNC_PREFIX, "ii",BitAnd},
117 { "bitnot", BUILTIN_FUNC_PREFIX, "i",BitNot},
118 { "bitor", BUILTIN_FUNC_PREFIX, "ii",BitOr},
119 { "bitxor", BUILTIN_FUNC_PREFIX, "ii",BitXor},
120 // v11
121 { "bitand64", BUILTIN_FUNC_PREFIX, "ii",BitAnd64},
122 { "bitnot64", BUILTIN_FUNC_PREFIX, "i",BitNot64},
123 { "bitor64", BUILTIN_FUNC_PREFIX, "ii",BitOr64},
124 { "bitxor64", BUILTIN_FUNC_PREFIX, "ii",BitXor64},
125
126 { "bitlshift", BUILTIN_FUNC_PREFIX, "ii",BitLShift},
127 { "bitlshiftl", BUILTIN_FUNC_PREFIX, "ii",BitLShift},
128 { "bitlshifta", BUILTIN_FUNC_PREFIX, "ii",BitLShift},
129 { "bitlshiftu", BUILTIN_FUNC_PREFIX, "ii",BitLShift},
130 { "bitlshifts", BUILTIN_FUNC_PREFIX, "ii",BitLShift},
131 { "bitshl", BUILTIN_FUNC_PREFIX, "ii",BitLShift},
132 { "bitsal", BUILTIN_FUNC_PREFIX, "ii",BitLShift},
133 // v11 omg under how many names do the same?! keep only two
134 { "bitshl64", BUILTIN_FUNC_PREFIX, "ii",BitLShift64},
135 { "bitsal64", BUILTIN_FUNC_PREFIX, "ii",BitLShift64},
136
137 { "bitrshiftl", BUILTIN_FUNC_PREFIX, "ii",BitRShiftL},
138 { "bitrshifta", BUILTIN_FUNC_PREFIX, "ii",BitRShiftA},
139 { "bitrshiftu", BUILTIN_FUNC_PREFIX, "ii",BitRShiftL},
140 { "bitrshifts", BUILTIN_FUNC_PREFIX, "ii",BitRShiftA},
141 { "bitshr", BUILTIN_FUNC_PREFIX, "ii",BitRShiftL},
142 { "bitsar", BUILTIN_FUNC_PREFIX, "ii",BitRShiftA},
143 // v11
144 { "bitshr64", BUILTIN_FUNC_PREFIX, "ii",BitRShift64L},
145 { "bitsar64", BUILTIN_FUNC_PREFIX, "ii",BitRShift64A},
146
147 { "bitlrotate", BUILTIN_FUNC_PREFIX, "ii",BitRotateL},
148 { "bitrrotate", BUILTIN_FUNC_PREFIX, "ii",BitRotateR},
149 { "bitrol", BUILTIN_FUNC_PREFIX, "ii",BitRotateL},
150 { "bitror", BUILTIN_FUNC_PREFIX, "ii",BitRotateR},
151 // v11
152 { "bitrol64", BUILTIN_FUNC_PREFIX, "ii",BitRotate64L},
153 { "bitror64", BUILTIN_FUNC_PREFIX, "ii",BitRotate64R},
154
155 { "bitchg", BUILTIN_FUNC_PREFIX, "ii",BitChg},
156 { "bitchange", BUILTIN_FUNC_PREFIX, "ii",BitChg},
157 { "bitclr", BUILTIN_FUNC_PREFIX, "ii",BitClr},
158 { "bitclear", BUILTIN_FUNC_PREFIX, "ii",BitClr},
159 { "bitset", BUILTIN_FUNC_PREFIX, "ii",BitSet},
160 { "bittst", BUILTIN_FUNC_PREFIX, "ii",BitTst},
161 { "bittest", BUILTIN_FUNC_PREFIX, "ii",BitTst},
162 { "bitsetcount", BUILTIN_FUNC_PREFIX, "i+",BitSetCount }, // avs+ 180221
163 // v11
164 { "bitchg64", BUILTIN_FUNC_PREFIX, "ii",BitChg64},
165 { "bitclr64", BUILTIN_FUNC_PREFIX, "ii",BitClr64},
166 { "bitset64", BUILTIN_FUNC_PREFIX, "ii",BitSet64},
167 { "bittst64", BUILTIN_FUNC_PREFIX, "ii",BitTst64},
168 { "bitsetcount64", BUILTIN_FUNC_PREFIX, "i+",BitSetCount64 },
169
170 { "lcase", BUILTIN_FUNC_PREFIX, "s",LCase},
171 { "ucase", BUILTIN_FUNC_PREFIX, "s",UCase},
172 { "strlen", BUILTIN_FUNC_PREFIX, "s",StrLen},
173 { "revstr", BUILTIN_FUNC_PREFIX, "s",RevStr},
174 { "leftstr", BUILTIN_FUNC_PREFIX, "si",LeftStr},
175 { "midstr", BUILTIN_FUNC_PREFIX, "si[length]i",MidStr},
176 { "rightstr", BUILTIN_FUNC_PREFIX, "si",RightStr},
177 { "findstr", BUILTIN_FUNC_PREFIX, "ss",FindStr},
178 { "fillstr", BUILTIN_FUNC_PREFIX, "i[]s",FillStr},
179 { "replacestr", BUILTIN_FUNC_PREFIX, "sss[sig]b",ReplaceStr}, // avs+ 161230, case 180222
180 { "trimall", BUILTIN_FUNC_PREFIX, "s",TrimAll }, // avs+ 180225 diff name of clip-function Trim
181 { "trimleft", BUILTIN_FUNC_PREFIX, "s",TrimLeft }, // avs+ 180225
182 { "trimright", BUILTIN_FUNC_PREFIX, "s",TrimRight }, // avs+ 180225
183
184 { "strcmp", BUILTIN_FUNC_PREFIX, "ss",StrCmp},
185 { "strcmpi", BUILTIN_FUNC_PREFIX, "ss",StrCmpi},
186
187 { "rand", BUILTIN_FUNC_PREFIX, "[max]i[scale]b[seed]b", Rand },
188
189 { "Select", BUILTIN_FUNC_PREFIX, "i.+", Select },
190
191 { "nop", BUILTIN_FUNC_PREFIX, "", NOP },
192 { "undefined",BUILTIN_FUNC_PREFIX, "", Undefined },
193
194 { "width", BUILTIN_FUNC_PREFIX, "c", Width },
195 { "height", BUILTIN_FUNC_PREFIX, "c", Height },
196 { "framecount", BUILTIN_FUNC_PREFIX, "c", FrameCount },
197 { "framerate", BUILTIN_FUNC_PREFIX, "c", FrameRate },
198 { "frameratenumerator", BUILTIN_FUNC_PREFIX, "c", FrameRateNumerator },
199 { "frameratedenominator", BUILTIN_FUNC_PREFIX, "c", FrameRateDenominator },
200 { "audiorate", BUILTIN_FUNC_PREFIX, "c", AudioRate },
201 { "audiolength", BUILTIN_FUNC_PREFIX, "c", AudioLength }, // v11: returns real int64
202 { "audiolengthlo", BUILTIN_FUNC_PREFIX, "c[]i", AudioLengthLo }, // audiolength%i
203 { "audiolengthhi", BUILTIN_FUNC_PREFIX, "c[]i", AudioLengthHi }, // audiolength/i
204 { "audiolengths", BUILTIN_FUNC_PREFIX, "c", AudioLengthS }, // as a string
205 { "audiolengthf", BUILTIN_FUNC_PREFIX, "c", AudioLengthF }, // at least this will give an order of the size
206 { "audioduration", BUILTIN_FUNC_PREFIX, "c", AudioDuration }, // In seconds
207 { "audiochannels", BUILTIN_FUNC_PREFIX, "c", AudioChannels },
208 { "audiobits", BUILTIN_FUNC_PREFIX, "c", AudioBits },
209 { "IsAudioFloat", BUILTIN_FUNC_PREFIX, "c", IsAudioFloat },
210 { "IsAudioInt", BUILTIN_FUNC_PREFIX, "c", IsAudioInt },
211
212 { "IsChannelMaskKnown", BUILTIN_FUNC_PREFIX, "c", IsChannelMaskKnown },
213 { "GetChannelMask", BUILTIN_FUNC_PREFIX, "c", GetChannelMask }, // SetChannelMask: see in audio.cpp
214
215 { "IsRGB", BUILTIN_FUNC_PREFIX, "c", IsRGB },
216 { "IsYUY2", BUILTIN_FUNC_PREFIX, "c", IsYUY2 },
217 { "IsYUV", BUILTIN_FUNC_PREFIX, "c", IsYUV },
218 { "IsY8", BUILTIN_FUNC_PREFIX, "c", IsY8 },
219 { "IsYV12", BUILTIN_FUNC_PREFIX, "c", IsYV12 },
220 { "IsYV16", BUILTIN_FUNC_PREFIX, "c", IsYV16 },
221 { "IsYV24", BUILTIN_FUNC_PREFIX, "c", IsYV24 },
222 { "IsYV411", BUILTIN_FUNC_PREFIX, "c", IsYV411 },
223 { "IsPlanar", BUILTIN_FUNC_PREFIX, "c", IsPlanar },
224 { "IsInterleaved", BUILTIN_FUNC_PREFIX, "c", IsInterleaved },
225 { "IsRGB24", BUILTIN_FUNC_PREFIX, "c", IsRGB24 },
226 { "IsRGB32", BUILTIN_FUNC_PREFIX, "c", IsRGB32 },
227 { "IsFieldBased", BUILTIN_FUNC_PREFIX, "c", IsFieldBased },
228 { "IsFrameBased", BUILTIN_FUNC_PREFIX, "c", IsFrameBased },
229 { "GetParity", BUILTIN_FUNC_PREFIX, "c[n]i", GetParity },
230 { "String", BUILTIN_FUNC_PREFIX, ".[]s", String },
231 { "Hex", BUILTIN_FUNC_PREFIX, "i[width]i", Hex }, // avs+ 20180222 new width parameter
232 { "Func", BUILTIN_FUNC_PREFIX, "n", Func },
233 { "Format", BUILTIN_FUNC_PREFIX, "s.*", FormatString },
234
235 { "IsBool", BUILTIN_FUNC_PREFIX, ".", IsBool },
236 { "IsInt", BUILTIN_FUNC_PREFIX, ".", IsInt },
237 { "IsLongStrict", BUILTIN_FUNC_PREFIX, ".", IsLongStrict }, // v11
238 { "IsFloat", BUILTIN_FUNC_PREFIX, ".", IsFloat },
239 { "IsFloatFStrict", BUILTIN_FUNC_PREFIX, ".", IsFloatfStrict }, // v11
240 { "IsString", BUILTIN_FUNC_PREFIX, ".", IsString },
241 { "IsClip", BUILTIN_FUNC_PREFIX, ".", IsClip },
242 { "IsFunction", BUILTIN_FUNC_PREFIX, ".", IsFunction },
243 { "Defined", BUILTIN_FUNC_PREFIX, ".", Defined },
244 { "TypeName", BUILTIN_FUNC_PREFIX, ".", TypeName },
245
246 { "Default", BUILTIN_FUNC_PREFIX, "..", Default },
247
248 { "Eval", BUILTIN_FUNC_PREFIX, "s[name]s", Eval },
249 { "Eval", BUILTIN_FUNC_PREFIX, "cs[name]s", EvalOop },
250 { "Apply", BUILTIN_FUNC_PREFIX, "s.*", Apply },
251 { "Import", BUILTIN_FUNC_PREFIX, "s+[utf8]b", Import },
252
253 { "Assert", BUILTIN_FUNC_PREFIX, "b[message]s", Assert },
254 { "Assert", BUILTIN_FUNC_PREFIX, "s", AssertEval },
255
256 { "SetMemoryMax", BUILTIN_FUNC_PREFIX, "[]i[type]i[index]i", SetMemoryMax }, // Neo
257 { "SetWorkingDir", BUILTIN_FUNC_PREFIX, "s", SetWorkingDir },
258 { "Exist", BUILTIN_FUNC_PREFIX, "s[utf8]b", Exist },
259
260 { "Chr", BUILTIN_FUNC_PREFIX, "i", AVSChr },
261 { "Ord", BUILTIN_FUNC_PREFIX, "s", AVSOrd },
262 { "Time", BUILTIN_FUNC_PREFIX, "s", AVSTime },
263 { "Spline", BUILTIN_FUNC_PREFIX, "[x]ff+[cubic]b", Spline },
264
265 // parameter is 'f' which cover any integer or float numbers
266 { "int", BUILTIN_FUNC_PREFIX, "f", Int },
267 { "frac", BUILTIN_FUNC_PREFIX, "f", Frac },
268 { "float", BUILTIN_FUNC_PREFIX, "f", Float },
269 { "inti", BUILTIN_FUNC_PREFIX, "f", IntI }, // v11
270 { "long", BUILTIN_FUNC_PREFIX, "f", Long }, // v11
271 { "floatf", BUILTIN_FUNC_PREFIX, "f", Floatf }, // v11
272 { "double", BUILTIN_FUNC_PREFIX, "f", Double }, // v11
273
274 { "value", BUILTIN_FUNC_PREFIX, "s",Value},
275 { "hexvalue", BUILTIN_FUNC_PREFIX, "s[pos]i",HexValue}, // avs+ 20180222 new pos parameter
276 { "hexvalue64", BUILTIN_FUNC_PREFIX, "s[pos]i",HexValue64 }, // v11
277
278 { "VersionNumber", BUILTIN_FUNC_PREFIX, "", VersionNumber },
279 { "VersionString", BUILTIN_FUNC_PREFIX, "", VersionString },
280 { "IsVersionOrGreater", BUILTIN_FUNC_PREFIX, "[majorversion]i[minorVersion]i[bugfixVersion]i", IsVersionOrGreater },
281
282 { "HasVideo", BUILTIN_FUNC_PREFIX, "c", HasVideo },
283 { "HasAudio", BUILTIN_FUNC_PREFIX, "c", HasAudio },
284
285 { "Min", BUILTIN_FUNC_PREFIX, "f+", AvsMin },
286 { "Max", BUILTIN_FUNC_PREFIX, "f+", AvsMax },
287
288 { "ScriptName", BUILTIN_FUNC_PREFIX, "", ScriptName },
289 { "ScriptFile", BUILTIN_FUNC_PREFIX, "", ScriptFile },
290 { "ScriptDir", BUILTIN_FUNC_PREFIX, "", ScriptDir },
291 { "ScriptNameUtf8", BUILTIN_FUNC_PREFIX, "", ScriptNameUtf8 },
292 { "ScriptFileUtf8", BUILTIN_FUNC_PREFIX, "", ScriptFileUtf8 },
293 { "ScriptDirUtf8", BUILTIN_FUNC_PREFIX, "", ScriptDirUtf8 },
294
295 { "PixelType", BUILTIN_FUNC_PREFIX, "c", PixelType },
296
297 { "AddAutoloadDir", BUILTIN_FUNC_PREFIX, "s[toFront]b[utf8]b", AddAutoloadDir },
298 { "ClearAutoloadDirs", BUILTIN_FUNC_PREFIX, "", ClearAutoloadDirs },
299 { "ListAutoloadDirs", BUILTIN_FUNC_PREFIX, "[utf8]b", ListAutoloadDirs },
300 { "AutoloadPlugins", BUILTIN_FUNC_PREFIX, "", AutoloadPlugins },
301 { "FunctionExists", BUILTIN_FUNC_PREFIX, "s", FunctionExists },
302 { "InternalFunctionExists", BUILTIN_FUNC_PREFIX, "s", InternalFunctionExists },
303
304 { "SetFilterMTMode", BUILTIN_FUNC_PREFIX, "si[force]b", SetFilterMTMode },
305 { "Prefetch", BUILTIN_FUNC_PREFIX, "c[threads]i[frames]i", Prefetcher::Create },
306 { "SetLogParams", BUILTIN_FUNC_PREFIX, "[target]s[level]i", SetLogParams },
307 { "LogMsg", BUILTIN_FUNC_PREFIX, "si", LogMsg },
308 { "SetCacheMode", BUILTIN_FUNC_PREFIX, "[mode]i", SetCacheMode }, // Neo
309 { "SetDeviceOpt", BUILTIN_FUNC_PREFIX, "[opt]i[val]i", SetDeviceOpt }, // Neo
310 { "SetMaxCPU", BUILTIN_FUNC_PREFIX, "s", SetMaxCPU }, // 20200331
311 { "SetFilterProp", BUILTIN_FUNC_PREFIX, "ss.[mode]i", SetFilterProp }, // any type (int/float/bool/string/fn/undef); clip rejected in body
312 { "SetFilterProp", BUILTIN_FUNC_PREFIX, "ss.s.[mode]i", SetFilterProp }, // conditional: when param==match, inject key=value
313 { "GetFilterProps", BUILTIN_FUNC_PREFIX, "", GetFilterProps },
314 { "SetFilterPropPassthrough", BUILTIN_FUNC_PREFIX, "s", SetFilterPropPassthrough },
315
316 { "IsY", BUILTIN_FUNC_PREFIX, "c", IsY },
317 { "Is420", BUILTIN_FUNC_PREFIX, "c", Is420 },
318 { "Is422", BUILTIN_FUNC_PREFIX, "c", Is422 },
319 { "Is444", BUILTIN_FUNC_PREFIX, "c", Is444 },
320 { "IsRGB48", BUILTIN_FUNC_PREFIX, "c", IsRGB48 },
321 { "IsRGB64", BUILTIN_FUNC_PREFIX, "c", IsRGB64 },
322 { "ComponentSize", BUILTIN_FUNC_PREFIX, "c", ComponentSize },
323 { "BitsPerComponent", BUILTIN_FUNC_PREFIX, "c", BitsPerComponent },
324 { "IsYUVA", BUILTIN_FUNC_PREFIX, "c", IsYUVA },
325 { "IsPlanarRGB", BUILTIN_FUNC_PREFIX, "c", IsPlanarRGB },
326 { "IsPlanarRGBA", BUILTIN_FUNC_PREFIX, "c", IsPlanarRGBA },
327 { "ColorSpaceNameToPixelType", BUILTIN_FUNC_PREFIX, "s", ColorSpaceNameToPixelType },
328 { "NumComponents", BUILTIN_FUNC_PREFIX, "c", NumComponents }, // r2348+
329 { "HasAlpha", BUILTIN_FUNC_PREFIX, "c", HasAlpha }, // r2348+
330 { "IsPackedRGB", BUILTIN_FUNC_PREFIX, "c", IsPackedRGB }, // r2348+
331 { "IsVideoFloat", BUILTIN_FUNC_PREFIX, "c", IsVideoFloat }, // r2435+
332
333 { "GetProcessInfo", BUILTIN_FUNC_PREFIX, "[type]i", GetProcessInfo }, // 170526-
334 #ifdef AVS_WINDOWS
335 { "StrToUtf8", BUILTIN_FUNC_PREFIX, "s", StrToUtf8 }, // 170601-
336 { "StrFromUtf8", BUILTIN_FUNC_PREFIX, "s", StrFromUtf8 }, // 170601-
337 #endif
338
339 { "IsFloatUvZeroBased", BUILTIN_FUNC_PREFIX, "", IsFloatUvZeroBased }, // 180516-
340 { "BuildPixelType", BUILTIN_FUNC_PREFIX, "[family]s[bits]i[chroma]i[compat]b[oldnames]b[sample_clip]c", BuildPixelType }, // 180517-
341 { "VarExist", BUILTIN_FUNC_PREFIX, "s", VarExist }, // 180606-
342
343
344 // Creates script array from zero or more anything.
345 // Direct array constant syntax e.g. x = [arg1,arg2,...] is translated to x = Array(arg1,arg2,...)
346 { "Array", BUILTIN_FUNC_PREFIX, ".*", ArrayCreate },
347 { "IsArray", BUILTIN_FUNC_PREFIX, ".", IsArray },
348 // dictionary type array indexing
349 { "ArrayGet", BUILTIN_FUNC_PREFIX, ".s", ArrayGet },
350 // classic array indexing background helper: e.g. a[3,4] -> ArrayGet(a, [2,3])
351 { "ArrayGet", BUILTIN_FUNC_PREFIX, ".i+", ArrayGet }, // .+i+ syntax is not possible.
352 // length can be zero
353 { "ArraySize", BUILTIN_FUNC_PREFIX, ".", ArraySize },
354 { "ArrayIns", BUILTIN_FUNC_PREFIX, "..i+", ArrayIns, (void*)0 },
355 { "ArrayAdd", BUILTIN_FUNC_PREFIX, "..i*", ArrayIns, (void*)1 },
356 { "ArraySet", BUILTIN_FUNC_PREFIX, "..i+", ArrayIns, (void*)2 },
357 { "ArrayDel", BUILTIN_FUNC_PREFIX, ".i+", ArrayIns, (void*)3 },
358 { "ArraySort", BUILTIN_FUNC_PREFIX, ".", ArraySort, (void*)0 },
359
360 /*
361 { "IsArrayOf", BUILTIN_FUNC_PREFIX, ".s", IsArrayOf },
362 */
363 { 0 }
364 };
365
366
367 /**********************************
368 ******* Script Function ******
369 *********************************/
370
371 ScriptFunction::ScriptFunction( const PExpression& _body, const bool* _param_floats,
372 const char** _param_names, int param_count )
373 : body(_body)
374 {
375 param_floats = new bool[param_count];
376 memcpy(param_floats, _param_floats, param_count * sizeof(const bool));
377
378 param_names = new const char* [param_count];
379 memcpy(param_names, _param_names, param_count * sizeof(const char*));
380 }
381
382 static bool is_within_int_in_float32_range(int64_t value) {
383 return value >= -16777216 && value <= 16777216;
384 }
385
386 AVSValue ScriptFunction::Execute(AVSValue args, void* user_data, IScriptEnvironment* env)
387 {
388 ScriptFunction* self = (ScriptFunction*)user_data;
389 env->PushContext();
390 for (int i=0; i<args.ArraySize(); ++i)
391 env->SetVar(self->param_names[i],
392 // Same as in ScriptFunction::Execute and AVSValue FunctionInstance::Execute
393
394 // force float args that are actually long/int (int64) to be float/double (depending on the range)
395 // opportunity to fit into the smaller float size
396 (self->param_floats[i] && args[i].IsInt()) ?
397 is_within_int_in_float32_range(args[i].AsLong()) ? (float)args[i].AsLong() : (double)args[i].AsLong() :
398 args[i]
399 );
400
401 AVSValue result;
402 try {
403 result = self->body->Evaluate(env);
404 }
405 catch (...) {
406 env->PopContext();
407 throw;
408 }
409
410 env->PopContext();
411 return result;
412 }
413
414 void ScriptFunction::Delete(void* self, IScriptEnvironment*)
415 {
416 delete (ScriptFunction*)self;
417 }
418
419 /***********************************
420 ******* Helper Functions ******
421 **********************************/
422
423 #ifdef AVS_WINDOWS
424
425 std::wstring CWDChanger::GetCurrentWorkingDirectory() {
426 DWORD length = GetCurrentDirectoryW(0, nullptr);
427 if (length == 0) return {};
428
429 std::wstring buffer(length, L'\0');
430 if (GetCurrentDirectoryW(length, &buffer[0]) == 0) return {};
431
432 // Remove trailing null character if present
433 if (!buffer.empty() && buffer.back() == L'\0') {
434 buffer.pop_back();
435 }
436
437 return buffer;
438 }
439
440 #else
441
442 7 std::string CWDChanger::GetCurrentWorkingDirectory() {
443 char buffer[FILENAME_MAX];
444
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 7 times.
7 if (getcwd(buffer, sizeof(buffer)) == nullptr) return {};
445
446
1/2
✓ Branch 7 → 8 taken 7 times.
✗ Branch 7 → 12 not taken.
14 return std::string(buffer);
447 }
448
449 #endif
450
451
452 #ifdef AVS_WINDOWS
453 void CWDChanger::Init(const wchar_t* new_cwd)
454 {
455 // works in unicode internally
456 uint32_t cwdLen = GetCurrentDirectoryW(0, NULL);
457 old_working_directory = std::make_unique<wchar_t[]>(cwdLen); // instead of new wchar_t[cwdLen];
458 uint32_t save_cwd_success = GetCurrentDirectoryW(cwdLen, old_working_directory.get());
459 bool set_cwd_success = SetCurrentDirectoryW(new_cwd);
460 restore = (save_cwd_success && set_cwd_success);
461 }
462
463 CWDChanger::CWDChanger(const wchar_t* new_cwd)
464 {
465 Init(new_cwd);
466 }
467
468 // utf8 on Windows as well
469 CWDChanger::CWDChanger(const char* new_cwd_utf8)
470 {
471 auto new_cwd_w = Utf8ToWideChar(new_cwd_utf8);
472 Init(new_cwd_w.get());
473 }
474
475 CWDChanger::~CWDChanger(void)
476 {
477 if (restore)
478 SetCurrentDirectoryW(old_working_directory.get());
479 }
480
481 DllDirChanger::DllDirChanger(const char* new_dir)
482 {
483 uint32_t len = GetDllDirectory (0, NULL);
484 old_directory = std::make_unique<char[]>(len + 1); // instead of new char[len+1]
485 uint32_t save_success = GetDllDirectory (len, old_directory.get());
486 bool set_success = SetDllDirectory(new_dir);
487 restore = (save_success && set_success);
488 }
489
490 DllDirChanger::~DllDirChanger(void)
491 {
492 if (restore)
493 SetDllDirectory(old_directory.get());
494 }
495 #else // copied from AvxSynth
496 CWDChanger::CWDChanger(const char* new_cwd)
497 {
498
499 char* path = getcwd(old_working_directory, FILENAME_MAX);
500 bool save_cwd_success = (NULL != path);
501 bool set_cwd_success = (0 == chdir(new_cwd));
502 restore = (save_cwd_success && set_cwd_success);
503 }
504
505 CWDChanger::~CWDChanger(void)
506 {
507 if (restore)
508 chdir(old_working_directory);
509 }
510 #endif
511
512
513 AVSValue Assert(AVSValue args, void*, IScriptEnvironment* env)
514 {
515 if (!args[0].AsBool())
516 env->ThrowError("%s", args[1].Defined() ? args[1].AsString() : "Assert: assertion failed");
517 return AVSValue();
518 }
519
520 AVSValue AssertEval(AVSValue args, void*, IScriptEnvironment* env)
521 {
522 const char* pred = args[0].AsString();
523 AVSValue eval_args[] = { args[0].AsString(), "asserted expression" };
524 AVSValue val = env->Invoke("Eval", AVSValue(eval_args, 2));
525 if (!val.IsBool())
526 env->ThrowError("Assert: expression did not evaluate to true or false: \"%s\"", pred);
527 if (!val.AsBool())
528 env->ThrowError("Assert: assertion failed: \"%s\"", pred);
529 return AVSValue();
530 }
531
532 AVSValue Eval(AVSValue args, void*, IScriptEnvironment* env)
533 {
534 const char *filename = args[1].AsString(0);
535 if (filename) filename = env->SaveString(filename);
536 ScriptParser parser(env, args[0].AsString(), filename);
537 PExpression exp = parser.Parse();
538 return exp->Evaluate(env);
539 }
540
541 AVSValue Apply(AVSValue args, void*, IScriptEnvironment* env)
542 {
543 return env->Invoke(args[0].AsString(), args[1]);
544 }
545
546 AVSValue EvalOop(AVSValue args, void*, IScriptEnvironment* env)
547 {
548 AVSValue prev_last = env->GetVarDef("last"); // Store previous last
549 env->SetVar("last", args[0]); // Set implicit last
550
551 AVSValue result;
552 try {
553 result = Eval(AVSValue(&args[1], 2), 0, env);
554 }
555 catch(...) {
556 env->SetVar("last", prev_last); // Restore implicit last
557 throw;
558 }
559 env->SetVar("last", prev_last); // Restore implicit last
560 return result;
561 }
562
563 AVSValue Import(AVSValue args, void*, IScriptEnvironment* env)
564 {
565 // called as s+ or s+[Utf8]b
566 const bool bHasUTF8param = args.IsArray() && args.ArraySize() == 2 && args[1].IsBool();
567 const bool bUtf8 = bHasUTF8param ? args[1].AsBool(false) : false;
568
569 args = args[0];
570 AVSValue result;
571
572 InternalEnvironment *envi = static_cast<InternalEnvironment*>(env);
573 const bool MainScript = (envi->IncrImportDepth() == 1);
574
575 AVSValue lastScriptName = env->GetVarDef("$ScriptName$");
576 AVSValue lastScriptFile = env->GetVarDef("$ScriptFile$");
577 AVSValue lastScriptDir = env->GetVarDef("$ScriptDir$");
578
579 AVSValue lastScriptNameUtf8 = env->GetVarDef("$ScriptNameUtf8$");
580 AVSValue lastScriptFileUtf8 = env->GetVarDef("$ScriptFileUtf8$");
581 AVSValue lastScriptDirUtf8 = env->GetVarDef("$ScriptDirUtf8$");
582
583 for (int i = 0; i < args.ArraySize(); ++i) {
584 const char* script_name = args[i].AsString();
585
586 #ifdef AVS_WINDOWS
587 /* Linux, macOS, pretty much every OS aside from Windows uses
588 UTF-8 pervasively and by default, making all the Ansi<->Unicode
589 stuff we have to specially handle on Windows (which uses UTF-16
590 when it does 'Unicode', further complicating things if you don't
591 force UTF-8) irrelevant. */
592
593 // Handling utf8 and ansi, working in wchar_t internally
594 // filename and path can be full unicode
595 // unicode input can come from CAVIFileSynth
596
597 std::unique_ptr<wchar_t[]> full_path_w;
598 wchar_t *file_part_w;
599
600 // make wchar_t full path strnig from either ansi or utf8
601 auto script_name_w = !bUtf8 ? AnsiToWideChar(script_name) : Utf8ToWideChar(script_name);
602
603 // Long (>MAX_PATH) path support starting in Windows 10, version 1607.
604 if (wcschr(script_name_w.get(), '\\') || wcschr(script_name_w.get(), '/')) {
605 DWORD len = GetFullPathNameW(script_name_w.get(), 0, NULL, NULL); // buffer size for path + terminating zero
606 full_path_w = std::make_unique<wchar_t[]>(len);
607 len = GetFullPathNameW(script_name_w.get(), len, full_path_w.get(), &file_part_w);
608 if (len == 0) {
609 auto script_name_utf8 = WideCharToUtf8(script_name_w.get());
610 env->ThrowError("Import: unable to open \"%s\" (path invalid?), error=0x%x", script_name_utf8.get(), GetLastError());
611 }
612 }
613 else {
614 DWORD len = SearchPathW(NULL, script_name_w.get(), NULL, 0, NULL, NULL); // buffer size for path + terminating zero
615 full_path_w = std::make_unique<wchar_t[]>(len);
616 len = SearchPathW(NULL, script_name_w.get(), NULL, len, full_path_w.get(), &file_part_w);
617 if (len == 0) {
618 auto script_name_utf8 = WideCharToUtf8(script_name_w.get());
619 env->ThrowError("Import: unable to locate \"%s\" (try specifying a path), error=0x%x", script_name_utf8.get(), GetLastError());
620 }
621 }
622
623 // back to 8 bit Ansi and Utf8
624 auto full_path = WideCharToAnsi(full_path_w.get());
625 auto full_path_utf8 = WideCharToUtf8(full_path_w.get());
626 auto file_part = WideCharToAnsi(file_part_w);
627 auto file_part_utf8 = WideCharToUtf8(file_part_w);
628 size_t dir_part_len = wcslen(full_path_w.get()) - wcslen(file_part_w);
629 auto dir_part = WideCharToAnsi_maxn(full_path_w.get(), dir_part_len);
630 auto dir_part_utf8 = WideCharToUtf8_maxn(full_path_w.get(), dir_part_len);
631
632 // supply L"\\\\?\\" if necessary for long file path support
633 std::wstring full_path_ex = std::wstring(full_path_w.get());
634 if (full_path_ex.length() > FILENAME_MAX && full_path_ex.substr(0, 4) != L"\\\\?\\")
635 full_path_ex = L"\\\\?\\" + full_path_ex;
636
637 HANDLE h = ::CreateFileW(full_path_ex.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
638 if (h == INVALID_HANDLE_VALUE)
639 env->ThrowError("Import: couldn't open \"%s\"", full_path.get());
640
641 env->SetGlobalVar("$ScriptName$", env->SaveString(full_path.get()));
642 env->SetGlobalVar("$ScriptFile$", env->SaveString(file_part.get()));
643 env->SetGlobalVar("$ScriptDir$", env->SaveString(dir_part.get()));
644 env->SetGlobalVar("$ScriptNameUtf8$", env->SaveString(full_path_utf8.get()));
645 env->SetGlobalVar("$ScriptFileUtf8$", env->SaveString(file_part_utf8.get()));
646 env->SetGlobalVar("$ScriptDirUtf8$", env->SaveString(dir_part_utf8.get()));
647 if (MainScript)
648 {
649 env->SetGlobalVar("$MainScriptName$", env->SaveString(full_path.get()));
650 env->SetGlobalVar("$MainScriptFile$", env->SaveString(file_part.get()));
651 env->SetGlobalVar("$MainScriptDir$", env->SaveString(dir_part.get()));
652 env->SetGlobalVar("$MainScriptNameUtf8$", env->SaveString(full_path_utf8.get()));
653 env->SetGlobalVar("$MainScriptFileUtf8$", env->SaveString(file_part_utf8.get()));
654 env->SetGlobalVar("$MainScriptDirUtf8$", env->SaveString(dir_part_utf8.get()));
655 }
656
657 *file_part_w = 0; // trunc full_path_w to dir-only
658 CWDChanger change_cwd(full_path_w.get());
659 // end of filename parsing / file open things
660
661 DWORD size = GetFileSize(h, NULL);
662 std::vector<char> buf(size + 1, 0);
663 bool status = ReadFile(h, buf.data(), size, &size, NULL);
664 CloseHandle(h);
665 if (!status)
666 env->ThrowError("Import: unable to read \"%s\"", script_name);
667
668 // Give poor Unicode users a hint they need to use ANSI encoding import"
669 if (size >= 2) {
670 unsigned char* q = reinterpret_cast<unsigned char*>(buf.data());
671
672 if ((q[0] == 0xFF && q[1] == 0xFE) || (q[0] == 0xFE && q[1] == 0xFF))
673 env->ThrowError("Import: Unicode source files are not supported, "
674 "re-save script with ANSI or UTF8 w/o BOM encoding! : \"%s\"", script_name);
675
676 if (q[0] == 0xEF && q[1] == 0xBB && q[2] == 0xBF)
677 env->ThrowError("Import: UTF-8 source files with BOM are not supported, "
678 "re-save script with ANSI or UTF8 w/o BOM encoding! : \"%s\"", script_name);
679 }
680
681 #else // adapted from AvxSynth
682 std::string file_part = fs::path(script_name).filename().string();
683 std::string full_path = fs::path(script_name).remove_filename();
684 std::string dir_part = fs::path(script_name).parent_path();
685
686 FILE* h = fopen(script_name, "r");
687 if(NULL == h)
688 env->ThrowError("Import: couldn't open \"%s\"", script_name );
689
690 env->SetGlobalVar("$ScriptName$", env->SaveString(script_name));
691 env->SetGlobalVar("$ScriptFile$", env->SaveString(file_part.c_str()));
692 env->SetGlobalVar("$ScriptDir$", env->SaveString(full_path.c_str()));
693 env->SetGlobalVar("$ScriptNameUtf8$", env->SaveString(script_name));
694 env->SetGlobalVar("$ScriptFileUtf8$", env->SaveString(file_part.c_str()));
695 env->SetGlobalVar("$ScriptDirUtf8$", env->SaveString(full_path.c_str()));
696 if (MainScript)
697 {
698 env->SetGlobalVar("$MainScriptName$", env->SaveString(script_name));
699 env->SetGlobalVar("$MainScriptFile$", env->SaveString(file_part.c_str()));
700 env->SetGlobalVar("$MainScriptDir$", env->SaveString(full_path.c_str()));
701 env->SetGlobalVar("$MainScriptNameUtf8$", env->SaveString(script_name));
702 env->SetGlobalVar("$MainScriptFileUtf8$", env->SaveString(file_part.c_str()));
703 env->SetGlobalVar("$MainScriptDirUtf8$", env->SaveString(full_path.c_str()));
704 }
705
706 //*file_part = 0; // trunc full_path to dir-only
707 CWDChanger change_cwd(full_path.c_str());
708 // end of filename parsing / file open things
709
710 fseek(h, 0, SEEK_END);
711 size_t size = ftell(h);
712 fseek(h, 0, SEEK_SET);
713
714 std::vector<char> buf(size + 1, 0);
715 if(size != fread(buf.data(), 1, size, h))
716 env->ThrowError("Import: unable to read \"%s\"", script_name);
717
718 fclose(h);
719 #endif
720
721 buf[size] = 0;
722 AVSValue eval_args[] = { buf.data(), script_name };
723 result = env->Invoke("Eval", AVSValue(eval_args, 2));
724 //env->ThrowError("Import: test %s size %d\n", buf.data(), (int)size);
725 }
726
727 env->SetGlobalVar("$ScriptName$", lastScriptName);
728 env->SetGlobalVar("$ScriptFile$", lastScriptFile);
729 env->SetGlobalVar("$ScriptDir$", lastScriptDir);
730 env->SetGlobalVar("$ScriptNameUtf8$", lastScriptNameUtf8);
731 env->SetGlobalVar("$ScriptFileUtf8$", lastScriptFileUtf8);
732 env->SetGlobalVar("$ScriptDirUtf8$", lastScriptDirUtf8);
733 envi->DecrImportDepth();
734
735 return result;
736 }
737
738
739 AVSValue ScriptName(AVSValue args, void*, IScriptEnvironment* env) { return env->GetVarDef("$ScriptName$"); }
740 AVSValue ScriptFile(AVSValue args, void*, IScriptEnvironment* env) { return env->GetVarDef("$ScriptFile$"); }
741 AVSValue ScriptDir (AVSValue args, void*, IScriptEnvironment* env) { return env->GetVarDef("$ScriptDir$" ); }
742 AVSValue ScriptNameUtf8(AVSValue args, void*, IScriptEnvironment* env) { return env->GetVarDef("$ScriptNameUtf8$"); }
743 AVSValue ScriptFileUtf8(AVSValue args, void*, IScriptEnvironment* env) { return env->GetVarDef("$ScriptFileUtf8$"); }
744 AVSValue ScriptDirUtf8(AVSValue args, void*, IScriptEnvironment* env) { return env->GetVarDef("$ScriptDirUtf8$"); }
745 AVSValue SetWorkingDir(AVSValue args, void*, IScriptEnvironment* env) { return env->SetWorkingDir(args[0].AsString()); }
746
747 AVSValue Muldiv(AVSValue args, void*, IScriptEnvironment* ) {
748 // designed for 32 bits, no change other than read int64 parameters,
749 // though they are caster back immediately to int
750 auto result = MulDiv((int)args[0].AsLong(), (int)args[1].AsLong(), (int)args[2].AsLong());
751 return (int)result;
752 }
753
754 // v11: up to int64 range
755 AVSValue Floor(AVSValue args, void*, IScriptEnvironment* ) {
756 int64_t result = static_cast<int64_t>(floor(args[0].AsFloat()));
757 if (result >= INT_MIN && result <= INT_MAX)
758 return (int)result;
759 return result;
760 }
761 // v11: up to int64 range
762 AVSValue Ceil(AVSValue args, void*, IScriptEnvironment* ) {
763 int64_t result = static_cast<int64_t>(ceil(args[0].AsFloat()));
764 if (result >= INT_MIN && result <= INT_MAX)
765 return (int)result;
766 return result;
767 }
768 // v11: up to int64 range
769 AVSValue Round(AVSValue args, void*, IScriptEnvironment* ) {
770 int64_t result = args[0].AsFloat() < 0 ? -static_cast<int64_t>(-args[0].AsFloat() + .5) : static_cast<int64_t>(args[0].AsFloat() + .5);
771 if (result >= INT_MIN && result <= INT_MAX)
772 return (int)result;
773 return result;
774 }
775
776 AVSValue Acos(AVSValue args, void* , IScriptEnvironment* ) { return acos(args[0].AsFloat()); }
777 AVSValue Asin(AVSValue args, void* , IScriptEnvironment* ) { return asin(args[0].AsFloat()); }
778 AVSValue Atan(AVSValue args, void* , IScriptEnvironment* ) { return atan(args[0].AsFloat()); }
779 AVSValue Atan2(AVSValue args, void* , IScriptEnvironment* ) { return atan2(args[0].AsFloat(), args[1].AsFloat()); }
780 AVSValue Cos(AVSValue args, void* , IScriptEnvironment* ) { return cos(args[0].AsFloat()); }
781 AVSValue Cosh(AVSValue args, void* , IScriptEnvironment* ) { return cosh(args[0].AsFloat()); }
782 AVSValue Exp(AVSValue args, void* , IScriptEnvironment* ) { return exp(args[0].AsFloat()); }
783 AVSValue Fmod(AVSValue args, void* , IScriptEnvironment* ) { return fmod(args[0].AsFloat(), args[1].AsFloat()); }
784 AVSValue Log(AVSValue args, void* , IScriptEnvironment* ) { return log(args[0].AsFloat()); }
785 AVSValue Log10(AVSValue args, void* , IScriptEnvironment* ) { return log10(args[0].AsFloat()); }
786 AVSValue Pow(AVSValue args, void* , IScriptEnvironment* ) { return pow(args[0].AsFloat(),args[1].AsFloat()); }
787 AVSValue Sin(AVSValue args, void* , IScriptEnvironment* ) { return sin(args[0].AsFloat()); }
788 AVSValue Sinh(AVSValue args, void* , IScriptEnvironment* ) { return sinh(args[0].AsFloat()); }
789 AVSValue Tan(AVSValue args, void* , IScriptEnvironment* ) { return tan(args[0].AsFloat()); }
790 AVSValue Tanh(AVSValue args, void* , IScriptEnvironment* ) { return tanh(args[0].AsFloat()); }
791 14 AVSValue Sqrt(AVSValue args, void* , IScriptEnvironment* ) { return sqrt(args[0].AsFloat()); }
792
793 // v11: up to int64 range
794 AVSValue Abs(AVSValue args, void* , IScriptEnvironment* ) {
795 int64_t result = std::abs(args[0].AsLong());
796 if (result >= INT_MIN && result <= INT_MAX)
797 return (int)result;
798 return result;
799 }
800 AVSValue FAbs(AVSValue args, void* , IScriptEnvironment* ) { return fabs(args[0].AsFloat()); }
801 AVSValue Pi(AVSValue args, void* , IScriptEnvironment* ) { return 3.14159265358979324; }
802 #ifdef OPT_ScriptFunctionTau
803 AVSValue Tau(AVSValue args, void* , IScriptEnvironment* ) { return 6.28318530717958648; }
804 #endif
805 AVSValue Sign(AVSValue args, void*, IScriptEnvironment* ) { return args[0].AsFloat()==0 ? 0 : args[0].AsFloat() > 0 ? 1 : -1; }
806
807 // v11: These bitwise functions are strictly for 32 bit, if 64 bit versions are implemented they will have different names
808
809 AVSValue BitAnd(AVSValue args, void*, IScriptEnvironment* ) { return args[0].AsInt() & args[1].AsInt(); }
810 AVSValue BitNot(AVSValue args, void*, IScriptEnvironment* ) { return ~args[0].AsInt(); }
811 AVSValue BitOr(AVSValue args, void*, IScriptEnvironment* ) { return args[0].AsInt() | args[1].AsInt(); }
812 AVSValue BitXor(AVSValue args, void*, IScriptEnvironment* ) { return args[0].AsInt() ^ args[1].AsInt(); }
813
814 AVSValue BitAnd64(AVSValue args, void*, IScriptEnvironment*) { return args[0].AsLong() & args[1].AsLong(); }
815 AVSValue BitNot64(AVSValue args, void*, IScriptEnvironment*) { return ~args[0].AsLong(); }
816 AVSValue BitOr64(AVSValue args, void*, IScriptEnvironment*) { return args[0].AsLong() | args[1].AsLong(); }
817 AVSValue BitXor64(AVSValue args, void*, IScriptEnvironment*) { return args[0].AsLong() ^ args[1].AsLong(); }
818
819 AVSValue BitLShift(AVSValue args, void*, IScriptEnvironment* ) { return args[0].AsInt() << args[1].AsInt(); }
820 AVSValue BitRShiftL(AVSValue args, void*, IScriptEnvironment* ) { return int(unsigned(args[0].AsInt()) >> unsigned(args[1].AsInt())); }
821 AVSValue BitRShiftA(AVSValue args, void*, IScriptEnvironment* ) { return args[0].AsInt() >> args[1].AsInt(); }
822
823 AVSValue BitLShift64(AVSValue args, void*, IScriptEnvironment*) { return args[0].AsLong() << args[1].AsInt(); }
824 AVSValue BitRShift64L(AVSValue args, void*, IScriptEnvironment*) { return int64_t(uint64_t(args[0].AsLong()) >> unsigned(args[1].AsInt())); }
825 AVSValue BitRShift64A(AVSValue args, void*, IScriptEnvironment*) { return args[0].AsLong() >> args[1].AsInt(); }
826
827 static unsigned int a_rol(unsigned int value, int shift) {
828 if ((shift &= sizeof(value)*8 - 1) == 0)
829 return value;
830 return (value << shift) | (value >> (sizeof(value)*8 - shift));
831 }
832 static uint64_t a_rol(uint64_t value, int shift) {
833 if ((shift &= sizeof(value) * 8 - 1) == 0)
834 return value;
835 return (value << shift) | (value >> (sizeof(value) * 8 - shift));
836 }
837
838 static unsigned int a_ror(unsigned int value, int shift) {
839 if ((shift &= sizeof(value)*8 - 1) == 0)
840 return value;
841 return (value >> shift) | (value << (sizeof(value)*8 - shift));
842 }
843 static uint64_t a_ror(uint64_t value, int shift) {
844 if ((shift &= sizeof(value) * 8 - 1) == 0)
845 return value;
846 return (value >> shift) | (value << (sizeof(value) * 8 - shift));
847 }
848
849 static int a_btc(int value, int bit) {
850 value ^= 1 << bit;
851 return value;
852 }
853 static int64_t a_btc(int64_t value, int bit) {
854 value ^= static_cast<int64_t>(1) << bit;
855 return value;
856 }
857
858 static int a_btr(int value, int bit) {
859 value &= ~(1 << bit);
860 return value;
861 }
862 static int64_t a_btr(int64_t value, int bit) {
863 value &= ~(static_cast<int64_t>(1) << bit);
864 return value;
865 }
866
867 static int a_bts(int value, int bit) {
868 value |= (1 << bit);
869 return value;
870 }
871 static int64_t a_bts(int64_t value, int bit) {
872 value |= (static_cast<int64_t>(1) << bit);
873 return value;
874 }
875
876 static bool a_bt(int value, int bit) {
877 return (value & (1 << bit)) ? true : false;
878 }
879 static bool a_bt(int64_t value, int bit) {
880 return (value & (static_cast<int64_t>(1)<< bit)) ? true : false;
881 }
882
883 AVSValue BitRotateL(AVSValue args, void*, IScriptEnvironment* ) { return (int)a_rol((unsigned int)args[0].AsInt(), args[1].AsInt()); }
884 AVSValue BitRotateR(AVSValue args, void*, IScriptEnvironment* ) { return (int)a_ror((unsigned int)args[0].AsInt(), args[1].AsInt()); }
885 AVSValue BitRotate64L(AVSValue args, void*, IScriptEnvironment*) { return (int64_t)a_rol((uint64_t)args[0].AsLong(), args[1].AsInt()); }
886 AVSValue BitRotate64R(AVSValue args, void*, IScriptEnvironment*) { return (int64_t)a_ror((uint64_t)args[0].AsLong(), args[1].AsInt()); }
887
888 AVSValue BitChg(AVSValue args, void*, IScriptEnvironment* ) { return a_btc(args[0].AsInt(), args[1].AsInt()); }
889 AVSValue BitClr(AVSValue args, void*, IScriptEnvironment* ) { return a_btr(args[0].AsInt(), args[1].AsInt()); }
890 AVSValue BitSet(AVSValue args, void*, IScriptEnvironment* ) { return a_bts(args[0].AsInt(), args[1].AsInt()); }
891 AVSValue BitTst(AVSValue args, void*, IScriptEnvironment* ) { return a_bt (args[0].AsInt(), args[1].AsInt()); }
892 AVSValue BitChg64(AVSValue args, void*, IScriptEnvironment*) { return a_btc(args[0].AsLong(), args[1].AsInt()); }
893 AVSValue BitClr64(AVSValue args, void*, IScriptEnvironment*) { return a_btr(args[0].AsLong(), args[1].AsInt()); }
894 AVSValue BitSet64(AVSValue args, void*, IScriptEnvironment*) { return a_bts(args[0].AsLong(), args[1].AsInt()); }
895 AVSValue BitTst64(AVSValue args, void*, IScriptEnvironment*) { return a_bt(args[0].AsLong(), args[1].AsInt()); }
896
897 static int numberOfSetBits(uint32_t i)
898 {
899 i = i - ((i >> 1) & 0x55555555);
900 i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
901 return (((i + (i >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
902 }
903
904 static int numberOfSetBits64(uint64_t i) {
905 return static_cast<int>(std::bitset<64>(i).count());
906 }
907
908 AVSValue BitSetCount(AVSValue args, void*, IScriptEnvironment*) {
909 if (args[0].IsInt())
910 return numberOfSetBits(static_cast<uint32_t>(args[0].AsInt()));
911 // multiple integer parameters
912 int count = 0;
913 for (int i = 0; i < args[0].ArraySize(); i++)
914 count += numberOfSetBits(static_cast<uint32_t>(args[0][i].AsInt()));
915 return count;
916 }
917
918 AVSValue BitSetCount64(AVSValue args, void*, IScriptEnvironment*) {
919 if (args[0].IsInt())
920 return numberOfSetBits64(static_cast<uint64_t>(args[0].AsLong()));
921 // multiple integer parameters
922 int count = 0;
923 for (int i = 0; i < args[0].ArraySize(); i++)
924 count += numberOfSetBits64(static_cast<uint64_t>(args[0][i].AsLong()));
925 return count;
926 }
927
928 static const char* toUpperCase(const char* string) {
929 // Make a temporary copy of the string
930 char* tmp = _strdup(string);
931 if (tmp == nullptr) {
932 return nullptr;
933 }
934 // Convert the copy to uppercase
935 _strupr(tmp);
936 return tmp;
937 }
938 AVSValue UCase(AVSValue args, void*, IScriptEnvironment* env) {
939 const char *res = toUpperCase(args[0].AsString());
940 if(res == nullptr)
941 env->ThrowError("UCase: memory allocation error");
942 AVSValue result = env->SaveString(res);
943 free((void*)res);
944 return result;
945 }
946 static const char* toLowerCase(const char* string) {
947 // Make a temporary copy of the string
948 char* tmp = _strdup(string);
949 if (tmp == nullptr) {
950 return nullptr;
951 }
952 // Convert the copy to lowercase
953 _strlwr(tmp);
954 return tmp;
955 }
956 AVSValue LCase(AVSValue args, void*, IScriptEnvironment* env) {
957 const char* res = toLowerCase(args[0].AsString());
958 if (res == nullptr)
959 env->ThrowError("LCase: memory allocation error");
960 AVSValue result = env->SaveString(res);
961 free((void*)res);
962 return result;
963 }
964
965 AVSValue StrLen(AVSValue args, void*, IScriptEnvironment* ) {
966 size_t len = strlen(args[0].AsString());
967 if (len > static_cast<size_t>(std::numeric_limits<int>::max()))
968 return static_cast<int64_t>(len);
969 else
970 return static_cast<int>(len);
971 }
972 static const char* toReversed(const char* string) {
973 // Make a temporary copy of the string
974 char* tmp = _strdup(string);
975 if (tmp == nullptr) {
976 return nullptr;
977 }
978 // reverse the copy
979 _strrev(tmp);
980 return tmp;
981 }
982
983 AVSValue RevStr(AVSValue args, void*, IScriptEnvironment* env) {
984 const char* res = toReversed(args[0].AsString());
985 if (res == nullptr)
986 env->ThrowError("RevStr: memory allocation error");
987 AVSValue result = env->SaveString(res);
988 free((void*)res);
989 return result;
990 }
991
992 AVSValue LeftStr(AVSValue args, void*, IScriptEnvironment* env)
993 {
994 const int64_t _count = args[1].AsLong();
995 if (_count < 0) {
996 env->ThrowError("LeftStr: Negative character count not allowed");
997 }
998 if (static_cast<uint64_t>(_count) > std::numeric_limits<size_t>::max() - 1) {
999 env->ThrowError("LeftStr: Character count exceeds maximum allowed value");
1000 }
1001 const size_t count = static_cast<size_t>(_count);
1002
1003 char* result = new(std::nothrow) char[count + 1];
1004 if (!result) env->ThrowError("LeftStr: malloc failure (%zu bytes)!", count + 1);
1005 strncpy(result, args[0].AsString(), count);
1006 result[count] = '\0'; // Ensure null termination
1007 AVSValue ret = env->SaveString(result);
1008 delete[] result;
1009 return ret;
1010 }
1011
1012 AVSValue MidStr(AVSValue args, void*, IScriptEnvironment* env)
1013 {
1014 const size_t maxlen = strlen(args[0].AsString());
1015
1016 if (args[1].AsLong() < 1)
1017 env->ThrowError("MidStr: Illegal character location. Positions start with 1.");
1018
1019 if (static_cast<uint64_t>(args[1].AsLong() - 1) > std::numeric_limits<size_t>::max() - 1)
1020 env->ThrowError("MidStr: Offset exceeds maximum allowed value");
1021
1022 size_t offset = static_cast<size_t>(args[1].AsLong() - 1); // pos=1 specifies start.
1023
1024 int64_t _len = args[2].AsLong(maxlen);
1025 if (_len < 0)
1026 env->ThrowError("MidStr: Character count cannot be negative");
1027 if (maxlen <= offset) { offset = 0; _len = 0;}
1028
1029 if (static_cast<uint64_t>(_len) > std::numeric_limits<size_t>::max() - 1)
1030 env->ThrowError("MidStr: Character count exceeds maximum allowed value");
1031 size_t len = static_cast<size_t>(_len);
1032
1033 if (offset + len > maxlen)
1034 len = maxlen - offset; // though strncpy handles premature string end
1035
1036 char *result = new(std::nothrow) char[len + 1];
1037 if (!result) env->ThrowError("MidStr: malloc failure (%zu bytes)!", len + 1);
1038 strncpy(result, args[0].AsString() + offset, len);
1039 result[len] = '\0';
1040
1041 AVSValue ret = env->SaveString(result);
1042 delete[] result;
1043 return ret;
1044 }
1045
1046 AVSValue RightStr(AVSValue args, void*, IScriptEnvironment* env)
1047 {
1048 const int64_t _count = args[1].AsLong();
1049 if (_count < 0)
1050 env->ThrowError("RightStr: Negative character count not allowed");
1051
1052 if (static_cast<uint64_t>(_count) > std::numeric_limits<size_t>::max() - 1)
1053 env->ThrowError("RightStr: Character count exceeds maximum allowed value");
1054
1055 size_t count = static_cast<size_t>(_count);
1056 const size_t len = strlen(args[0].AsString());
1057 if (count > len)
1058 count = len;
1059 // no error given, limit to string length
1060 // env->ThrowError("RightStr: Character count (%zu) exceeds string length (%zu)", count, len);
1061
1062 const size_t offset = len - count;
1063
1064 char* result = new(std::nothrow) char[count + 1];
1065 if (!result) env->ThrowError("RightStr: memory allocation failure (%zu bytes)!", count + 1);
1066 strncpy(result, args[0].AsString() + offset, count);
1067 result[count] = '\0';
1068
1069 AVSValue ret = env->SaveString(result);
1070 delete[] result;
1071 return ret;
1072 }
1073
1074 AVSValue ReplaceStr(AVSValue args, void*, IScriptEnvironment* env) {
1075 char const * const original = args[0].AsString();
1076 char const * const pattern = args[1].AsString();
1077 char const * const replacement = args[2].AsString();
1078 const bool case_insensitive = args[3].AsBool(false);
1079
1080 const size_t replace_len = strlen(replacement);
1081 const size_t pattern_len = strlen(pattern);
1082 const size_t orig_len = strlen(original);
1083
1084 size_t pattern_count = 0;
1085 const char * orig_ptr;
1086 const char * pattern_location;
1087
1088 if (0 == pattern_len)
1089 return original;
1090
1091 if (case_insensitive) {
1092 char *original_lower = new(std::nothrow) char[sizeof(char) * (orig_len + 1)];
1093 if (!original_lower) env->ThrowError("ReplaceStr: malloc failure!");
1094 char *pattern_lower = new(std::nothrow) char[sizeof(char) * (pattern_len + 1)];
1095 if (!pattern_lower) env->ThrowError("ReplaceStr: malloc failure!");
1096
1097 // make them lowercase for comparison
1098 strcpy(original_lower, original);
1099 strcpy(pattern_lower, pattern);
1100 #ifdef MSVC
1101 // works fine also for accented ANSI characters
1102 _locale_t locale = _create_locale(LC_ALL, ".ACP"); // Sets the locale to the ANSI code page obtained from the operating system.
1103 _strlwr_l(original_lower, locale);
1104 _strlwr_l(pattern_lower, locale);
1105 _free_locale(locale);
1106 #else
1107 _strlwr(original_lower);
1108 _strlwr(pattern_lower);
1109 #endif
1110
1111 // find how many times the _lowercased_ pattern occurs in the _lowercased_ original string
1112 for (orig_ptr = original_lower; (pattern_location = strstr(orig_ptr, pattern_lower)); orig_ptr = pattern_location + pattern_len)
1113 {
1114 pattern_count++;
1115 }
1116
1117 // allocate memory for the new string
1118 size_t const retlen = orig_len + pattern_count * (replace_len - pattern_len);
1119 char *result = new(std::nothrow) char[sizeof(char) * (retlen + 1)];
1120 if (!result) env->ThrowError("ReplaceStr: malloc failure!");
1121 *result = 0;
1122
1123 // copy the original string,
1124 // replacing all the instances of the pattern
1125 const char * orig_upper_ptr;
1126 char * result_ptr = result;
1127 // handling dual pointer set: orig, uppercase
1128 for (orig_ptr = original, orig_upper_ptr = original_lower;
1129 (pattern_location = strstr(orig_upper_ptr, pattern_lower));
1130 orig_upper_ptr = pattern_location + pattern_len, orig_ptr = original + (orig_upper_ptr - original_lower))
1131 {
1132 const size_t skiplen = pattern_location - orig_upper_ptr;
1133 // copy the section until the occurence of the pattern
1134 strncpy(result_ptr, orig_ptr, skiplen);
1135 result_ptr += skiplen;
1136 // copy the replacement
1137 strncpy(result_ptr, replacement, replace_len);
1138 result_ptr += replace_len;
1139 }
1140 // copy rest
1141 strcpy(result_ptr, orig_ptr);
1142 AVSValue ret = env->SaveString(result);
1143 delete[] result;
1144 delete[] original_lower;
1145 delete[] pattern_lower;
1146 return ret;
1147 }
1148
1149 // old case sensitive version
1150
1151 // find how many times the pattern occurs in the original string
1152 for (orig_ptr = original; (pattern_location = strstr(orig_ptr, pattern)); orig_ptr = pattern_location + pattern_len)
1153 {
1154 pattern_count++;
1155 }
1156
1157 // allocate memory for the new string
1158 size_t const retlen = orig_len + pattern_count * (replace_len - pattern_len);
1159 char *result = new(std::nothrow) char[sizeof(char) * (retlen + 1)];
1160 if (!result) env->ThrowError("ReplaceStr: malloc failure!");
1161 *result = 0;
1162
1163 // copy the original string,
1164 // replacing all the instances of the pattern
1165 char * result_ptr = result;
1166 for (orig_ptr = original; (pattern_location = strstr(orig_ptr, pattern)); orig_ptr = pattern_location + pattern_len)
1167 {
1168 const size_t skiplen = pattern_location - orig_ptr;
1169 // copy the section until the occurence of the pattern
1170 strncpy(result_ptr, orig_ptr, skiplen);
1171 result_ptr += skiplen;
1172 // copy the replacement
1173 strncpy(result_ptr, replacement, replace_len);
1174 result_ptr += replace_len;
1175 }
1176 // copy rest
1177 strcpy(result_ptr, orig_ptr);
1178 AVSValue ret = env->SaveString(result);
1179 delete[] result;
1180 return ret;
1181 }
1182
1183 AVSValue TrimLeft(AVSValue args, void*, IScriptEnvironment* env)
1184 {
1185 char const *original = args[0].AsString();
1186 char const *s = original;
1187 char ch;
1188 // space, npsp, tab
1189 while ((ch = *s) == (char)32 || ch == (char)160 || ch == (char)9)
1190 s++;
1191
1192 if (original == s)
1193 return args[0]; // avoid SaveString if no change
1194
1195 return env->SaveString(s);
1196 }
1197
1198 AVSValue TrimRight(AVSValue args, void*, IScriptEnvironment* env)
1199 {
1200 char const *original = args[0].AsString();
1201 size_t len = strlen(original);
1202 if (len == 0)
1203 return args[0]; // avoid SaveString if no change
1204
1205 size_t orig_len = len;
1206 char const *s = original + len;
1207
1208 char ch;
1209 // space, npsp, tab
1210 while ((len > 0) && ((ch = *--s) == (char)32 || ch == (char)160 || ch == (char)9)) {
1211 len--;
1212 }
1213
1214 if(orig_len == len)
1215 return args[0]; // avoid SaveString if no change
1216
1217 if (len == 0)
1218 return env->SaveString("");
1219
1220 size_t retlen = s - original + 1;
1221
1222 char *result = new(std::nothrow) char[sizeof(char) * (retlen + 1)];
1223 if (!result) env->ThrowError("TrimRight: malloc failure!");
1224 strncpy(result, original, retlen);
1225 result[retlen] = 0;
1226
1227 AVSValue ret = env->SaveString(result);
1228 delete[] result;
1229 return ret;
1230 }
1231
1232 AVSValue TrimAll(AVSValue args, void*, IScriptEnvironment* env)
1233 {
1234 // not simplify with calling Left/Right, avoid double SaveStrings
1235
1236 // like TrimLeft
1237 char const *original = args[0].AsString();
1238 if (!*original)
1239 return args[0]; // avoid SaveString if no change
1240
1241 char ch;
1242 // space, npsp, tab
1243 while ((ch = *original) == (char)32 || ch == (char)160 || ch == (char)9)
1244 original++;
1245
1246 // almost like TrimRight
1247 size_t len = strlen(original);
1248 if (len == 0)
1249 return env->SaveString("");
1250
1251 size_t orig_len = len;
1252 char const *s = original + len;
1253
1254 // space, npsp, tab
1255 while ((len > 0) && ((ch = *--s) == (char)32 || ch == (char)160 || ch == (char)9))
1256 len--;
1257
1258 if (orig_len == len)
1259 return env->SaveString(original); // nothing to cut from right
1260
1261 if (len == 0)
1262 return env->SaveString(""); // full cut
1263
1264 size_t retlen = s - original + 1;
1265
1266 char *result = new(std::nothrow) char[sizeof(char) * (retlen + 1)];
1267 if (!result) env->ThrowError("TrimAll: malloc failure!");
1268 strncpy(result, original, retlen);
1269 result[retlen] = 0;
1270
1271 AVSValue ret = env->SaveString(result);
1272 delete[] result;
1273 return ret;
1274 }
1275
1276
1277 AVSValue StrCmp(AVSValue args, void*, IScriptEnvironment*)
1278 {
1279 return lstrcmp( args[0].AsString(), args[1].AsString() );
1280 }
1281
1282 AVSValue StrCmpi(AVSValue args, void*, IScriptEnvironment*)
1283 {
1284 return lstrcmpi( args[0].AsString(), args[1].AsString() );
1285 }
1286
1287 AVSValue FindStr(AVSValue args, void*, IScriptEnvironment*)
1288 {
1289 const char *pdest = strstr( args[0].AsString(),args[1].AsString() );
1290 int result = (int)(pdest - args[0].AsString() + 1);
1291 if (pdest == NULL) result = 0;
1292 return result;
1293 }
1294
1295 // FIXME: to v11 64 bit support
1296 AVSValue Rand(AVSValue args, void*, IScriptEnvironment*)
1297 { int limit = args[0].AsInt(RAND_MAX);
1298 bool scale_mode = args[1].AsBool((abs(limit) > RAND_MAX));
1299
1300 if (args[2].AsBool(false)) srand( (unsigned) time(NULL) ); //seed
1301
1302 if (scale_mode) {
1303 double f = 1.0 / (RAND_MAX + 1.0);
1304 return int(f * rand() * limit);
1305 }
1306 else { //modulus mode
1307 int s = (limit < 0 ? -1 : 1);
1308 if (limit==0) return 0;
1309 else return s * rand() % limit;
1310 }
1311 }
1312
1313 AVSValue Select(AVSValue args, void*, IScriptEnvironment* env)
1314 {
1315 // arraysize is still int
1316 int64_t i = args[0].AsLong();
1317 if ((args[1].ArraySize() <= i) || (i < 0) || (i > INT_MAX))
1318 env->ThrowError("Select: Index value out of range");
1319 return args[1][static_cast<int>(i)];
1320 }
1321
1322 AVSValue NOP(AVSValue args, void*, IScriptEnvironment*) { return 0;}
1323
1324 AVSValue Undefined(AVSValue args, void*, IScriptEnvironment*) { return AVSValue();}
1325
1326 AVSValue Exist(AVSValue args, void*, IScriptEnvironment*nv) {
1327 const char *filename = args[0].AsString();
1328 #ifdef AVS_POSIX
1329 constexpr bool utf8default = true;
1330 #else
1331 constexpr bool utf8default = false;
1332 #endif
1333 const bool utf8 = args[1].AsBool(utf8default);
1334
1335 if (strchr(filename, '*') || strchr(filename, '?')) // wildcard
1336 return false;
1337
1338 #ifdef AVS_WINDOWS
1339 if (utf8) {
1340 // fixme/enhance me: check win codepage 65001 UTF8 and do like posix native utf8
1341 // (remark applies to all utf8 in avs+)
1342 auto wsource = Utf8ToWideChar(filename);
1343 std::wstring filename_w = wsource.get();
1344 return fs::exists(filename_w);
1345 }
1346 #endif
1347 return fs::exists(filename);
1348 }
1349
1350
1351 //WE ->
1352
1353 // Spline functions to generate and evaluate a natural bicubic spline
1354 void spline(float x[], float y[], int n, float y2[])
1355 {
1356 int i, k;
1357 float p, qn, sig, un, * u;
1358
1359 u = new float[n];
1360
1361 y2[1] = u[1] = 0.0f;
1362
1363 for (i = 2; i <= n - 1; i++) {
1364 sig = (x[i] - x[i - 1]) / (x[i + 1] - x[i - 1]);
1365 p = sig * y2[i - 1] + 2.0f;
1366 y2[i] = (sig - 1.0f) / p;
1367 u[i] = (y[i + 1] - y[i]) / (x[i + 1] - x[i]) - (y[i] - y[i - 1]) / (x[i] - x[i - 1]);
1368 u[i] = (6.0f * u[i] / (x[i + 1] - x[i - 1]) - sig * u[i - 1]) / p;
1369 }
1370 qn = un = 0.0f;
1371 y2[n] = (un - qn * u[n - 1]) / (qn * y2[n - 1] + 1.0f);
1372 for (k = n - 1; k >= 1; k--) {
1373 y2[k] = y2[k] * y2[k + 1] + u[k];
1374 }
1375
1376 delete[] u;
1377 }
1378
1379 int splint(float xa[], float ya[], float y2a[], int n, float x, float& y, bool cubic)
1380 {
1381 int klo, khi, k;
1382 float h, b, a;
1383
1384 klo = 1;
1385 khi = n;
1386 while (khi - klo > 1) {
1387 k = (khi + klo) >> 1;
1388 if (xa[k] > x) khi = k;
1389 else klo = k;
1390 }
1391 h = xa[khi] - xa[klo];
1392 if (h == 0.0f) {
1393 y = 0.0f;
1394 return -1; // all x's have to be different
1395 }
1396 a = (xa[khi] - x) / h;
1397 b = (x - xa[klo]) / h;
1398
1399 if (cubic) {
1400 y = a * ya[klo] + b * ya[khi] + ((a * a * a - a) * y2a[klo] + (b * b * b - b) * y2a[khi]) * (h * h) / 6.0f;
1401 }
1402 else {
1403 y = a * ya[klo] + b * ya[khi];
1404 }
1405 return 0;
1406 }
1407
1408 // the script functions
1409 AVSValue AVSChr(AVSValue args, void*, IScriptEnvironment* env)
1410 {
1411 char s[2];
1412
1413 s[0] = (char)(args[0].AsInt());
1414 s[1] = 0;
1415 return env->SaveString(s);
1416 }
1417
1418 AVSValue AVSOrd(AVSValue args, void*, IScriptEnvironment*)
1419 {
1420 return (int)args[0].AsString()[0] & 0xFF;
1421 }
1422
1423 AVSValue FillStr(AVSValue args, void*, IScriptEnvironment* env )
1424 {
1425 const int64_t _count = args[0].AsLong();
1426 if (_count <= 0)
1427 env->ThrowError("FillStr: Repeat count must be greater than zero!");
1428
1429 const char *str = args[1].AsString(" ");
1430 const size_t len_to_repeat = strlen(str);
1431 if (len_to_repeat == 0)
1432 return str;
1433
1434 constexpr size_t max_size_t = std::numeric_limits<size_t>::max();
1435 size_t max_repeats = (max_size_t - 1) / len_to_repeat;
1436
1437 size_t count = static_cast<size_t>(_count);
1438 if (count > max_repeats)
1439 env->ThrowError("FillStr: too many repeats, resulting string exceeds the maximum allowed length!");
1440
1441 const size_t total = count * len_to_repeat;
1442
1443 char *buff = new(std::nothrow) char[total+1];
1444 if (!buff)
1445 env->ThrowError("FillStr: memory allocation failure (%zu bytes)!", total + 1);
1446
1447 if (len_to_repeat == 1)
1448 std::fill_n(buff, total, str[0]);
1449 else {
1450 for (size_t i = 0; i < count; i++)
1451 memcpy(buff + i * len_to_repeat, str, len_to_repeat);
1452 }
1453 buff[total] = '\0';
1454
1455 AVSValue ret = env->SaveString(buff);
1456 delete[] buff;
1457 return ret;
1458 }
1459
1460 AVSValue AVSTime(AVSValue args, void*, IScriptEnvironment* env)
1461 {
1462 time_t lt_t;
1463 struct tm* lt;
1464 time(&lt_t);
1465 lt = localtime(&lt_t);
1466 char s[1024];
1467 strftime(s, 1024, args[0].AsString(""), lt);
1468 s[1023] = 0;
1469 return env->SaveString(s);
1470 }
1471
1472 // FIXME: to v11 64 bit support
1473 AVSValue Spline(AVSValue args, void*, IScriptEnvironment* env)
1474 {
1475 int n;
1476 float x, y;
1477 int i;
1478 bool cubic;
1479
1480 AVSValue coordinates;
1481
1482 x = args[0].AsFloatf(0);
1483 coordinates = args[1];
1484 cubic = args[2].AsBool(true);
1485
1486 n = coordinates.ArraySize();
1487
1488 if (n < 4 || n & 1) env->ThrowError("To few arguments for Spline");
1489
1490 n = n / 2;
1491
1492 float* buf = new float[(n + 1) * 3];
1493 float* xa = &(buf[(n + 1) * 0]);
1494 float* ya = &(buf[(n + 1) * 1]);
1495 float* y2a = &(buf[(n + 1) * 2]);
1496
1497 for (i = 1; i <= n; i++) {
1498 xa[i] = coordinates[(i - 1) * 2 + 0].AsFloatf(0);
1499 ya[i] = coordinates[(i - 1) * 2 + 1].AsFloatf(0);
1500 }
1501
1502 for (i = 1; i < n; i++) {
1503 if (xa[i] >= xa[i + 1]) env->ThrowError("Spline: all x values have to be different and in ascending order!");
1504 }
1505
1506 spline(xa, ya, n, y2a);
1507 splint(xa, ya, y2a, n, x, y, cubic);
1508
1509 delete[] buf;
1510
1511 return y;
1512 }
1513
1514 // WE <-
1515
1516 static inline const VideoInfo& VI(const AVSValue& arg) { return arg.AsClip()->GetVideoInfo(); }
1517
1518 static const std::map<int, std::string> pixel_format_table =
1519 { // names for lookup by pixel_type or name
1520 {VideoInfo::CS_BGR24, "RGB24"},
1521 {VideoInfo::CS_BGR32, "RGB32"},
1522 {VideoInfo::CS_YUY2 , "YUY2"},
1523 {VideoInfo::CS_YV24 , "YV24"},
1524 {VideoInfo::CS_YV16 , "YV16"},
1525 {VideoInfo::CS_YV12 , "YV12"},
1526 {VideoInfo::CS_I420 , "YV12"},
1527 {VideoInfo::CS_YUV9 , "YUV9"},
1528 {VideoInfo::CS_YV411, "YV411"},
1529 {VideoInfo::CS_Y8 , "Y8"},
1530
1531 {VideoInfo::CS_YUV420P10, "YUV420P10"},
1532 {VideoInfo::CS_YUV422P10, "YUV422P10"},
1533 {VideoInfo::CS_YUV444P10, "YUV444P10"},
1534 {VideoInfo::CS_Y10 , "Y10"},
1535 {VideoInfo::CS_YUV420P12, "YUV420P12"},
1536 {VideoInfo::CS_YUV422P12, "YUV422P12"},
1537 {VideoInfo::CS_YUV444P12, "YUV444P12"},
1538 {VideoInfo::CS_Y12 , "Y12"},
1539 {VideoInfo::CS_YUV420P14, "YUV420P14"},
1540 {VideoInfo::CS_YUV422P14, "YUV422P14"},
1541 {VideoInfo::CS_YUV444P14, "YUV444P14"},
1542 {VideoInfo::CS_Y14 , "Y14"},
1543 {VideoInfo::CS_YUV420P16, "YUV420P16"},
1544 {VideoInfo::CS_YUV422P16, "YUV422P16"},
1545 {VideoInfo::CS_YUV444P16, "YUV444P16"},
1546 {VideoInfo::CS_Y16 , "Y16"},
1547 {VideoInfo::CS_YUV420PS , "YUV420PS"},
1548 {VideoInfo::CS_YUV422PS , "YUV422PS"},
1549 {VideoInfo::CS_YUV444PS , "YUV444PS"},
1550 {VideoInfo::CS_Y32 , "Y32"},
1551
1552 {VideoInfo::CS_BGR48 , "RGB48"},
1553 {VideoInfo::CS_BGR64 , "RGB64"},
1554
1555 {VideoInfo::CS_RGBP , "RGBP"},
1556 {VideoInfo::CS_RGBP10 , "RGBP10"},
1557 {VideoInfo::CS_RGBP12 , "RGBP12"},
1558 {VideoInfo::CS_RGBP14 , "RGBP14"},
1559 {VideoInfo::CS_RGBP16 , "RGBP16"},
1560 {VideoInfo::CS_RGBPS , "RGBPS"},
1561
1562 {VideoInfo::CS_YUVA420, "YUVA420"},
1563 {VideoInfo::CS_YUVA422, "YUVA422"},
1564 {VideoInfo::CS_YUVA444, "YUVA444"},
1565 {VideoInfo::CS_YUVA420P10, "YUVA420P10"},
1566 {VideoInfo::CS_YUVA422P10, "YUVA422P10"},
1567 {VideoInfo::CS_YUVA444P10, "YUVA444P10"},
1568 {VideoInfo::CS_YUVA420P12, "YUVA420P12"},
1569 {VideoInfo::CS_YUVA422P12, "YUVA422P12"},
1570 {VideoInfo::CS_YUVA444P12, "YUVA444P12"},
1571 {VideoInfo::CS_YUVA420P14, "YUVA420P14"},
1572 {VideoInfo::CS_YUVA422P14, "YUVA422P14"},
1573 {VideoInfo::CS_YUVA444P14, "YUVA444P14"},
1574 {VideoInfo::CS_YUVA420P16, "YUVA420P16"},
1575 {VideoInfo::CS_YUVA422P16, "YUVA422P16"},
1576 {VideoInfo::CS_YUVA444P16, "YUVA444P16"},
1577 {VideoInfo::CS_YUVA420PS , "YUVA420PS"},
1578 {VideoInfo::CS_YUVA422PS , "YUVA422PS"},
1579 {VideoInfo::CS_YUVA444PS , "YUVA444PS"},
1580
1581 {VideoInfo::CS_RGBAP , "RGBAP"},
1582 {VideoInfo::CS_RGBAP10 , "RGBAP10"},
1583 {VideoInfo::CS_RGBAP12 , "RGBAP12"},
1584 {VideoInfo::CS_RGBAP14 , "RGBAP14"},
1585 {VideoInfo::CS_RGBAP16 , "RGBAP16"},
1586 {VideoInfo::CS_RGBAPS , "RGBAPS"},
1587 };
1588
1589 static const std::multimap<int, std::string> pixel_format_table_ex =
1590 { // alternative names for lookup by name (multimap!)
1591 {VideoInfo::CS_YV24 , "YUV444"},
1592 {VideoInfo::CS_YV16 , "YUV422"},
1593 {VideoInfo::CS_YV12 , "YUV420"},
1594 {VideoInfo::CS_YV411, "YUV411"},
1595 {VideoInfo::CS_RGBP , "RGBP8"},
1596 {VideoInfo::CS_RGBAP, "RGBAP8"},
1597 {VideoInfo::CS_YV24 , "YUV444P8"},
1598 {VideoInfo::CS_YV16 , "YUV422P8"},
1599 {VideoInfo::CS_YV12 , "YUV420P8"},
1600 {VideoInfo::CS_YV411, "YUV411P8"},
1601 {VideoInfo::CS_YUVA420, "YUVA420P8"},
1602 {VideoInfo::CS_YUVA422, "YUVA422P8"},
1603 {VideoInfo::CS_YUVA444, "YUVA444P8"},
1604 };
1605
1606 const char *GetPixelTypeName(const int pixel_type)
1607 {
1608 const std::string name = "";
1609 auto it = pixel_format_table.find(pixel_type);
1610 if (it == pixel_format_table.end())
1611 return "";
1612 return (it->second).c_str();
1613 }
1614
1615 5 int GetPixelTypeFromName(const char *pixeltypename)
1616 {
1617
1/2
✓ Branch 4 → 5 taken 5 times.
✗ Branch 4 → 46 not taken.
5 std::string name_to_find = pixeltypename;
1618
2/2
✓ Branch 19 → 8 taken 33 times.
✓ Branch 19 → 20 taken 5 times.
76 for (auto & c: name_to_find) c = toupper(c); // uppercase input string
1619
2/2
✓ Branch 29 → 21 taken 284 times.
✓ Branch 29 → 30 taken 4 times.
288 for (auto it = pixel_format_table.begin(); it != pixel_format_table.end(); it++)
1620 {
1621
3/4
✓ Branch 22 → 23 taken 284 times.
✗ Branch 22 → 49 not taken.
✓ Branch 23 → 24 taken 1 time.
✓ Branch 23 → 26 taken 283 times.
284 if ((it->second).compare(name_to_find) == 0)
1622 1 return it->first;
1623 }
1624 // find by alternative names e.g. YUV420 or YUV420P8 instead of YV12
1625
1/2
✓ Branch 40 → 32 taken 20 times.
✗ Branch 40 → 41 not taken.
20 for (auto it = pixel_format_table_ex.begin(); it != pixel_format_table_ex.end(); it++)
1626 {
1627
3/4
✓ Branch 33 → 34 taken 20 times.
✗ Branch 33 → 50 not taken.
✓ Branch 34 → 35 taken 4 times.
✓ Branch 34 → 37 taken 16 times.
20 if ((it->second).compare(name_to_find) == 0)
1628 4 return it->first;
1629 }
1630 return VideoInfo::CS_UNKNOWN;
1631 5 }
1632
1633
1634 AVSValue PixelType (AVSValue args, void*, IScriptEnvironment*) {
1635 return GetPixelTypeName(VI(args[0]).pixel_type);
1636 }
1637
1638 // AVS+
1639 AVSValue ColorSpaceNameToPixelType (AVSValue args, void*, IScriptEnvironment*) {
1640 return GetPixelTypeFromName(args[0].AsString());
1641 }
1642
1643 AVSValue Width(AVSValue args, void*, IScriptEnvironment*) { return VI(args[0]).width; }
1644 AVSValue Height(AVSValue args, void*, IScriptEnvironment*) { return VI(args[0]).height; }
1645 AVSValue FrameCount(AVSValue args, void*, IScriptEnvironment*) { return VI(args[0]).num_frames; }
1646 AVSValue FrameRate(AVSValue args, void*, IScriptEnvironment*) { const VideoInfo& vi = VI(args[0]); return (double)vi.fps_numerator / vi.fps_denominator; } // maximise available precision
1647 AVSValue FrameRateNumerator(AVSValue args, void*, IScriptEnvironment*) { return (int)VI(args[0]).fps_numerator; } // unsigned int truncated to int
1648 AVSValue FrameRateDenominator(AVSValue args, void*, IScriptEnvironment*) { return (int)VI(args[0]).fps_denominator; } // unsigned int truncated to int
1649 AVSValue AudioRate(AVSValue args, void*, IScriptEnvironment*) { return VI(args[0]).audio_samples_per_second; }
1650 AVSValue AudioLength(AVSValue args, void*, IScriptEnvironment*) { return VI(args[0]).num_audio_samples; } // since v11 not truncated to int
1651 AVSValue AudioLengthLo(AVSValue args, void*, IScriptEnvironment*) { return (int)(VI(args[0]).num_audio_samples % (unsigned)args[1].AsInt(1000000000)); }
1652 AVSValue AudioLengthHi(AVSValue args, void*, IScriptEnvironment*) { return (int)(VI(args[0]).num_audio_samples / (unsigned)args[1].AsInt(1000000000)); }
1653 AVSValue AudioLengthS(AVSValue args, void*, IScriptEnvironment* env) {
1654 char s[32];
1655 #ifdef AVS_WINDOWS
1656 return env->SaveString(_i64toa(VI(args[0]).num_audio_samples, s, 10));
1657 #else
1658 sprintf(s, "%" PRId64, VI(args[0]).num_audio_samples);
1659 return env->SaveString(s);
1660 #endif
1661 }
1662 AVSValue AudioLengthF(AVSValue args, void*, IScriptEnvironment*) { return static_cast<double>(VI(args[0]).num_audio_samples); } // at least this will give an order of the size.
1663 // Since v11 it has of little use: AudioLength now can return int64,
1664 // anyway, cast to double instead of float
1665
1666 AVSValue AudioDuration(AVSValue args, void*, IScriptEnvironment*) {
1667 const VideoInfo& vi = VI(args[0]);
1668 return (double)vi.num_audio_samples / vi.audio_samples_per_second;
1669 }
1670
1671 AVSValue AudioChannels(AVSValue args, void*, IScriptEnvironment*) { return VI(args[0]).HasAudio() ? VI(args[0]).nchannels : 0; }
1672 AVSValue AudioBits(AVSValue args, void*, IScriptEnvironment*) { return VI(args[0]).BytesPerChannelSample()*8; }
1673 AVSValue IsAudioFloat(AVSValue args, void*, IScriptEnvironment*) { return VI(args[0]).IsSampleType(SAMPLE_FLOAT); }
1674 AVSValue IsAudioInt(AVSValue args, void*, IScriptEnvironment*) { return VI(args[0]).IsSampleType(SAMPLE_INT8 | SAMPLE_INT16 | SAMPLE_INT24 | SAMPLE_INT32 ); }
1675 AVSValue IsChannelMaskKnown(AVSValue args, void*, IScriptEnvironment*) { return VI(args[0]).IsChannelMaskKnown(); }
1676 AVSValue GetChannelMask(AVSValue args, void*, IScriptEnvironment*) { return (int)VI(args[0]).GetChannelMask(); }
1677
1678 AVSValue IsRGB(AVSValue args, void*, IScriptEnvironment*) { return VI(args[0]).IsRGB(); }
1679 AVSValue IsRGB24(AVSValue args, void*, IScriptEnvironment*) { return VI(args[0]).IsRGB24(); }
1680 AVSValue IsRGB32(AVSValue args, void*, IScriptEnvironment*) { return VI(args[0]).IsRGB32(); }
1681 AVSValue IsYUV(AVSValue args, void*, IScriptEnvironment*) { return VI(args[0]).IsYUV(); }
1682 AVSValue IsYUY2(AVSValue args, void*, IScriptEnvironment*) { return VI(args[0]).IsYUY2(); }
1683 AVSValue IsY8(AVSValue args, void*, IScriptEnvironment*) { return VI(args[0]).IsY8(); }
1684 AVSValue IsYV12(AVSValue args, void*, IScriptEnvironment*) { return VI(args[0]).IsYV12(); }
1685 AVSValue IsYV16(AVSValue args, void*, IScriptEnvironment*) { return VI(args[0]).IsYV16(); }
1686 AVSValue IsYV24(AVSValue args, void*, IScriptEnvironment*) { return VI(args[0]).IsYV24(); }
1687 AVSValue IsYV411(AVSValue args, void*, IScriptEnvironment*) { return VI(args[0]).IsYV411(); }
1688 AVSValue IsPlanar(AVSValue args, void*, IScriptEnvironment*) { return VI(args[0]).IsPlanar(); }
1689 AVSValue IsInterleaved(AVSValue args, void*, IScriptEnvironment*) { return VI(args[0]).IsColorSpace(VideoInfo::CS_INTERLEAVED); }
1690 AVSValue IsFieldBased(AVSValue args, void*, IScriptEnvironment*) { return VI(args[0]).IsFieldBased(); }
1691 AVSValue IsFrameBased(AVSValue args, void*, IScriptEnvironment*) { return !VI(args[0]).IsFieldBased(); }
1692 AVSValue GetParity(AVSValue args, void*, IScriptEnvironment*) { return args[0].AsClip()->GetParity(args[1].AsInt(0)); }
1693
1694 AVSValue HasVideo(AVSValue args, void*, IScriptEnvironment*) { return VI(args[0]).HasVideo(); }
1695 AVSValue HasAudio(AVSValue args, void*, IScriptEnvironment*) { return VI(args[0]).HasAudio(); }
1696
1697 AVSValue String(AVSValue args, void*, IScriptEnvironment* env)
1698 {
1699 if (args[0].IsString()) return args[0];
1700 if (args[0].IsBool()) return (args[0].AsBool() ? "true" : "false");
1701 if (args[0].IsFunction()) return args[0].AsFunction()->ToString(env);
1702 if (args[1].Defined()) {
1703 // WE --> when a format parameter is present
1704 // order! if it is an Int: IsFloat gives True
1705 // If parameter exists, always convert to float
1706 if (args[0].GetType() == AvsValueType::VALUE_TYPE_FLOAT) // real 32 bit float
1707 {
1708 return env->Sprintf(args[1].AsString("%f"), args[0].AsFloatf());
1709 // AsFloatf returns 32 bit float
1710 }
1711 else if (args[0].IsFloat()) // 32 or 64 bit integer or double
1712 {
1713 return env->Sprintf(args[1].AsString("%lf"), args[0].AsFloat());
1714 // AsFloat returns double
1715 }
1716 return "";
1717 }
1718 else {
1719 // standard behaviour
1720 if (args[0].IsLongStrict()) {
1721 char s[21];
1722 sprintf(s, "%" PRId64, args[0].AsLong());
1723 return env->SaveString(s);
1724 }
1725 if (args[0].IsInt()) {
1726 char s[12]; // with sign: worst case 11
1727 sprintf(s, "%d", args[0].AsInt());
1728 return env->SaveString(s);
1729 }
1730 if (args[0].IsFloat()) { // for double as well.
1731 char s[50]; // safe size for double
1732 #ifdef MSVC
1733 _locale_t locale = _create_locale(LC_NUMERIC, "C"); // decimal point: dot
1734 _sprintf_l(s, "%lf", locale, args[0].AsFloat());
1735 _free_locale(locale);
1736 #else
1737 sprintf(s, "%lf", args[0].AsFloat());
1738 #endif
1739 return env->SaveString(s);
1740 }
1741 }
1742 return "";
1743 }
1744
1745 AVSValue Hex(AVSValue args, void*, IScriptEnvironment* env)
1746 {
1747 int n = args[0].AsInt();
1748 int wid = args[1].AsInt(0); // 0..8 is the minimum width of the returned string
1749 wid = (wid<0) ? 0 : (wid > 8) ? 8 : wid;
1750 char buf[8 + 1];
1751 sprintf_s(buf, "%0*X", wid, n); // uppercase, unlike <=r2580
1752 return env->SaveString(buf);
1753 }
1754
1755 static std::string AVSValue_to_string(AVSValue v, IScriptEnvironment* env) {
1756 if (v.IsString()) return v.AsString();
1757 if (v.IsBool()) return v.AsBool() ? "true" : "false";
1758 if (v.IsFunction()) return v.AsFunction()->ToString(env);
1759 if (v.IsInt()) return std::to_string(v.AsLong()); // AsLong handles both 32 and 64-bit int
1760 if (v.IsFloat()) return double_to_string(v.AsFloat());
1761 return "";
1762 }
1763
1764
1765 // Formatting function with parameter list with ordered, indexed or named replacements
1766 AVSValue FormatString(AVSValue args, void*, IScriptEnvironment* env)
1767 {
1768 // Format("{} {}!", "Hello", "world")
1769 // max_pixel_value = 255
1770 // Format("max pixel value = {max_pixel_value}!")
1771 // Format("Pi={1} x={0} y={0}!", 12, Pi())
1772 std::string format = args[0].AsString();
1773 int numargs = args[1].ArraySize();
1774
1775 // (name), value pairs, name can be empty
1776 std::vector<std::pair<std::string, std::string>> sv;
1777 for (int i = 0; i < numargs; i++)
1778 {
1779 std::string name; // can be empty
1780 std::string val_as_s;
1781
1782 AVSValue v = args[1][i];
1783 // ["name", value] support
1784 if (v.IsArray()) {
1785 if (v.ArraySize() != 2 || !v[0].IsString())
1786 env->ThrowError("Format: for key-value lookup parameter must be in [\"name\", value] array format");
1787 name = v[0].AsString();
1788 v = v[1];
1789 }
1790
1791 val_as_s = AVSValue_to_string(v, env);
1792
1793 sv.push_back(std::make_pair(name, val_as_s));
1794 }
1795
1796 size_t supplied_params_count = sv.size();
1797
1798 size_t len = format.size();
1799 size_t i = 0;
1800 bool in_parenthesis = false;
1801 std::string ss;
1802 size_t last_pos = 0;
1803 std::string last_param_section;
1804
1805 size_t param_counter = 0;
1806
1807 while (i < len) {
1808 if (!in_parenthesis) {
1809 size_t x = format.find_first_of('{', last_pos);
1810 // }} can appear only when escaped
1811 size_t cx = format.find_first_of('}', last_pos);
1812 if (cx != std::string::npos && cx < x)
1813 {
1814 if (cx + 1 < len && format[cx + 1] == '}') // }} escaped
1815 {
1816 ss += format.substr(last_pos, cx - last_pos + 1);
1817 last_pos = cx + 2;
1818 i = last_pos;
1819 continue;
1820 }
1821 env->ThrowError("Format: unbalanced curly bracket at position %zu", cx);
1822 }
1823
1824 if (x == std::string::npos) // { not found
1825 {
1826 ss += format.substr(last_pos); // copy rest
1827 break;
1828 }
1829 else if (x + 1 < len && format[x + 1] == '{') // {{ escaped
1830 {
1831 ss += format.substr(last_pos, x - last_pos + 1);
1832 last_pos = x + 2;
1833 i = last_pos;
1834 }
1835 else {
1836 // found {, not escaped
1837 ss += format.substr(last_pos, x - last_pos);
1838 last_pos = x + 1; // points to after the {
1839 i = last_pos;
1840 in_parenthesis = true;
1841 }
1842 continue;
1843 } // end of not-in-bracket-mode
1844
1845 // in-curly-bracket: search for the closing bracket
1846
1847 size_t x = format.find_first_of('}', last_pos);
1848 if (x == std::string::npos) // not found, will throw error outside
1849 break;
1850
1851 last_param_section = format.substr(last_pos, x - last_pos); // name, order number or empty
1852
1853 if (last_param_section.empty()) {
1854 // simple {}, insert next parameter, consume one from the list
1855 // in c++20 you cannot mix
1856 if (param_counter >= supplied_params_count)
1857 env->ThrowError("Format: more parameter sections than parameters supplied");
1858 ss += sv[param_counter++].second;
1859 }
1860 else {
1861 // name or number
1862
1863 bool validName = true;
1864 // check for a valid identifier name
1865 auto ch = last_param_section[0];
1866 if (ch != '_' && !isalpha(ch))
1867 validName = false;
1868 else {
1869 for (size_t i = 1; i < last_param_section.length(); i++) {
1870 const char ch = last_param_section[i];
1871 if (!(ch == '_' || isalnum(ch))) {
1872 validName = false;
1873 break;
1874 }
1875 }
1876 }
1877
1878 if (!validName) {
1879 // valid number like {2} to index parameters
1880 int index;
1881 try {
1882 // string -> integer
1883 index = std::stoi(last_param_section);
1884 }
1885 catch (...) {
1886 env->ThrowError("Format: invalid parameter specifier: \"%s\".", last_param_section.c_str());
1887 }
1888
1889 if (index < 0 || index >= (int)supplied_params_count)
1890 env->ThrowError("Format: parameter index is out of range: %d", index);
1891
1892 ss += sv[index].second;
1893 }
1894 else {
1895 // find among the named parameters
1896 auto it = std::find_if(sv.begin(), sv.end(),
1897 [&last_param_section](const std::pair<std::string, std::string>& element) { return element.first == last_param_section; });
1898 if (it != sv.end())
1899 ss += it->second; // name was found
1900 else {
1901 // last resort: variable with the given name
1902 AVSValue v;
1903 if (!env->GetVarTry(last_param_section.c_str(), &v))
1904 env->ThrowError("Format: no parameter or variable found with name \"%s\".", last_param_section.c_str());
1905
1906 std::string val_as_s = AVSValue_to_string(v, env);
1907
1908 ss += val_as_s;
1909 }
1910 }
1911 }
1912
1913 last_pos = x + 1;
1914 i = last_pos;
1915 in_parenthesis = false;
1916 }
1917
1918 if(in_parenthesis)
1919 env->ThrowError("Format: unclosed curly bracket");
1920
1921 return env->SaveString(ss.c_str());
1922 }
1923
1924 AVSValue Func(AVSValue args, void*, IScriptEnvironment*) { return args[0]; }
1925
1926 AVSValue IsBool(AVSValue args, void*, IScriptEnvironment*) { return args[0].IsBool(); }
1927 AVSValue IsInt(AVSValue args, void*, IScriptEnvironment*) { return args[0].IsInt(); }
1928 AVSValue IsLongStrict(AVSValue args, void*, IScriptEnvironment*) { return args[0].IsLongStrict(); }
1929 AVSValue IsFloat(AVSValue args, void*, IScriptEnvironment*) { return args[0].IsFloat(); }
1930 AVSValue IsFloatfStrict(AVSValue args, void*, IScriptEnvironment*) { return args[0].IsFloatfStrict(); }
1931 AVSValue IsString(AVSValue args, void*, IScriptEnvironment*) { return args[0].IsString(); }
1932 AVSValue IsClip(AVSValue args, void*, IScriptEnvironment*) { return args[0].IsClip(); }
1933 AVSValue IsFunction(AVSValue args, void*, IScriptEnvironment*) { return args[0].IsFunction(); }
1934 AVSValue Defined(AVSValue args, void*, IScriptEnvironment*) { return args[0].Defined(); }
1935
1936 const char* GetAVSTypeName(AVSValue value) {
1937 if (value.IsClip())
1938 return "clip";
1939 else if (value.IsBool())
1940 return "bool";
1941 else if (value.IsLongStrict()) // must be before IsInt
1942 return "long";
1943 else if (value.IsInt())
1944 return "int";
1945 else if (value.IsFloatfStrict()) // before IsFloat
1946 return "float";
1947 else if (value.IsFloat())
1948 return "double";
1949 else if (value.IsString())
1950 return "string";
1951 else if (value.IsArray())
1952 return "array";
1953 else if (value.IsFunction())
1954 return "function";
1955 else if (!value.Defined())
1956 return "undefined value";
1957 else
1958 return "unknown type";
1959 }
1960
1961 AVSValue TypeName(AVSValue args, void*, IScriptEnvironment*) { return GetAVSTypeName(args[0]); }
1962
1963 AVSValue Default(AVSValue args, void*, IScriptEnvironment*) { return args[0].Defined() ? args[0] : args[1]; }
1964
1965 static float find_next_valid_float(const double version) {
1966 float version_f = static_cast<float>(version);
1967 const float initial_value = version_f;
1968 // float epsilon = std::nextafterf(version_f, INFINITY) - version_f;
1969 int steps = 0;
1970
1971 while (version_f < version) {
1972 version_f = std::nextafterf(version_f, INFINITY);
1973 steps++;
1974
1975 // Safety check to prevent infinite loops
1976 if (steps > 1000000) {
1977 // std::cout << "Too many steps required, possible overflow\n";
1978 version_f = initial_value;
1979 break;
1980 }
1981 }
1982 return version_f;
1983 }
1984
1985 AVSValue VersionNumber(AVSValue args, void*, IScriptEnvironment*) {
1986 const double VersionToReturn = AVS_VERSION; // consider upgrading
1987 float VersionToReturnf = find_next_valid_float(VersionToReturn);
1988 return VersionToReturnf;
1989 // A typical transition, when - even in Avisynth+ - we return 2.6f here.
1990 // From 3.7.4 script constants are of 64-bit double precision, and
1991 // the very popular IsAvs26 = VersionNumber() >= 2.6 will fail, since
1992 // 2.6f < 2.6, (double)(float)2.6 is 2.5999999046. Arrrgh.
1993 // 2.6 cannot be exactly specified as a floating point number and has
1994 // differently rounded values in float and in double.
1995 // Thus we start increasing the float value with the smallest available steps,
1996 // until the comparison will be fine.
1997 // Prior to interface version 11, Avisynth supported only 32-bit floating-point data (float), not 64-bit (double).
1998 // To maintain compatibility (old plugins get this value as 32 bit float), this return
1999 // value must remain a 32-bit float.
2000 }
2001
2002 AVSValue VersionString(AVSValue args, void*, IScriptEnvironment*) { return AVS_FULLVERSION; }
2003 AVSValue IsVersionOrGreater(AVSValue args, void*, IScriptEnvironment* env)
2004 {
2005 if (!args[0].Defined() || !args[1].Defined()) {
2006 env->ThrowError("IsVersionOrGreater error: at least two parameters (majorVersion, minorVersion) required!");
2007 }
2008
2009 // true when current version is at least the same or greater than the given three-part version
2010 const int majorVersion = args[0].AsInt(0);
2011 const int minorVersion = args[1].AsInt(0);
2012 const int bugfixVersion = args[2].AsInt(0);
2013 if (majorVersion != AVS_MAJOR_VER) return majorVersion < AVS_MAJOR_VER;
2014 if (minorVersion != AVS_MINOR_VER) return minorVersion < AVS_MINOR_VER;
2015 return bugfixVersion <= AVS_BUGFIX_VER;
2016 }
2017
2018 AVSValue Frac(AVSValue args, void*, IScriptEnvironment*) {
2019 if (args[0].IsInt()) return 0.f;
2020 double result = args[0].AsFloat() - int64_t(args[0].AsFloat());
2021 if (args[0].IsFloat())
2022 return (float)result;
2023 return result;
2024 }
2025
2026 AVSValue Int(AVSValue args, void*, IScriptEnvironment*) {
2027 if (args[0].IsLongStrict()) return args[0].AsLong();
2028 if (args[0].IsInt()) return args[0].AsInt();
2029
2030 int64_t result = int64_t(args[0].AsFloat());
2031 if (result >= INT_MIN && result <= INT_MAX)
2032 return (int)result;
2033 return result;
2034 }
2035
2036 AVSValue IntI(AVSValue args, void*, IScriptEnvironment*) {
2037 if (args[0].IsInt()) return static_cast<int>(args[0].AsLong());
2038
2039 int result = static_cast<int>(args[0].AsFloat());
2040 return result;
2041 }
2042
2043 AVSValue Long(AVSValue args, void*, IScriptEnvironment*) {
2044 if (args[0].IsInt()) return args[0].AsLong();
2045
2046 int64_t result = static_cast<int64_t>(args[0].AsFloat());
2047 return result;
2048 }
2049
2050 AVSValue Float(AVSValue args, void*, IScriptEnvironment*) {
2051 if (args[0].IsInt())
2052 return (double)args[0].AsLong();
2053 if(args[0].IsFloatfStrict())
2054 return args[0].AsFloatf();
2055 return args[0].AsFloat();
2056 }
2057
2058 // Always to 64 bit double
2059 AVSValue Double(AVSValue args, void*, IScriptEnvironment*) {
2060 return args[0].AsFloat();
2061 }
2062
2063 // Always to 32 bit float
2064 AVSValue Floatf(AVSValue args, void*, IScriptEnvironment*) {
2065 return args[0].AsFloatf();
2066 }
2067
2068 AVSValue Value(AVSValue args, void*, IScriptEnvironment*) { char *stopstring; return strtod(args[0].AsString(),&stopstring); }
2069
2070 AVSValue HexValue(AVSValue args, void*, IScriptEnvironment*)
2071 {
2072 // Added optional pos arg default = 1, start position in string of the HexString, 1 denotes the string beginning.
2073 // Will return 0 if error in 'pos' ie if pos is less than 1 or greater than string length.
2074 const char* str = args[0].AsString();
2075 int64_t pos = args[1].AsLong(1) - 1; // start is pos 1
2076 size_t sz = strlen(str);
2077 if (pos < 0 || static_cast<size_t>(pos) >= sz)
2078 return 0;
2079 str += pos;
2080 char* stopstring;
2081 unsigned long result = strtoul(str, &stopstring, 16);
2082 // keep int range, FFFFFFFF is negative - compatibility, see HexValue64
2083 return (int)(result);
2084 }
2085
2086 // new in v11
2087 AVSValue HexValue64(AVSValue args, void*, IScriptEnvironment*)
2088 {
2089 // Added optional pos arg default = 1, start position in string of the HexString, 1 denotes the string beginning.
2090 // Will return 0 if error in 'pos' ie if pos is less than 1 or greater than string length.
2091 const char* str = args[0].AsString();
2092 int64_t pos = args[1].AsLong(1) - 1; // start is pos 1
2093 size_t sz = strlen(str);
2094 if (pos < 0 || static_cast<size_t>(pos) >= sz)
2095 return 0;
2096 str += pos;
2097 char* stopstring;
2098 // v11: strtoul --> strtoull to 64 bit results long long
2099 unsigned long long result = strtoull(str, &stopstring, 16);
2100 // FFFFFFFF is positive
2101 return static_cast<int64_t>(result);
2102 }
2103
2104 AVSValue AvsMin(AVSValue args, void*, IScriptEnvironment* env)
2105 {
2106 bool isInt = true;
2107 bool isFloat32 = true;
2108
2109 const int n = args[0].ArraySize();
2110 if (n < 2) env->ThrowError("Too few arguments for Min");
2111
2112 // If all numbers are Ints return an Int
2113 for (int i = 0; i < n; i++)
2114 if (!args[0][i].IsInt()) {
2115 isInt = false;
2116 break;
2117 }
2118
2119 // v11: If all numbers are 32 bit floats return real float instead of double
2120 for (int i = 0; i < n; i++)
2121 if (!args[0][i].IsFloatfStrict()) {
2122 isFloat32 = false;
2123 break;
2124 }
2125
2126 if (isInt) {
2127 int64_t V = args[0][0].AsLong();
2128 for (int i = 1; i < n; i++)
2129 V = min(V, args[0][i].AsLong());
2130 // keep the smaller type
2131 if (V >= INT_MIN && V <= INT_MAX)
2132 return (int)V;
2133 return V;
2134 }
2135 else {
2136 double V = args[0][0].AsFloat();
2137 for (int i = 1; i < n; i++)
2138 V = min(V, args[0][i].AsFloat());
2139 if (isFloat32)
2140 return (float)V;
2141 return V;
2142 }
2143 }
2144
2145 AVSValue AvsMax(AVSValue args, void*, IScriptEnvironment* env)
2146 {
2147 bool isInt = true;
2148 bool isFloat32 = true;
2149
2150 const int n = args[0].ArraySize();
2151 if (n < 2) env->ThrowError("Too few arguments for Max");
2152
2153 // If all numbers are Ints return an Int
2154 for (int i = 0; i < n; i++)
2155 if (!args[0][i].IsInt()) {
2156 isInt = false;
2157 break;
2158 }
2159
2160 // v11: If all numbers are 32 bit floats return real float instead of double
2161 for (int i = 0; i < n; i++)
2162 if (!args[0][i].IsFloatfStrict()) {
2163 isFloat32 = false;
2164 break;
2165 }
2166
2167 if (isInt) {
2168 int64_t V = args[0][0].AsLong();
2169 for (int i = 1; i < n; i++)
2170 V = max(V, args[0][i].AsLong());
2171 // keep the smaller type
2172 if (V >= INT_MIN && V <= INT_MAX)
2173 return (int)V;
2174 return V;
2175 }
2176 else {
2177 double V = args[0][0].AsFloat();
2178 for (int i = 1; i < n; i++)
2179 V = max(V, args[0][i].AsFloat());
2180 if (isFloat32)
2181 return (float)V;
2182 return V;
2183 }
2184 }
2185
2186 // The "AddAutoloadDir" script function allows supplying a UTF-8 directory path
2187 // even when the system code page is ANSI.
2188 // On Windows the Avisynth script typically treats string parameters as ANSI
2189 // by default, unless we force the interpretation with an optional bool utf8 = true.
2190 // The directory parameter is converted from ANSI to UTF-8 internally before calling
2191 // the interface API. This behavior depends on the IScriptEnvironment2 (development)
2192 // interface, which provides an AddAutoloadDir method that requires now UTF-8 paths.
2193 AVSValue AddAutoloadDir (AVSValue args, void*, IScriptEnvironment* env)
2194 {
2195 IScriptEnvironment2 *env2 = static_cast<IScriptEnvironment2*>(env);
2196 const bool utf8 = args[2].AsBool(false); // default ANSI on Windows, n/a (see charToUtf8) on other OSes
2197 auto dir_utf8 = charToUtf8(args[0].AsString(), utf8); // takes care of ANSI to UTF8 conversion on Windows if needed
2198 env2->AddAutoloadDir(dir_utf8.c_str(), args[1].AsBool(true));
2199
2200 return AVSValue();
2201 }
2202
2203 AVSValue ClearAutoloadDirs (AVSValue args, void*, IScriptEnvironment* env)
2204 {
2205 IScriptEnvironment2 *env2 = static_cast<IScriptEnvironment2*>(env);
2206 env2->ClearAutoloadDirs();
2207 return AVSValue();
2208 }
2209
2210 AVSValue ListAutoloadDirs(AVSValue args, void*, IScriptEnvironment* env)
2211 {
2212 InternalEnvironment* envi = static_cast<InternalEnvironment*>(env);
2213 const char* AutoLoadDirs = envi->ListAutoloadDirs(); // internally uses SaveString
2214 #if defined(AVS_WINDOWS)
2215 const bool utf8 = args[0].AsBool(false); // default ANSI on Windows, n/a on other OSes
2216 if (!utf8) {
2217 // On Windows the environment uses ANSI by default. When the caller requests ANSI
2218 // (utf8 == false), convert the internally stored UTF-8 string to ANSI before returning.
2219 // Characters that cannot be represented in ANSI will be replaced with '?'.
2220 return AVSValue(env->SaveString(Utf8ToAnsi(AutoLoadDirs).c_str())); // New SaveString needed.
2221 }
2222 #endif
2223 return AVSValue(AutoLoadDirs);
2224 }
2225
2226
2227 AVSValue AutoloadPlugins (AVSValue args, void*, IScriptEnvironment* env)
2228 {
2229 IScriptEnvironment2 *env2 = static_cast<IScriptEnvironment2*>(env);
2230 env2->AutoloadPlugins();
2231 return AVSValue();
2232 }
2233
2234 AVSValue FunctionExists (AVSValue args, void*, IScriptEnvironment* env)
2235 {
2236 return env->FunctionExists(args[0].AsString());
2237 }
2238
2239 AVSValue InternalFunctionExists (AVSValue args, void*, IScriptEnvironment* env)
2240 {
2241 IScriptEnvironment2 *env2 = static_cast<IScriptEnvironment2*>(env);
2242 return env2->InternalFunctionExists(args[0].AsString());
2243 }
2244
2245 AVSValue SetFilterMTMode (AVSValue args, void*, IScriptEnvironment* env)
2246 {
2247 IScriptEnvironment2 *env2 = static_cast<IScriptEnvironment2*>(env);
2248 env2->SetFilterMTMode(args[0].AsString(), (MtMode)args[1].AsInt(), args[2].AsBool(false));
2249 return AVSValue();
2250 }
2251
2252 AVSValue SetLogParams(AVSValue args, void*, IScriptEnvironment* env)
2253 {
2254 const char* target = args[0].AsString("stderr");
2255 const int level = args[1].AsInt(LOGLEVEL_INFO);
2256
2257 InternalEnvironment *envi = static_cast<InternalEnvironment*>(env);
2258 envi->SetLogParams(target, level);
2259 return AVSValue();
2260 }
2261
2262 AVSValue LogMsg(AVSValue args, void*, IScriptEnvironment* env)
2263 {
2264 if ((args.ArraySize() != 2) || !args[0].IsString() || !args[1].IsInt())
2265 {
2266 env->ThrowError("Invalid parameters to Log() function.");
2267 }
2268 else
2269 {
2270 InternalEnvironment *envi = static_cast<InternalEnvironment*>(env);
2271 envi->LogMsg(args[1].AsInt(), args[0].AsString());
2272 }
2273 return AVSValue();
2274 }
2275
2276 AVSValue SetCacheMode(AVSValue args, void*, IScriptEnvironment* env)
2277 {
2278 InternalEnvironment *envI = static_cast<InternalEnvironment*>(env);
2279 envI->SetCacheMode((CacheMode)args[0].AsInt());
2280 return AVSValue();
2281 }
2282
2283 AVSValue SetDeviceOpt(AVSValue args, void*, IScriptEnvironment* env)
2284 {
2285 InternalEnvironment *envI = static_cast<InternalEnvironment*>(env);
2286 envI->SetDeviceOpt((DeviceOpt)args[0].AsInt(), args[1].AsInt(0));
2287 return AVSValue();
2288 }
2289
2290 AVSValue SetFilterProp(AVSValue args, void*, IScriptEnvironment* env)
2291 {
2292 InternalEnvironment* envi = static_cast<InternalEnvironment*>(env);
2293
2294 // 3+1-arg: "ss.[mode]i"
2295 // 5+1-arg: "ss.s.[mode]i":
2296 // arg3 exists and is string or integer/undefined
2297 if (args[3].IsString()) {
2298 // 5+1-arg conditional form matched by "ss.s.[mode]i":
2299 // SetFilterProp(filter, param_name, param_match, prop_key, prop_value [, mode])
2300 // Inject prop_key=prop_value only when the named call arg 'param_name' equals param_match.
2301 const AVSValue& param_match = args[2];
2302 // param_match may be a scalar (int/float/bool/string) or an array of scalars (aliases)
2303 if (param_match.IsArray()) {
2304 for (int j = 0; j < param_match.ArraySize(); ++j) {
2305 const AVSValue& elem = param_match[j];
2306 if (!elem.IsInt() && !elem.IsFloat() && !elem.IsString() && !elem.IsBool())
2307 env->ThrowError("SetFilterProp: alias array element %d must be int, float, bool, or string", j);
2308 }
2309 } else if (!param_match.IsInt() && !param_match.IsFloat() && !param_match.IsString() && !param_match.IsBool()) {
2310 env->ThrowError("SetFilterProp: condition value must be int, float, bool, string, "
2311 "or an array of those");
2312 }
2313 const AVSValue& prop_value = args[4];
2314 if (prop_value.Defined() &&
2315 !prop_value.IsInt() && !prop_value.IsFloat() && !prop_value.IsString() &&
2316 !prop_value.IsBool() && !prop_value.IsFunction())
2317 env->ThrowError("SetFilterProp: property value (arg 5) must be int, float, bool, string, or function");
2318 // Frame properties have no bool type: convert bool value to int 0/1
2319 AVSValue stored_value = prop_value;
2320 if (stored_value.IsBool())
2321 stored_value = AVSValue(stored_value.AsBool() ? 1 : 0);
2322 const int mode = args[5].AsInt(AVSPropAppendMode::PROPAPPENDMODE_REPLACE);
2323 envi->SetFilterPropConditional(args[0].AsString(), args[1].AsString(), param_match,
2324 args[3].AsString(), stored_value, mode);
2325 } else {
2326 // 3-arg simple form matched by "ss.[mode]i":
2327 // SetFilterProp(filter, prop_key, value [, mode])
2328 const int mode = args[3].AsInt(AVSPropAppendMode::PROPAPPENDMODE_REPLACE);
2329 AVSValue val = args[2];
2330 if (val.Defined() && !val.IsInt() && !val.IsFloat() && !val.IsString() && !val.IsBool() && !val.IsFunction())
2331 env->ThrowError("SetFilterProp: property value must be int, float, bool, string, function, or undefined()");
2332 // Frame properties have no bool type: convert bool to int 0/1
2333 if (val.IsBool())
2334 val = AVSValue(val.AsBool() ? 1 : 0);
2335 envi->SetFilterProp(args[0].AsString(), args[1].AsString(), val, mode);
2336 }
2337 return AVSValue();
2338 }
2339
2340 AVSValue GetFilterProps(AVSValue args, void*, IScriptEnvironment* env)
2341 {
2342 InternalEnvironment* envi = static_cast<InternalEnvironment*>(env);
2343 return AVSValue(envi->GetFilterProps());
2344 }
2345
2346 AVSValue SetFilterPropPassthrough(AVSValue args, void*, IScriptEnvironment* env)
2347 {
2348 InternalEnvironment* envi = static_cast<InternalEnvironment*>(env);
2349 envi->SetFilterPropPassthrough(args[0].AsString());
2350 return AVSValue();
2351 }
2352
2353 // Neo style
2354 AVSValue SetMemoryMax(AVSValue args, void*, IScriptEnvironment* env)
2355 {
2356 int memMax = args[0].AsInt(0);
2357 int deviceType = args[1].AsInt(0);
2358 int deviceIndex = args[2].AsInt(0);
2359
2360 if (deviceType == 0 || deviceType == DEV_TYPE_CPU) {
2361 return env->SetMemoryMax(memMax);
2362 }
2363
2364 InternalEnvironment *envI = static_cast<InternalEnvironment*>(env);
2365 return envI->SetMemoryMax((AvsDeviceType)deviceType, deviceIndex, memMax);
2366 }
2367
2368 AVSValue SetMaxCPU(AVSValue args, void*, IScriptEnvironment* env)
2369 {
2370 InternalEnvironment* envI = static_cast<InternalEnvironment*>(env);
2371 envI->SetMaxCPU(args[0].AsString());
2372 return AVSValue();
2373 }
2374
2375 AVSValue IsY(AVSValue args, void*, IScriptEnvironment*) { return VI(args[0]).IsY(); }
2376 AVSValue Is420(AVSValue args, void*, IScriptEnvironment*) { return VI(args[0]).Is420(); }
2377 AVSValue Is422(AVSValue args, void*, IScriptEnvironment*) { return VI(args[0]).Is422(); }
2378 AVSValue Is444(AVSValue args, void*, IScriptEnvironment*) { return VI(args[0]).Is444(); }
2379 AVSValue IsRGB48(AVSValue args, void*, IScriptEnvironment*) { return VI(args[0]).IsRGB48(); }
2380 AVSValue IsRGB64(AVSValue args, void*, IScriptEnvironment*) { return VI(args[0]).IsRGB64(); }
2381 AVSValue ComponentSize(AVSValue args, void*, IScriptEnvironment*) { return VI(args[0]).ComponentSize(); }
2382 AVSValue BitsPerComponent(AVSValue args, void*, IScriptEnvironment*) { return VI(args[0]).BitsPerComponent(); }
2383 AVSValue IsYUVA(AVSValue args, void*, IScriptEnvironment*) { return VI(args[0]).IsYUVA(); }
2384 AVSValue IsPlanarRGB(AVSValue args, void*, IScriptEnvironment*) { return VI(args[0]).IsPlanarRGB(); }
2385 AVSValue IsPlanarRGBA(AVSValue args, void*, IScriptEnvironment*) { return VI(args[0]).IsPlanarRGBA(); }
2386 AVSValue NumComponents(AVSValue args, void*, IScriptEnvironment*) { return VI(args[0]).NumComponents(); }
2387 AVSValue HasAlpha(AVSValue args, void*, IScriptEnvironment*) { return VI(args[0]).IsPlanarRGBA() || VI(args[0]).IsYUVA() || VI(args[0]).IsRGB32() || VI(args[0]).IsRGB64(); }
2388 AVSValue IsPackedRGB(AVSValue args, void*, IScriptEnvironment*) { return VI(args[0]).IsRGB24() || VI(args[0]).IsRGB32() || VI(args[0]).IsRGB48() || VI(args[0]).IsRGB64(); }
2389 AVSValue IsVideoFloat(AVSValue args, void*, IScriptEnvironment*) { return VI(args[0]).BitsPerComponent() == 32; }
2390
2391 // helper for GetProcessInfo
2392 static int ProcessType() {
2393 #define PROCESS_UNKNOWN -1
2394 #define PROCESS_32_ON_32 0
2395 #define PROCESS_32_ON_64 1
2396 #define PROCESS_64_ON_64 2
2397
2398 if constexpr(sizeof(void*) == 8)
2399 return PROCESS_64_ON_64;
2400 #ifdef AVS_WINDOWS
2401 else {
2402 // IsWow64Process is not available on all supported versions of Windows.
2403 // Use GetModuleHandle to get a handle to the DLL that contains the function
2404 // and GetProcAddress to get a pointer to the function if available.
2405
2406 BOOL bWoW64Process = FALSE;
2407 typedef bool(WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
2408 LPFN_ISWOW64PROCESS fnIsWow64Process;
2409 HMODULE hKernel32 = GetModuleHandle("kernel32.dll");
2410 if (hKernel32 == NULL)
2411 return PROCESS_UNKNOWN;
2412
2413 fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(hKernel32, "IsWow64Process");
2414 if (fnIsWow64Process != NULL)
2415 fnIsWow64Process(GetCurrentProcess(), &bWoW64Process);
2416 else
2417 return PROCESS_UNKNOWN;
2418
2419 if (bWoW64Process)
2420 return PROCESS_32_ON_64; //WoW64
2421
2422 return PROCESS_32_ON_32;
2423 }
2424 #endif
2425 }
2426
2427 AVSValue GetProcessInfo(AVSValue args, void*, IScriptEnvironment* env)
2428 {
2429 int infoType = args[0].AsInt(0);
2430 if (infoType < 0 || infoType > 1)
2431 env->ThrowError("GetProcessInfo: type must be 0 or 1");
2432 if (infoType == 0) {
2433 return sizeof(void *) == 8 ? 64 : 32;
2434 }
2435 // infoType == 1
2436 return ProcessType();
2437 }
2438
2439 #ifdef AVS_WINDOWS
2440 AVSValue StrToUtf8(AVSValue args, void*, IScriptEnvironment* env) {
2441 const char *source = args[0].AsString();
2442 // in two steps: Ansi -> WideChar -> Utf8
2443 auto wsource = AnsiToWideCharACP(source);
2444 // wide -> utf8
2445 auto source_utf8 = WideCharToUtf8(wsource.get());
2446 AVSValue ret = env->SaveString(source_utf8.get());
2447 return ret;
2448 }
2449
2450 AVSValue StrFromUtf8(AVSValue args, void*, IScriptEnvironment* env) {
2451 const char *source_utf8 = args[0].AsString();
2452 // in two steps: Utf8 -> WideChar -> Ansi
2453 auto wsource = Utf8ToWideChar(source_utf8);
2454 // wide -> ansi
2455 auto source_ansi = WideCharToAnsiACP(wsource.get());
2456 AVSValue ret = env->SaveString(source_ansi.get());
2457 return ret;
2458 }
2459 #endif
2460
2461
2462 AVSValue IsFloatUvZeroBased(AVSValue args, void*, IScriptEnvironment*)
2463 {
2464 #ifdef FLOAT_CHROMA_IS_HALF_CENTERED
2465 return false;
2466 #else
2467 return true;
2468 #endif
2469 }
2470
2471 AVSValue BuildPixelType(AVSValue args, void*, IScriptEnvironment* env)
2472 {
2473 // { "BuildPixelType", BUILTIN_FUNC_PREFIX, "[family]s[bits]i[chroma]i[compat]b[oldnames]b[sample_clip]c", BuildPixelType }, // 180517-
2474 // family: YUV, YUVA, RGB, RGBA, Y
2475 // bits: 8, 10, 12, 14, 16, 32
2476 // chroma: for YUV(A) 420,422,444,411. Ignored for RGB(A) and Y
2477 // compat (default false): returns packed rgb formats for 8/16 bits (RGB default: planar RGB)
2478 // oldnames (default false): returns YV12/YV16/YV24 instead of YUV420P8/YUV422P8/YUV444P8
2479 // sample_clip: when supported, its format is overridden by specified parameters (e.g. only change bits=10)
2480
2481 const bool hasTemplate = args[5].Defined();
2482
2483 if (!args[0].Defined() && !hasTemplate)
2484 env->ThrowError("BuildPixelType error: no color space 'family' or template 'sample_clip' specified");
2485 if (!args[1].Defined() && !hasTemplate)
2486 env->ThrowError("BuildPixelType error: no 'bits' or template 'sample_clip' specified");
2487
2488 std::string family;
2489 if (!args[0].Defined() && hasTemplate) {
2490 // no family parameter: use template
2491 VideoInfo const &vi = args[5].AsClip()->GetVideoInfo();
2492 if (vi.IsY())
2493 family = "Y";
2494 else if (vi.IsPlanar()) {
2495 if (vi.IsYUV())
2496 family = "YUV";
2497 else if (vi.IsYUVA())
2498 family = "YUVA";
2499 else if (vi.IsPlanarRGB())
2500 family = "RGB";
2501 else if (vi.IsPlanarRGBA())
2502 family = "RGBA";
2503 else
2504 env->ThrowError("BuildPixelType error: invalid sample_clip format");
2505 }
2506 else if (vi.IsRGB24() || vi.IsRGB48())
2507 family = "RGB";
2508 else if (vi.IsRGB32() || vi.IsRGB64())
2509 family = "RGBA";
2510 else
2511 env->ThrowError("BuildPixelType error: invalid sample_clip format");
2512 }
2513 else {
2514 family = args[0].AsString();
2515 for (auto & c : family) c = toupper(c); // uppercase input string
2516 }
2517
2518 const bool isYUV = family == "YUV";
2519 const bool isYUVA = family == "YUVA";
2520 const bool isRGB = family == "RGB";
2521 const bool isRGBA = family == "RGBA";
2522 const bool isY = family == "Y";
2523
2524 if(!isYUV && !isYUVA && !isRGB && !isRGBA && !isY)
2525 env->ThrowError("BuildPixelType error: wrong 'family'.", family.c_str());
2526
2527 int bits;
2528 if (!args[1].Defined() && hasTemplate) {
2529 // no bits parameter: get it from template sample_clip
2530 bits = args[5].AsClip()->GetVideoInfo().BitsPerComponent();
2531 } else {
2532 bits = args[1].AsInt();
2533 }
2534
2535 if (bits != 8 && bits != 10 && bits != 12 && bits != 14 && bits != 16 && bits != 32)
2536 env->ThrowError("BuildPixelType error: 'bits'=%d is not valid.", bits);
2537
2538 int chroma;
2539
2540 if (isYUV || isYUVA) {
2541 if (!args[2].Defined() && hasTemplate) {
2542 // no chroma parameter: subsampling from template clip
2543 VideoInfo const &vi = args[5].AsClip()->GetVideoInfo();
2544 const int hs = vi.GetPlaneWidthSubsampling(PLANAR_U);
2545 const int vs = vi.GetPlaneHeightSubsampling(PLANAR_U);
2546 if (hs == 0 && vs == 0) chroma = 444;
2547 else if (hs == 1 && vs == 0) chroma = 422;
2548 else if (hs == 1 && vs == 1) chroma = 420;
2549 else if (hs == 2 && vs == 0) chroma = 411;
2550 else
2551 env->ThrowError("BuildPixelType error: sample_clip has invalid chroma subsampling.");
2552 }
2553 else {
2554 chroma = args[2].AsInt(444);
2555 }
2556 }
2557 else {
2558 chroma = 444; // n/a
2559 }
2560
2561 if(chroma != 444 && chroma != 422 && chroma != 420 && chroma != 411)
2562 env->ThrowError("BuildPixelType error: 'chroma' must be 444, 422, 420 or 411.");
2563
2564 // packed RGB compatibility formats only for RGB(A)
2565 const bool compat = isRGB || isRGBA ? args[3].AsBool(false) : false;
2566
2567 // e.g. return YV12 instead of YUV420P8
2568 const bool oldNames = args[4].AsBool(false);
2569
2570 if(compat && bits != 8 && bits != 16)
2571 env->ThrowError("BuildPixelType error: 'compat'=true requires bits=8 or 16 for RGB(A).");
2572
2573 if(chroma == 411 && bits != 8)
2574 env->ThrowError("BuildPixelType error: 411 is supported only for 8 bits.");
2575
2576 if (compat) {
2577 if (isRGB && bits == 8)
2578 return "RGB24";
2579 if (isRGB && bits == 16)
2580 return "RGB48";
2581 if (isRGBA && bits == 8)
2582 return "RGB32";
2583 return "RGB64"; // RGBA, bits==16
2584 }
2585
2586 std::string format;
2587
2588 if (isYUV || isYUVA || isY)
2589 format = family;
2590 else if (isRGB)
2591 format = "RGBP";
2592 else if (isRGBA)
2593 format = "RGBAP";
2594
2595 if (isYUV || isYUVA) {
2596 if (chroma == 444)
2597 format += "444";
2598 else if(chroma == 422)
2599 format += "422";
2600 else if (chroma == 420)
2601 format += "420";
2602 else if (chroma == 411)
2603 format += "411";
2604
2605 format = format + "P";
2606 }
2607
2608 if (bits == 32)
2609 format += (isY ? "32" : "S"); // no "YS", only "Y32"
2610 else
2611 format = format + std::to_string(bits);
2612
2613 if (oldNames) {
2614 if (format == "YUV420" || format == "YUV420P8") format = "YV12";
2615 else if (format == "YUV422" || format == "YUV422P8") format = "YV16";
2616 else if (format == "YUV444" || format == "YUV444P8") format = "YV24";
2617 }
2618
2619 // 411 has no alternative naming
2620 if (format == "YUV411") format = "YV411";
2621
2622 return env->SaveString(format.c_str());
2623 }
2624
2625 AVSValue VarExist(AVSValue args, void*, IScriptEnvironment* env)
2626 {
2627 const char *name = args[0].AsString();
2628 int len = (int)strlen(name);
2629
2630 bool validName = true;
2631 // check for a valid identifier name
2632 if (*name != '_' && !isalpha(*name))
2633 validName = false;
2634 else {
2635 for (int i = 1; i < len; i++) {
2636 const char ch = name[i];
2637 if (!(ch == '_' || isalnum(ch))) {
2638 validName = false;
2639 break;
2640 }
2641 }
2642 }
2643
2644 if (!validName)
2645 env->ThrowError("VarExist: invalid variable name");
2646
2647 AVSValue result;
2648 return (env->GetVarTry(name, &result)); // true if exists
2649 }
2650
2651
2652 AVSValue ArrayCreate(AVSValue args, void*, IScriptEnvironment* env)
2653 {
2654 return args[0];
2655 }
2656
2657 AVSValue IsArray(AVSValue args, void*, IScriptEnvironment* env) { return args[0].IsArray(); }
2658
2659 AVSValue ArrayGet(AVSValue args, void*, IScriptEnvironment* env)
2660 {
2661 // signature .i+
2662 // parameters: [0] array to index; [1] one or more integer indexes or a string
2663 if (!args[0].IsArray())
2664 env->ThrowError("ArrayGet: array type required.");
2665 const int size = args[0].ArraySize();
2666 if (args[1].IsString()) {
2667 // associative search
2668 // { {"a", element1}, { "b", element2 }, etc..}
2669 const char* tag = args[1].AsString();
2670 for (int i = 0; i < size; i++)
2671 {
2672 AVSValue currentTagValue = args[0][i]; // two elements e.g. { "b", element2 }
2673 if (!currentTagValue.IsArray())
2674 env->ThrowError("ArrayGet: Array must contain array[string, any] elements for dictionary lookup");
2675 if (currentTagValue.ArraySize() < 2)
2676 env->ThrowError("ArrayGet: Internal array must have at least two elements (tag, value)");
2677 AVSValue currentTag = currentTagValue[0];
2678 if (currentTag.IsString() && !lstrcmpi(currentTag.AsString(), tag))
2679 {
2680 return currentTagValue[1];
2681 }
2682 }
2683 return AVSValue(); // undefined
2684 }
2685 else if (args[1].IsArray()) {
2686 AVSValue indexes = args[1];
2687 AVSValue currentValue = args[0];
2688 int index_count = indexes.ArraySize(); // array of parameters. a[1,2] -> [1,2]
2689 if (index_count == 0)
2690 env->ThrowError("ArrayGet: no index specified");
2691 for (int i = 0; i < index_count; i++)
2692 {
2693 if (!currentValue.IsArray())
2694 env->ThrowError("ArrayGet: not an array. Index=%d", i);
2695 int currentIndex = indexes[i].AsInt();
2696 if (currentIndex < 0 || currentIndex >= currentValue.ArraySize())
2697 env->ThrowError("ArrayGet: Array index out of range. Problematic index count: %d", i + 1);
2698 currentValue = currentValue[currentIndex];
2699 }
2700 return currentValue;
2701 }
2702 env->ThrowError("ArrayGet: Invalid array index, must be integer or string, or comma separated integers");
2703 return AVSValue(); // undefined
2704 }
2705
2706 AVSValue ArraySize(AVSValue args, void*, IScriptEnvironment* env)
2707 {
2708 // func signature: "."
2709 if (!args[0].IsArray())
2710 env->ThrowError("ArraySize: parameter must be an array");
2711 return args[0].ArraySize();
2712 }
2713
2714 AVSValue ArrayIns(AVSValue args, void* user_data, IScriptEnvironment* env)
2715 {
2716 int mode = (int)(intptr_t)user_data;
2717 enum ArrayMode {
2718 INSERT = 0,
2719 APPEND = 1,
2720 REPLACE = 2,
2721 DEL = 3
2722 };
2723 // signature .. and ..i
2724 // parameters:
2725 // [0] array to modify;
2726 // [1] element to insert (ArrayAdd, ArrayIns and ArraySet) [2] inserting index(es) (ArrayIns, ArraySet)
2727 // or [1] delete index(es) ArrayDel
2728
2729 const char* funcname = mode == DEL ? "ArrayDel" : mode == REPLACE ? "ArraySet" : mode == APPEND ? "ArrayAdd" : "ArrayIns";
2730
2731 if (!args[0].IsArray())
2732 env->ThrowError("%s error: array type required.", funcname);
2733
2734 const auto orig_size = args[0].ArraySize();
2735
2736 const int index_param_pos = mode == DEL ? 1 : 2;
2737 AVSValue indexes = args[index_param_pos];
2738 int index_count = indexes.ArraySize(); // array of parameters. a[1,2] -> [1,2]
2739
2740 if (mode == INSERT || mode == REPLACE || mode == DEL) {
2741 if (index_count == 0)
2742 env->ThrowError("%s: no index specified", funcname);
2743 }
2744
2745 const int new_size =
2746 mode == DEL && index_count == 1 ? orig_size - 1 :
2747 mode == APPEND && index_count == 0 ? orig_size + 1 :
2748 mode == INSERT && index_count == 1 ? orig_size + 1 :
2749 orig_size; // replace and recurside other cases
2750
2751 std::vector<AVSValue> new_val(new_size);
2752
2753 int action_pos;
2754 if (mode == APPEND)
2755 action_pos = orig_size; // at the end
2756 else
2757 action_pos = indexes[0].AsInt();
2758
2759 // copy before insertion/replace point
2760 for (int i = 0; i < action_pos; i++)
2761 new_val[i] = args[0][i]; // avs+: automatic deep copy
2762
2763 if (
2764 ((mode == REPLACE || mode == INSERT || mode == DEL) && index_count > 1) ||
2765 ((mode == APPEND) && index_count >= 1))
2766 {
2767 int current_index = indexes[0].AsInt();
2768 // for multi-level array recursion is needed because there is no exact reference to an inner element
2769 if (mode == DEL) {
2770 AVSValue params[2] = { args[0][current_index], index_count <= 1 ? AVSValue(nullptr, 0) : AVSValue(&indexes[1], index_count - 1) };
2771 new_val[current_index] = env->Invoke(funcname, AVSValue(params, 2)); // recursively
2772 }
2773 else {
2774 AVSValue params[3] = { args[0][current_index], args[1], index_count <= 1 ? AVSValue(nullptr, 0) : AVSValue(&indexes[1], index_count - 1) };
2775 new_val[current_index] = env->Invoke(funcname, AVSValue(params, 3)); // recursively
2776 }
2777 mode = REPLACE;
2778 }
2779 else if (mode != DEL) {
2780 new_val[action_pos] = args[1];
2781 }
2782
2783 // copy from after insertion/replace/delete point
2784 if (mode == DEL) {
2785 for (int i = action_pos + 1; i < orig_size; i++)
2786 new_val[i - 1] = args[0][i]; // avs+: automatic deep copy
2787 }
2788 else if (mode == REPLACE) {
2789 for (int i = action_pos+1; i < orig_size; i++)
2790 new_val[i] = args[0][i]; // avs+: automatic deep copy
2791 }
2792 else {
2793 for (int i = action_pos; i < orig_size; i++)
2794 new_val[i + 1] = args[0][i]; // avs+: automatic deep copy
2795 }
2796
2797 if(new_size == 0)
2798 return AVSValue(nullptr, 0); // zero array
2799
2800 return AVSValue(new_val.data(), new_size);
2801 }
2802
2803 // Custom comparator functions for sorting
2804 bool customCompareBool(const std::pair<const AVSValue*, int>& a, const std::pair<const AVSValue*, int>& b) {
2805 return (a.first)->AsBool() < (b.first)->AsBool();
2806 }
2807
2808 // v11: 64 bit content as well
2809 bool customCompareInt(const std::pair<const AVSValue *, int>& a, const std::pair<const AVSValue *, int>& b) {
2810 return (a.first)->AsLong() < (b.first)->AsLong(); // v11: AsLong instead of AsInt
2811 }
2812
2813 // v11: 64 bit content as well
2814 bool customCompareFloat(const std::pair<const AVSValue*, int>& a, const std::pair<const AVSValue*, int>& b) {
2815 return (a.first)->AsFloat() < (b.first)->AsFloat(); // v11: AsFloat instead of AsFloatf
2816 }
2817
2818 bool customCompareString(const std::pair<const AVSValue*, int>& a, const std::pair<const AVSValue*, int>& b) {
2819 return std::strcmp((a.first)->AsString(), (b.first)->AsString()) < 0;
2820 }
2821
2822 AVSValue ArraySort(AVSValue args, void* user_data, IScriptEnvironment* env)
2823 {
2824 // [0] array to sort;
2825
2826 if (!args[0].IsArray())
2827 env->ThrowError("ArraySort error: array type required.");
2828
2829 const auto size = args[0].ArraySize();
2830
2831 if (size == 0)
2832 return AVSValue(nullptr, 0); // zero array
2833
2834 std::vector<std::pair<const AVSValue*, int>> indexedArr(size);
2835
2836 // Create a pair of (element reference, index) with type checks
2837 // Note: integers and float can be mixed, sort by the broadest type
2838 AvsValueType finalType = (args[0][0]).GetType();
2839 for (int i = 0; i < size; ++i) {
2840 indexedArr[i] = { &args[0][i], i };
2841 AvsValueType currentType = indexedArr[i].first->GetType();
2842 if (finalType == AvsValueType::VALUE_TYPE_INT && currentType == AvsValueType::VALUE_TYPE_LONG)
2843 {
2844 // promote int to long; note: since v11: long (int64) exists
2845 finalType = currentType;
2846 }
2847 else if (finalType == AvsValueType::VALUE_TYPE_FLOAT && currentType == AvsValueType::VALUE_TYPE_DOUBLE)
2848 {
2849 // promote float to double; note: since v11: double exists
2850 finalType = currentType;
2851 }
2852 else if ((finalType == AvsValueType::VALUE_TYPE_INT || finalType == AvsValueType::VALUE_TYPE_LONG) &&
2853 (currentType == AvsValueType::VALUE_TYPE_FLOAT || currentType == AvsValueType::VALUE_TYPE_DOUBLE)) {
2854 // promote int-like to float-like; note: since v11: int64/double exists
2855 finalType = currentType;
2856 }
2857 // cannot mix bools, ints and strings
2858 if (finalType == AvsValueType::VALUE_TYPE_STRING) {
2859 if (currentType != AvsValueType::VALUE_TYPE_STRING)
2860 env->ThrowError("ArraySort: array contains different basic types, string expected.");
2861 }
2862 else if (finalType == AvsValueType::VALUE_TYPE_BOOL) {
2863 if (currentType != AvsValueType::VALUE_TYPE_BOOL)
2864 env->ThrowError("ArraySort: array contains different basic types, bool expected.");
2865 }
2866 else {
2867 // int-like or float-like
2868 if (currentType != AvsValueType::VALUE_TYPE_INT &&
2869 currentType != AvsValueType::VALUE_TYPE_LONG &&
2870 currentType != AvsValueType::VALUE_TYPE_FLOAT &&
2871 currentType != AvsValueType::VALUE_TYPE_DOUBLE)
2872 env->ThrowError("ArraySort: array contains different basic types, number expected.");
2873 }
2874 }
2875
2876 switch(finalType){
2877 case AvsValueType::VALUE_TYPE_BOOL: std::sort(indexedArr.begin(), indexedArr.end(), customCompareBool); break;
2878 case AvsValueType::VALUE_TYPE_INT:
2879 case AvsValueType::VALUE_TYPE_LONG:
2880 std::sort(indexedArr.begin(), indexedArr.end(), customCompareInt); break;
2881 case AvsValueType::VALUE_TYPE_FLOAT:
2882 case AvsValueType::VALUE_TYPE_DOUBLE:
2883 std::sort(indexedArr.begin(), indexedArr.end(), customCompareFloat); break;
2884 case AvsValueType::VALUE_TYPE_STRING: std::sort(indexedArr.begin(), indexedArr.end(), customCompareString); break;
2885 default:
2886 env->ThrowError("ArraySort: unsupported data type");
2887 }
2888
2889 // copy the results once
2890 std::vector<AVSValue> new_val(size);
2891 for (int i = 0; i < size; ++i) {
2892 new_val[i] = *indexedArr[i].first;
2893 }
2894
2895 return AVSValue(new_val.data(), size);
2896 }
2897
2898