diff mupdf-source/thirdparty/mujs/jsarray.c @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mupdf-source/thirdparty/mujs/jsarray.c	Mon Sep 15 11:43:07 2025 +0200
@@ -0,0 +1,751 @@
+#include "jsi.h"
+
+int js_getlength(js_State *J, int idx)
+{
+	int len;
+	js_getproperty(J, idx, "length");
+	len = js_tointeger(J, -1);
+	js_pop(J, 1);
+	return len;
+}
+
+void js_setlength(js_State *J, int idx, int len)
+{
+	js_pushnumber(J, len);
+	js_setproperty(J, idx < 0 ? idx - 1 : idx, "length");
+}
+
+static void jsB_new_Array(js_State *J)
+{
+	int i, top = js_gettop(J);
+
+	js_newarray(J);
+
+	if (top == 2) {
+		if (js_isnumber(J, 1)) {
+			js_copy(J, 1);
+			js_setproperty(J, -2, "length");
+		} else {
+			js_copy(J, 1);
+			js_setindex(J, -2, 0);
+		}
+	} else {
+		for (i = 1; i < top; ++i) {
+			js_copy(J, i);
+			js_setindex(J, -2, i - 1);
+		}
+	}
+}
+
+static void Ap_concat(js_State *J)
+{
+	int i, top = js_gettop(J);
+	int n, k, len;
+
+	js_newarray(J);
+	n = 0;
+
+	for (i = 0; i < top; ++i) {
+		js_copy(J, i);
+		if (js_isarray(J, -1)) {
+			len = js_getlength(J, -1);
+			for (k = 0; k < len; ++k)
+				if (js_hasindex(J, -1, k))
+					js_setindex(J, -3, n++);
+			js_pop(J, 1);
+		} else {
+			js_setindex(J, -2, n++);
+		}
+	}
+}
+
+static void Ap_join(js_State *J)
+{
+	char * volatile out = NULL;
+	const char * volatile r = NULL;
+	const char *sep;
+	int seplen;
+	int k, n, len, rlen;
+
+	len = js_getlength(J, 0);
+
+	if (js_isdefined(J, 1)) {
+		sep = js_tostring(J, 1);
+		seplen = strlen(sep);
+	} else {
+		sep = ",";
+		seplen = 1;
+	}
+
+	if (len <= 0) {
+		js_pushliteral(J, "");
+		return;
+	}
+
+	if (js_try(J)) {
+		js_free(J, out);
+		js_throw(J);
+	}
+
+	n = 0;
+	for (k = 0; k < len; ++k) {
+		js_getindex(J, 0, k);
+		if (js_iscoercible(J, -1)) {
+			r = js_tostring(J, -1);
+			rlen = strlen(r);
+		} else {
+			rlen = 0;
+		}
+
+		if (k == 0) {
+			out = js_malloc(J, rlen + 1);
+			if (rlen > 0) {
+				memcpy(out, r, rlen);
+				n += rlen;
+			}
+		} else {
+			if (n + seplen + rlen > JS_STRLIMIT)
+				js_rangeerror(J, "invalid string length");
+			out = js_realloc(J, out, n + seplen + rlen + 1);
+			if (seplen > 0) {
+				memcpy(out + n, sep, seplen);
+				n += seplen;
+			}
+			if (rlen > 0) {
+				memcpy(out + n, r, rlen);
+				n += rlen;
+			}
+		}
+
+		js_pop(J, 1);
+	}
+
+	js_pushlstring(J, out, n);
+	js_endtry(J);
+	js_free(J, out);
+}
+
+static void Ap_pop(js_State *J)
+{
+	int n;
+
+	n = js_getlength(J, 0);
+
+	if (n > 0) {
+		js_getindex(J, 0, n - 1);
+		js_delindex(J, 0, n - 1);
+		js_setlength(J, 0, n - 1);
+	} else {
+		js_setlength(J, 0, 0);
+		js_pushundefined(J);
+	}
+}
+
+static void Ap_push(js_State *J)
+{
+	int i, top = js_gettop(J);
+	int n;
+
+	n = js_getlength(J, 0);
+
+	for (i = 1; i < top; ++i, ++n) {
+		js_copy(J, i);
+		js_setindex(J, 0, n);
+	}
+
+	js_setlength(J, 0, n);
+
+	js_pushnumber(J, n);
+}
+
+static void Ap_reverse(js_State *J)
+{
+	int len, middle, lower;
+
+	len = js_getlength(J, 0);
+	middle = len / 2;
+	lower = 0;
+
+	while (lower != middle) {
+		int upper = len - lower - 1;
+		int haslower = js_hasindex(J, 0, lower);
+		int hasupper = js_hasindex(J, 0, upper);
+		if (haslower && hasupper) {
+			js_setindex(J, 0, lower);
+			js_setindex(J, 0, upper);
+		} else if (hasupper) {
+			js_setindex(J, 0, lower);
+			js_delindex(J, 0, upper);
+		} else if (haslower) {
+			js_setindex(J, 0, upper);
+			js_delindex(J, 0, lower);
+		}
+		++lower;
+	}
+
+	js_copy(J, 0);
+}
+
+static void Ap_shift(js_State *J)
+{
+	int k, len;
+
+	len = js_getlength(J, 0);
+
+	if (len == 0) {
+		js_setlength(J, 0, 0);
+		js_pushundefined(J);
+		return;
+	}
+
+	js_getindex(J, 0, 0);
+
+	for (k = 1; k < len; ++k) {
+		if (js_hasindex(J, 0, k))
+			js_setindex(J, 0, k - 1);
+		else
+			js_delindex(J, 0, k - 1);
+	}
+
+	js_delindex(J, 0, len - 1);
+	js_setlength(J, 0, len - 1);
+}
+
+static void Ap_slice(js_State *J)
+{
+	int len, s, e, n;
+	double sv, ev;
+
+	js_newarray(J);
+
+	len = js_getlength(J, 0);
+	sv = js_tointeger(J, 1);
+	ev = js_isdefined(J, 2) ? js_tointeger(J, 2) : len;
+
+	if (sv < 0) sv = sv + len;
+	if (ev < 0) ev = ev + len;
+
+	s = sv < 0 ? 0 : sv > len ? len : sv;
+	e = ev < 0 ? 0 : ev > len ? len : ev;
+
+	for (n = 0; s < e; ++s, ++n)
+		if (js_hasindex(J, 0, s))
+			js_setindex(J, -2, n);
+}
+
+struct sortslot {
+	js_Value v;
+	js_State *J;
+};
+
+static int sortcmp(const void *avoid, const void *bvoid)
+{
+	const struct sortslot *aslot = avoid, *bslot = bvoid;
+	const js_Value *a = &aslot->v, *b = &bslot->v;
+	js_State *J = aslot->J;
+	const char *sx, *sy;
+	double v;
+	int c;
+
+	int unx = (a->t.type == JS_TUNDEFINED);
+	int uny = (b->t.type == JS_TUNDEFINED);
+	if (unx) return !uny;
+	if (uny) return -1;
+
+	if (js_iscallable(J, 1)) {
+		js_copy(J, 1); /* copy function */
+		js_pushundefined(J);
+		js_pushvalue(J, *a);
+		js_pushvalue(J, *b);
+		js_call(J, 2);
+		v = js_tonumber(J, -1);
+		c = (v == 0) ? 0 : (v < 0) ? -1 : 1;
+		js_pop(J, 1);
+	} else {
+		js_pushvalue(J, *a);
+		js_pushvalue(J, *b);
+		sx = js_tostring(J, -2);
+		sy = js_tostring(J, -1);
+		c = strcmp(sx, sy);
+		js_pop(J, 2);
+	}
+	return c;
+}
+
+static void Ap_sort(js_State *J)
+{
+	struct sortslot * volatile array = NULL;
+	int i, n, len;
+
+	len = js_getlength(J, 0);
+	if (len <= 0) {
+		js_copy(J, 0);
+		return;
+	}
+
+	if (len >= INT_MAX / (int)sizeof(*array))
+		js_rangeerror(J, "array is too large to sort");
+
+	/* Holding objects where the GC cannot see them is illegal, but if we
+	 * don't allow the GC to run we can use qsort() on a temporary array of
+	 * js_Values for fast sorting.
+	 */
+	++J->gcpause;
+
+	if (js_try(J)) {
+		--J->gcpause;
+		js_free(J, array);
+		js_throw(J);
+	}
+
+	array = js_malloc(J, len * sizeof *array);
+
+	n = 0;
+	for (i = 0; i < len; ++i) {
+		if (js_hasindex(J, 0, i)) {
+			array[n].v = *js_tovalue(J, -1);
+			array[n].J = J;
+			js_pop(J, 1);
+			++n;
+		}
+	}
+
+	qsort(array, n, sizeof *array, sortcmp);
+
+	for (i = 0; i < n; ++i) {
+		js_pushvalue(J, array[i].v);
+		js_setindex(J, 0, i);
+	}
+	for (i = len-i; i >= n; --i) {
+		js_delindex(J, 0, i);
+	}
+
+	--J->gcpause;
+
+	js_endtry(J);
+	js_free(J, array);
+
+	js_copy(J, 0);
+}
+
+static void Ap_splice(js_State *J)
+{
+	int top = js_gettop(J);
+	int len, start, del, add, k;
+
+	len = js_getlength(J, 0);
+	start = js_tointeger(J, 1);
+	if (start < 0)
+		start = (len + start) > 0 ? len + start : 0;
+	else if (start > len)
+		start = len;
+
+	if (js_isdefined(J, 2))
+		del = js_tointeger(J, 2);
+	else
+		del = len - start;
+	if (del > len - start)
+		del = len - start;
+	if (del < 0)
+		del = 0;
+
+	js_newarray(J);
+
+	/* copy deleted items to return array */
+	for (k = 0; k < del; ++k)
+		if (js_hasindex(J, 0, start + k))
+			js_setindex(J, -2, k);
+	js_setlength(J, -1, del);
+
+	/* shift the tail to resize the hole left by deleted items */
+	add = top - 3;
+	if (add < del) {
+		for (k = start; k < len - del; ++k) {
+			if (js_hasindex(J, 0, k + del))
+				js_setindex(J, 0, k + add);
+			else
+				js_delindex(J, 0, k + add);
+		}
+		for (k = len; k > len - del + add; --k)
+			js_delindex(J, 0, k - 1);
+	} else if (add > del) {
+		for (k = len - del; k > start; --k) {
+			if (js_hasindex(J, 0, k + del - 1))
+				js_setindex(J, 0, k + add - 1);
+			else
+				js_delindex(J, 0, k + add - 1);
+		}
+	}
+
+	/* copy new items into the hole */
+	for (k = 0; k < add; ++k) {
+		js_copy(J, 3 + k);
+		js_setindex(J, 0, start + k);
+	}
+
+	js_setlength(J, 0, len - del + add);
+}
+
+static void Ap_unshift(js_State *J)
+{
+	int i, top = js_gettop(J);
+	int k, len;
+
+	len = js_getlength(J, 0);
+
+	for (k = len; k > 0; --k) {
+		int from = k - 1;
+		int to = k + top - 2;
+		if (js_hasindex(J, 0, from))
+			js_setindex(J, 0, to);
+		else
+			js_delindex(J, 0, to);
+	}
+
+	for (i = 1; i < top; ++i) {
+		js_copy(J, i);
+		js_setindex(J, 0, i - 1);
+	}
+
+	js_setlength(J, 0, len + top - 1);
+
+	js_pushnumber(J, len + top - 1);
+}
+
+static void Ap_toString(js_State *J)
+{
+	if (!js_iscoercible(J, 0))
+		js_typeerror(J, "'this' is not an object");
+	js_getproperty(J, 0, "join");
+	if (!js_iscallable(J, -1)) {
+		js_pop(J, 1);
+		// TODO: call Object.prototype.toString implementation directly
+		js_getglobal(J, "Object");
+		js_getproperty(J, -1, "prototype");
+		js_rot2pop1(J);
+		js_getproperty(J, -1, "toString");
+		js_rot2pop1(J);
+	}
+	js_copy(J, 0);
+	js_call(J, 0);
+}
+
+static void Ap_indexOf(js_State *J)
+{
+	int k, len, from;
+
+	len = js_getlength(J, 0);
+	from = js_isdefined(J, 2) ? js_tointeger(J, 2) : 0;
+	if (from < 0) from = len + from;
+	if (from < 0) from = 0;
+
+	js_copy(J, 1);
+	for (k = from; k < len; ++k) {
+		if (js_hasindex(J, 0, k)) {
+			if (js_strictequal(J)) {
+				js_pushnumber(J, k);
+				return;
+			}
+			js_pop(J, 1);
+		}
+	}
+
+	js_pushnumber(J, -1);
+}
+
+static void Ap_lastIndexOf(js_State *J)
+{
+	int k, len, from;
+
+	len = js_getlength(J, 0);
+	from = js_isdefined(J, 2) ? js_tointeger(J, 2) : len - 1;
+	if (from > len - 1) from = len - 1;
+	if (from < 0) from = len + from;
+
+	js_copy(J, 1);
+	for (k = from; k >= 0; --k) {
+		if (js_hasindex(J, 0, k)) {
+			if (js_strictequal(J)) {
+				js_pushnumber(J, k);
+				return;
+			}
+			js_pop(J, 1);
+		}
+	}
+
+	js_pushnumber(J, -1);
+}
+
+static void Ap_every(js_State *J)
+{
+	int hasthis = js_gettop(J) >= 3;
+	int k, len;
+
+	if (!js_iscallable(J, 1))
+		js_typeerror(J, "callback is not a function");
+
+	len = js_getlength(J, 0);
+	for (k = 0; k < len; ++k) {
+		if (js_hasindex(J, 0, k)) {
+			js_copy(J, 1);
+			if (hasthis)
+				js_copy(J, 2);
+			else
+				js_pushundefined(J);
+			js_copy(J, -3);
+			js_pushnumber(J, k);
+			js_copy(J, 0);
+			js_call(J, 3);
+			if (!js_toboolean(J, -1))
+				return;
+			js_pop(J, 2);
+		}
+	}
+
+	js_pushboolean(J, 1);
+}
+
+static void Ap_some(js_State *J)
+{
+	int hasthis = js_gettop(J) >= 3;
+	int k, len;
+
+	if (!js_iscallable(J, 1))
+		js_typeerror(J, "callback is not a function");
+
+	len = js_getlength(J, 0);
+	for (k = 0; k < len; ++k) {
+		if (js_hasindex(J, 0, k)) {
+			js_copy(J, 1);
+			if (hasthis)
+				js_copy(J, 2);
+			else
+				js_pushundefined(J);
+			js_copy(J, -3);
+			js_pushnumber(J, k);
+			js_copy(J, 0);
+			js_call(J, 3);
+			if (js_toboolean(J, -1))
+				return;
+			js_pop(J, 2);
+		}
+	}
+
+	js_pushboolean(J, 0);
+}
+
+static void Ap_forEach(js_State *J)
+{
+	int hasthis = js_gettop(J) >= 3;
+	int k, len;
+
+	if (!js_iscallable(J, 1))
+		js_typeerror(J, "callback is not a function");
+
+	len = js_getlength(J, 0);
+	for (k = 0; k < len; ++k) {
+		if (js_hasindex(J, 0, k)) {
+			js_copy(J, 1);
+			if (hasthis)
+				js_copy(J, 2);
+			else
+				js_pushundefined(J);
+			js_copy(J, -3);
+			js_pushnumber(J, k);
+			js_copy(J, 0);
+			js_call(J, 3);
+			js_pop(J, 2);
+		}
+	}
+
+	js_pushundefined(J);
+}
+
+static void Ap_map(js_State *J)
+{
+	int hasthis = js_gettop(J) >= 3;
+	int k, len;
+
+	if (!js_iscallable(J, 1))
+		js_typeerror(J, "callback is not a function");
+
+	js_newarray(J);
+
+	len = js_getlength(J, 0);
+	for (k = 0; k < len; ++k) {
+		if (js_hasindex(J, 0, k)) {
+			js_copy(J, 1);
+			if (hasthis)
+				js_copy(J, 2);
+			else
+				js_pushundefined(J);
+			js_copy(J, -3);
+			js_pushnumber(J, k);
+			js_copy(J, 0);
+			js_call(J, 3);
+			js_setindex(J, -3, k);
+			js_pop(J, 1);
+		}
+	}
+	js_setlength(J, -1, len);
+}
+
+static void Ap_filter(js_State *J)
+{
+	int hasthis = js_gettop(J) >= 3;
+	int k, to, len;
+
+	if (!js_iscallable(J, 1))
+		js_typeerror(J, "callback is not a function");
+
+	js_newarray(J);
+	to = 0;
+
+	len = js_getlength(J, 0);
+	for (k = 0; k < len; ++k) {
+		if (js_hasindex(J, 0, k)) {
+			js_copy(J, 1);
+			if (hasthis)
+				js_copy(J, 2);
+			else
+				js_pushundefined(J);
+			js_copy(J, -3);
+			js_pushnumber(J, k);
+			js_copy(J, 0);
+			js_call(J, 3);
+			if (js_toboolean(J, -1)) {
+				js_pop(J, 1);
+				js_setindex(J, -2, to++);
+			} else {
+				js_pop(J, 2);
+			}
+		}
+	}
+}
+
+static void Ap_reduce(js_State *J)
+{
+	int hasinitial = js_gettop(J) >= 3;
+	int k, len;
+
+	if (!js_iscallable(J, 1))
+		js_typeerror(J, "callback is not a function");
+
+	len = js_getlength(J, 0);
+	k = 0;
+
+	if (len == 0 && !hasinitial)
+		js_typeerror(J, "no initial value");
+
+	/* initial value of accumulator */
+	if (hasinitial)
+		js_copy(J, 2);
+	else {
+		while (k < len)
+			if (js_hasindex(J, 0, k++))
+				break;
+		if (k == len)
+			js_typeerror(J, "no initial value");
+	}
+
+	while (k < len) {
+		if (js_hasindex(J, 0, k)) {
+			js_copy(J, 1);
+			js_pushundefined(J);
+			js_rot(J, 4); /* accumulator on top */
+			js_rot(J, 4); /* property on top */
+			js_pushnumber(J, k);
+			js_copy(J, 0);
+			js_call(J, 4); /* calculate new accumulator */
+		}
+		++k;
+	}
+
+	/* return accumulator */
+}
+
+static void Ap_reduceRight(js_State *J)
+{
+	int hasinitial = js_gettop(J) >= 3;
+	int k, len;
+
+	if (!js_iscallable(J, 1))
+		js_typeerror(J, "callback is not a function");
+
+	len = js_getlength(J, 0);
+	k = len - 1;
+
+	if (len == 0 && !hasinitial)
+		js_typeerror(J, "no initial value");
+
+	/* initial value of accumulator */
+	if (hasinitial)
+		js_copy(J, 2);
+	else {
+		while (k >= 0)
+			if (js_hasindex(J, 0, k--))
+				break;
+		if (k < 0)
+			js_typeerror(J, "no initial value");
+	}
+
+	while (k >= 0) {
+		if (js_hasindex(J, 0, k)) {
+			js_copy(J, 1);
+			js_pushundefined(J);
+			js_rot(J, 4); /* accumulator on top */
+			js_rot(J, 4); /* property on top */
+			js_pushnumber(J, k);
+			js_copy(J, 0);
+			js_call(J, 4); /* calculate new accumulator */
+		}
+		--k;
+	}
+
+	/* return accumulator */
+}
+
+static void A_isArray(js_State *J)
+{
+	if (js_isobject(J, 1)) {
+		js_Object *T = js_toobject(J, 1);
+		js_pushboolean(J, T->type == JS_CARRAY);
+	} else {
+		js_pushboolean(J, 0);
+	}
+}
+
+void jsB_initarray(js_State *J)
+{
+	js_pushobject(J, J->Array_prototype);
+	{
+		jsB_propf(J, "Array.prototype.toString", Ap_toString, 0);
+		jsB_propf(J, "Array.prototype.concat", Ap_concat, 0); /* 1 */
+		jsB_propf(J, "Array.prototype.join", Ap_join, 1);
+		jsB_propf(J, "Array.prototype.pop", Ap_pop, 0);
+		jsB_propf(J, "Array.prototype.push", Ap_push, 0); /* 1 */
+		jsB_propf(J, "Array.prototype.reverse", Ap_reverse, 0);
+		jsB_propf(J, "Array.prototype.shift", Ap_shift, 0);
+		jsB_propf(J, "Array.prototype.slice", Ap_slice, 2);
+		jsB_propf(J, "Array.prototype.sort", Ap_sort, 1);
+		jsB_propf(J, "Array.prototype.splice", Ap_splice, 2);
+		jsB_propf(J, "Array.prototype.unshift", Ap_unshift, 0); /* 1 */
+
+		/* ES5 */
+		jsB_propf(J, "Array.prototype.indexOf", Ap_indexOf, 1);
+		jsB_propf(J, "Array.prototype.lastIndexOf", Ap_lastIndexOf, 1);
+		jsB_propf(J, "Array.prototype.every", Ap_every, 1);
+		jsB_propf(J, "Array.prototype.some", Ap_some, 1);
+		jsB_propf(J, "Array.prototype.forEach", Ap_forEach, 1);
+		jsB_propf(J, "Array.prototype.map", Ap_map, 1);
+		jsB_propf(J, "Array.prototype.filter", Ap_filter, 1);
+		jsB_propf(J, "Array.prototype.reduce", Ap_reduce, 1);
+		jsB_propf(J, "Array.prototype.reduceRight", Ap_reduceRight, 1);
+	}
+	js_newcconstructor(J, jsB_new_Array, jsB_new_Array, "Array", 0); /* 1 */
+	{
+		/* ES5 */
+		jsB_propf(J, "Array.isArray", A_isArray, 1);
+	}
+	js_defglobal(J, "Array", JS_DONTENUM);
+}