/* * Copyright 2025 Vsevolod Stakhov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "lua_common.h" #include "lua_classnames.h" #include "shingles.h" #include "contrib/fmt/include/fmt/format.h" /*** * @module rspamd_shingle * This module provides methods to work with text shingles */ /*** * @method shingle:to_table() * Converts shingle to table of decimal strings * @return {table} table of RSPAMD_SHINGLE_SIZE decimal strings */ LUA_FUNCTION_DEF(shingle, to_table); /*** * @method shingle:get(index) * Gets element at index as two lua_Integer values (high and low 32 bits) * @param {number} index 1-based index * @return {number,number} high and low 32-bit parts */ LUA_FUNCTION_DEF(shingle, get); /*** * @method shingle:get_string(index) * Gets element at index as decimal string * @param {number} index 1-based index * @return {string} decimal representation */ LUA_FUNCTION_DEF(shingle, get_string); static const struct luaL_reg shinglelib_m[] = { LUA_INTERFACE_DEF(shingle, to_table), LUA_INTERFACE_DEF(shingle, get), LUA_INTERFACE_DEF(shingle, get_string), {"__tostring", rspamd_lua_class_tostring}, {nullptr, nullptr}}; static struct rspamd_shingle * lua_check_shingle(lua_State *L, int pos) { void *ud = rspamd_lua_check_udata(L, pos, rspamd_shingle_classname); luaL_argcheck(L, ud != nullptr, pos, "'shingle' expected"); return static_cast(ud); } void lua_newshingle(lua_State *L, const void *sh) { auto *nsh = static_cast( lua_newuserdata(L, sizeof(struct rspamd_shingle))); if (sh != nullptr) { memcpy(nsh, sh, sizeof(struct rspamd_shingle)); } rspamd_lua_setclass(L, rspamd_shingle_classname, -1); } static int lua_shingle_to_table(lua_State *L) { LUA_TRACE_POINT; auto *sh = lua_check_shingle(L, 1); lua_createtable(L, RSPAMD_SHINGLE_SIZE, 0); for (int i = 0; i < RSPAMD_SHINGLE_SIZE; i++) { auto str = fmt::format("{}", sh->hashes[i]); lua_pushstring(L, str.c_str()); lua_rawseti(L, -2, i + 1); } return 1; } static int lua_shingle_get(lua_State *L) { LUA_TRACE_POINT; auto *sh = lua_check_shingle(L, 1); auto idx = luaL_checkinteger(L, 2) - 1; if (idx < 0 || idx >= RSPAMD_SHINGLE_SIZE) { return luaL_error(L, "index out of bounds: %d", idx + 1); } uint64_t val = sh->hashes[idx]; lua_pushinteger(L, (lua_Integer) (val >> 32)); lua_pushinteger(L, (lua_Integer) (val & 0xFFFFFFFF)); return 2; } static int lua_shingle_get_string(lua_State *L) { LUA_TRACE_POINT; auto *sh = lua_check_shingle(L, 1); auto idx = luaL_checkinteger(L, 2) - 1; if (idx < 0 || idx >= RSPAMD_SHINGLE_SIZE) { return luaL_error(L, "index out of bounds: %d", idx + 1); } auto str = fmt::format("{}", sh->hashes[idx]); lua_pushstring(L, str.c_str()); return 1; } void luaopen_shingle(lua_State *L) { rspamd_lua_new_class(L, rspamd_shingle_classname, shinglelib_m); lua_pop(L, 1); }