{"slug":"AI/EVENTS/dataview_by_Gottfriedleibniz","category":"AI","title":"Dataview by Gottfriedleibniz","kind":"code","intro":"","body":"--[[\n    Default, and assumed, LUAI_MAXSHORTLEN is 40. To create a non internalized\n    string always force the buffer to be greater than that value.\n--]]\nlocal _strblob = string.blob or function(length)\n    return string.rep(\"\\0\", math.max(40 + 1, length))\nend\n\n--[[\n    API:\n        DataView::{Get | Set}Int8\n        DataView::{Get | Set}Uint8\n        DataView::{Get | Set}Int16\n        DataView::{Get | Set}Uint16\n        DataView::{Get | Set}Int32\n        DataView::{Get | Set}Uint32\n        DataView::{Get | Set}Int64\n        DataView::{Get | Set}Uint64\n        DataView::{Get | Set}LuaInt\n        DataView::{Get | Set}UluaInt\n        DataView::{Get | Set}LuaNum\n        DataView::{Get | Set}Float32\n        DataView::{Get | Set}Float64\n        DataView::{Get | Set}String\n            Parameters:\n                Get: self, offset, endian (optional)\n                Set: self, offset, value, endian (optional)\n        DataView::{GetFixed | SetFixed}::Int\n        DataView::{GetFixed | SetFixed}::Uint\n        DataView::{GetFixed | SetFixed}::String\n            Parameters:\n                Get: offset, typelen, endian (optional)\n                Set: offset, typelen, value, endian (optional)\n    NOTES:\n        (1) Endianness changed from JS API, defaults to little endian.\n        (2) {Get|Set|Next} offsets are zero-based.\n    EXAMPLES:\n        local view = DataView.ArrayBuffer(512)\n        if Citizen.InvokeNative(0x79923CD21BECE14E, 1, view:Buffer(), Citizen.ReturnResultAnyway()) then\n            local dlc = {\n                validCheck = view:GetInt64(0),\n                weaponHash = view:GetInt32(8),\n                val3 = view:GetInt64(16),\n                weaponCost = view:GetInt64(24),\n                ammoCost = view:GetInt64(32),\n                ammoType = view:GetInt64(40),\n                defaultClipSize = view:GetInt64(48),\n                nameLabel = view:GetFixedString(56, 64),\n                descLabel = view:GetFixedString(120, 64),\n                simpleDesc = view:GetFixedString(184, 64),\n                upperCaseName = view:GetFixedString(248, 64),\n            }\n        end\n--]]\nDataView = {\n    EndBig = \">\",\n    EndLittle = \"<\",\n    Types = {\n        Int8 = { code = \"i1\", size = 1 },\n        Uint8 = { code = \"I1\", size = 1 },\n        Int16 = { code = \"i2\", size = 2 },\n        Uint16 = { code = \"I2\", size = 2 },\n        Int32 = { code = \"i4\", size = 4 },\n        Uint32 = { code = \"I4\", size = 4 },\n        Int64 = { code = \"i8\", size = 8 },\n        Uint64 = { code = \"I8\", size = 8 },\n\n        LuaInt = { code = \"j\", size = 8 }, -- a lua_Integer\n        UluaInt = { code = \"J\", size = 8 }, -- a lua_Unsigned\n        LuaNum = { code = \"n\", size = 8}, -- a lua_Number\n        Float32 = { code = \"f\", size = 4 }, -- a float (native size)\n        Float64 = { code = \"d\", size = 8 }, -- a double (native size)\n        String = { code = \"z\", size = -1, }, -- zero terminated string\n    },\n\n    FixedTypes = {\n        String = { code = \"c\", size = -1, }, -- a fixed-sized string with n bytes\n        Int = { code = \"i\", size = -1, }, -- a signed int with n bytes\n        Uint = { code = \"I\", size = -1, }, -- an unsigned int with n bytes\n    },\n}\nDataView.__index = DataView\n\n--[[ Is a dataview type at a specific offset still within buffer length --]]\nlocal function _ib(o, l, t) return ((t.size < 0 and true) or (o + (t.size - 1) <= l)) end\nlocal function _ef(big) return (big and DataView.EndBig) or DataView.EndLittle end\n\n--[[ Helper function for setting fixed datatypes within a buffer --]]\nlocal SetFixed = nil\n\n--[[ Create an ArrayBuffer with a size in bytes --]]\nfunction DataView.ArrayBuffer(length)\n    return setmetatable({\n        offset = 1, length = length, blob = _strblob(length)\n    }, DataView)\nend\n\n--[[ Wrap a non-internalized string --]]\nfunction DataView.Wrap(blob)\n    return setmetatable({\n        offset = 1, blob = blob, length = blob:len(),\n    }, DataView)\nend\n\nfunction DataView:Buffer() return self.blob end\nfunction DataView:ByteLength() return self.length end\nfunction DataView:ByteOffset() return self.offset end\nfunction DataView:SubView(offset)\n    return setmetatable({\n        offset = offset, blob = self.blob, length = self.length,\n    }, DataView)\nend\n\n--[[ Create the API by using DataView.Types. --]]\nfor label,datatype in pairs(DataView.Types) do\n    DataView[\"Get\" .. label] = function(self, offset, endian)\n        local o = self.offset + offset\n        if _ib(o, self.length, datatype) then\n            local v,_ = string.unpack(_ef(endian) .. datatype.code, self.blob, o)\n            return v\n        end\n        return nil -- Out of bounds\n    end\n\n    DataView[\"Set\" .. label] = function(self, offset, value, endian)\n        local o = self.offset + offset\n        if _ib(o, self.length, datatype) then\n            return SetFixed(self, o, value, _ef(endian) .. datatype.code)\n        end\n        return self -- Out of bounds\n    end\n\n    -- Ensure cache is correct.\n    if datatype.size >= 0 and string.packsize(datatype.code) ~= datatype.size then\n        local msg = \"Pack size of %s (%d) does not match cached length: (%d)\"\n        error(msg:format(label, string.packsize(fmt[#fmt]), datatype.size))\n        return nil\n    end\nend\n\nfor label,datatype in pairs(DataView.FixedTypes) do\n    DataView[\"GetFixed\" .. label] = function(self, offset, typelen, endian)\n        local o = self.offset + offset\n        if o + (typelen - 1) <= self.length then\n            local code = _ef(endian) .. \"c\" .. tostring(typelen)\n            local v,_ = string.unpack(code, self.blob, o)\n            return v\n        end\n        return nil -- Out of bounds\n    end\n\n    DataView[\"SetFixed\" .. label] = function(self, offset, typelen, value, endian)\n        local o = self.offset + offset\n        if o + (typelen - 1) <= self.length then\n            local code = _ef(endian) .. \"c\" .. tostring(typelen)\n            return SetFixed(self, o, value, code)\n        end\n        return self\n    end\nend\n\n--[[ Helper function for setting fixed datatypes within a buffer --]]\nSetFixed = function(self, offset, value, code)\n    local fmt = { }\n    local values = { }\n\n    -- All bytes prior to the offset\n    if self.offset < offset then\n        local size = offset - self.offset\n        fmt[#fmt + 1] = \"c\" .. tostring(size)\n        values[#values + 1] = self.blob:sub(self.offset, size)\n    end\n\n    fmt[#fmt + 1] = code\n    values[#values + 1] = value\n\n    -- All bytes after the value (offset + size) to the end of the buffer\n    -- growing the buffer if needed.\n    local ps = string.packsize(fmt[#fmt])\n    if (offset + ps) <= self.length then\n        local newoff = offset + ps\n        local size = self.length - newoff + 1\n\n        fmt[#fmt + 1] = \"c\" .. tostring(size)\n        values[#values + 1] = self.blob:sub(newoff, self.length)\n    end\n\n    self.blob = string.pack(table.concat(fmt, \"\"), table.unpack(values))\n    self.length = self.blob:len()\n    return self\nend\n","tables":[],"sourceUrl":"https://github.com/femga/rdr3_discoveries/blob/477aaaccadb7f0c042286611d9939009636cff12/AI/EVENTS/dataview_by_Gottfriedleibniz.lua","rows":[]}