├── .github ├── FUNDING.yml └── workflows │ └── release.yml ├── LICENSE ├── README.MD └── lua ├── tests └── sfs │ └── sfs.lua └── sfs.lua /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: Srlion 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Srlion https://github.com/Srlion 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | Just make sure to give credits when you are going to use this in anything. 24 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | run-tests: 10 | uses: CFC-Servers/GLuaTest/.github/workflows/run_tests.yml@main 11 | with: 12 | branch: x86-64 13 | 14 | build: 15 | runs-on: ubuntu-22.04 16 | needs: run-tests 17 | permissions: 18 | contents: write 19 | steps: 20 | - uses: actions/checkout@v5 21 | with: 22 | fetch-depth: "0" 23 | 24 | - name: Bump version and push tag 25 | id: tag 26 | uses: anothrNick/github-tag-action@1.75.0 27 | env: 28 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 29 | WITH_V: false 30 | DEFAULT_BUMP: "patch" 31 | RELEASE_BRANCHES: "master,main,dev" 32 | 33 | # Update the version file locally 34 | - name: Update version file 35 | if: steps.tag.outputs.new_tag != '' 36 | run: sed -i 's/VERSION = "[^"]*"/VERSION = "${{ steps.tag.outputs.new_tag }}"/' lua/sfs.lua 37 | 38 | # Get the commit message 39 | - name: Extract Commit Message 40 | id: extract_commit_message 41 | run: | 42 | echo "COMMIT_MESSAGE=$(git log -1 --pretty=%B)" >> $GITHUB_ENV 43 | 44 | # Create a release with the updated file and commit message as release notes 45 | - name: Create GitHub Release 46 | if: steps.tag.outputs.new_tag != '' 47 | env: 48 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 49 | run: | 50 | gh release create "${{ steps.tag.outputs.new_tag }}" \ 51 | --title "Release ${{ steps.tag.outputs.new_tag }}" \ 52 | --notes "$COMMIT_MESSAGE" \ 53 | lua/sfs.lua 54 | -------------------------------------------------------------------------------- /README.MD: -------------------------------------------------------------------------------- 1 | # SFS 2 | 3 | SFS - Srlion's Fast Binary Serializer for Garry's Mod 4 | 5 | ## Introduction 6 | 7 | This is a blazing fast binary serializer. It is designed to be efficient and avoid operations not yet implemented in LuaJIT 2.0.5. It is particularly useful for encoding and decoding network messages. With LuaJIT 2.1 it's even way faster. 8 | 9 | It's made for Garry's Mod in mind, designed to be blazing fast for addons that transfer lots of server -> client -> server data while being safe to use with user input. 10 | 11 | I made it because I was done using pon outputting huge output and messagepack causing issues. Also they don't have anyway to limit the size when decoding. 12 | 13 | Each type is encoded with a prefix byte to identify type, except for small numbers/strings/arrays/tables, which are encoded directly. This allows for efficient encoding and decoding of data, You can read sfs.lua to understand how it works. 14 | 15 | Highly inspired by MessagePack. 16 | 17 | ## Usage 18 | 19 | ```lua 20 | local sfs = include("sfs.lua") 21 | 22 | -- To encode data 23 | local encoded, err = sfs.encode(data) 24 | if err then 25 | print("Error encoding data: ", err) 26 | return 27 | end 28 | 29 | -- To decode data 30 | local decoded, err = sfs.decode(encoded) 31 | if err then 32 | print("Error decoding data: ", err) 33 | return 34 | end 35 | 36 | print(decoded) 37 | ``` 38 | 39 | You can also add custom types! 40 | 41 | ```lua 42 | local Encoder = sfs.Encoder 43 | local Decoder = sfs.Decoder 44 | local ENDING = Encoder.ENDING 45 | 46 | local SortedMap; do 47 | local SortedMapMethods = {} 48 | local SortedMapMeta = { 49 | __index = SortedMapMethods, 50 | __tostring = function(s) 51 | return string.format("SortedMap: %p", s) 52 | end, 53 | MetaName = "SortedMap" 54 | } 55 | 56 | SortedMap = { 57 | Meta = SortedMapMeta, 58 | } 59 | 60 | function SortedMap.New() 61 | return setmetatable({ 62 | map = {}, 63 | keys = {}, 64 | size = 0 65 | }, SortedMapMeta) 66 | end 67 | 68 | function SortedMapMethods:Hey() 69 | PrintTable(self) 70 | end 71 | end 72 | 73 | local SORTED_MAP_ID 74 | SORTED_MAP_ID = sfs.add_custom_type(SortedMap.Meta, function(buf, v) 75 | Encoder.write_byte(buf, SORTED_MAP_ID) 76 | 77 | if Encoder.write_table(buf, v.map) then -- if it returns true, there was an error 78 | return true 79 | end 80 | Encoder.write_byte(buf, ENDING) 81 | 82 | if Encoder.write_array(buf, v.keys, v.size) then -- if it returns true, there was an error 83 | return true 84 | end 85 | Encoder.write_byte(buf, ENDING) 86 | end, function(ctx) 87 | ctx[1] = ctx[1] + 1 -- Skip the type byte (SORTED_MAP_ID) 88 | 89 | local map, keys, err 90 | 91 | map, err = Decoder.read_table(ctx, ENDING) 92 | if err then return nil, err end 93 | 94 | keys, err = Decoder.read_array(ctx, ENDING) 95 | if err then return nil, err end 96 | 97 | return setmetatable({ 98 | map = map, 99 | keys = keys, 100 | size = #keys 101 | }, SortedMap.Meta) 102 | end) 103 | 104 | local data = SortedMap.New() 105 | data.map["keys"] = "values" 106 | data.keys[1] = "key" 107 | data.size = 1 108 | 109 | local encoded, err = sfs.encode(data) 110 | if err then 111 | print("Error encoding data: ", err) 112 | return 113 | end 114 | 115 | local decoded, err = sfs.decode(encoded) 116 | if err then 117 | print("Error decoding data: ", err) 118 | return 119 | end 120 | 121 | PrintTable(decoded) 122 | ``` 123 | 124 | ## Functions 125 | 126 | - `encode(data)` Encodes the given data into a string. Returns the encoded string, an error string, and a secondary error string. If the encoding is successful, the error strings will be nil. 127 | 128 | - `decode(encoded_data, max_size?)` Decodes the given string into the original data. Returns the decoded data, an error string, and a secondary error string. If the decoding is successful, the error strings will be nil. max_size is an optional parameter that allows you to specify a maximum size for the decoded data. This can be useful for preventing denial-of-service attacks where an attacker sends a very large encoded string. 129 | 130 | - `set_type_function(t_fn)` Sets a custom type function. This can be useful if you have custom type function that you want the library to use instead of global `type` function. 131 | 132 | - `add_custom_type(type_name, encode_fn, decode_fn)` Adds a custom type to the library. This can be useful if you have custom types that you want to encode and decode. Returns the type ID that was assigned to the custom type. 133 | 134 | Note 135 | This module does not throw errors. Instead, functions return an error string when something goes wrong. Always check these return values to make sure your calls to encode and decode were successful. 136 | 137 | Internal Functions 138 | The Encoder and Decoder tables are also exported for advanced usage. These tables contain the internal functions used for encoding and decoding data. 139 | 140 | ## Benchmarks 141 | 142 | > [!NOTE] 143 | > These benchmarks are not updated with new changes. I will update them soon™. (New changes shouldn't affect the performance that much) 144 | 145 | This benchmark is not highly accurate, but it gives a rough idea of how fast the library is. 146 | 147 | ```lua 148 | local value_to_encode = {nil, false, true, "xd lol hehe", 1, 0xFF, 0xFFFF, 0xFFFFFFFF, 0xFFFFFFFFFFFFF, 1.7976931348623e308} 149 | ``` 150 | 151 | Running it 100,000 times: 152 | 153 | | Library | Encode + Decode | 154 | | ------- | --------------- | 155 | | sfs | 1.233872852 | 156 | | cbor | 1.7398643 | 157 | | pon | 2.392090866 | 158 | 159 | Around 40% faster than cbor and 94% faster than pon. Encode output will be almost the same size as cbor but way smaller than pon. 160 | 161 | - After some testing, pon can be smaller than sfs (not by a significant margin) when all the data is composed of strings (not in all cases). This is because pon always uses two bytes and does not include the string length, making it potentially smaller in certain string-based scenarios. However, it is important to note that the performance difference between the two is substantial, and when dealing with mixed data types, sfs will generally result in a much smaller output size. 162 | 163 | | Library | Encode Output Size | 164 | | ------- | ------------------ | 165 | | sfs | 52 | 166 | | cbor | 53 | 167 | | pon | 88 | 168 | 169 | It may not make a difference for small data, but it will make a difference for big ones. 170 | 171 | ## Tested On [Physgun](https://billing.physgun.com/aff.php?aff=131) Dev Server 172 | 173 | **Gamemode:** Sandbox 174 | 175 | - Lua Refresh -> **OFF** 176 | - Physgun Utils -> **OFF** 177 | -------------------------------------------------------------------------------- /lua/tests/sfs/sfs.lua: -------------------------------------------------------------------------------- 1 | local sfs = include("sfs.lua") 2 | 3 | local encode = sfs.encode 4 | local decode = sfs.decode 5 | 6 | local Encoder = sfs.Encoder 7 | local Decoder = sfs.Decoder 8 | 9 | local function name(v) 10 | return "type: " .. v 11 | end 12 | 13 | local function are_equal(t1, t2) 14 | if type(t1) ~= type(t2) then return false end 15 | if type(t1) ~= "table" then 16 | if t1 ~= t1 and t2 ~= t2 then return true end -- both NaN 17 | return t1 == t2 18 | end 19 | for k in pairs(t1) do 20 | if t2[k] == nil then return false end 21 | if not are_equal(t1[k], t2[k]) then return false end 22 | end 23 | if table.Count(t1) ~= table.Count(t2) then return false end 24 | return true 25 | end 26 | 27 | local function expect_same_number(expect, decoded, original) 28 | if original ~= original then 29 | -- original is NaN ⇒ decoded must also be NaN 30 | expect(decoded ~= decoded).to.beTrue() 31 | return 32 | end 33 | if original == 0 then 34 | -- preserve zero sign 35 | local inv_o = 1 / original 36 | local inv_d = 1 / decoded 37 | expect(inv_d).to.equal(inv_o) -- +inf vs -inf must match 38 | return 39 | end 40 | expect(decoded).to.equal(original) 41 | end 42 | 43 | local function generate_test_numbers(current_value, total_range) 44 | local to_test = {} 45 | local step_factor = 1.5 46 | table.insert(to_test, current_value) 47 | while current_value < total_range do 48 | local step = math.min(math.floor(step_factor * math.random(10, 100)), total_range - current_value) 49 | current_value = current_value + step 50 | table.insert(to_test, current_value) 51 | step_factor = step_factor * 1.1 52 | end 53 | table.insert(to_test, total_range) 54 | return to_test 55 | end 56 | 57 | local function generate_test_strings(total_range) 58 | local result = {} 59 | local length = 1 60 | table.insert(result, string.rep("a", length)) 61 | while length < total_range do 62 | local increase = math.floor(length * 0.75) 63 | increase = math.max(1, increase) 64 | length = length + increase 65 | if length > total_range then 66 | length = total_range 67 | end 68 | table.insert(result, string.rep("a", length)) 69 | end 70 | return result 71 | end 72 | 73 | local function generate_test_array(total_range) 74 | local result = {} 75 | local length = 1 76 | table.insert(result, { 0 }) 77 | while length < total_range do 78 | local increase = math.floor(length * 0.75) 79 | increase = math.max(1, increase) 80 | length = length + increase 81 | if length > total_range then 82 | length = total_range 83 | end 84 | local new_array = {} 85 | for i = 1, length do 86 | new_array[i] = true 87 | end 88 | table.insert(result, new_array) 89 | end 90 | return result 91 | end 92 | 93 | local function generate_test_table(total_range, result) 94 | result = result or {} 95 | local length = 1 96 | table.insert(result, { key1 = "value1" }) 97 | while length < total_range do 98 | local increase = math.floor(length * 0.75) 99 | increase = math.max(1, increase) 100 | length = length + increase 101 | if length > total_range then 102 | length = total_range 103 | end 104 | local new_table = {} 105 | for i = 1, length do 106 | new_table["key" .. i] = "value" .. i 107 | end 108 | table.insert(result, new_table) 109 | end 110 | return result 111 | end 112 | 113 | -- local tested = sfs.encode(9007199254740991) 114 | -- print(sfs.decode(tested) == 9007199254740992) 115 | 116 | return { 117 | groupName = "sfs", 118 | beforeAll = function() 119 | collectgarbage() 120 | collectgarbage() 121 | collectgarbage() 122 | end, 123 | afterEach = function() 124 | collectgarbage() 125 | collectgarbage() 126 | collectgarbage() 127 | end, 128 | cases = { 129 | { 130 | name = name("nil"), 131 | func = function() 132 | local data = nil 133 | local encoded = encode(data) 134 | local decoded = decode(encoded) 135 | expect(decoded).to.equal(data) 136 | end 137 | }, 138 | { 139 | name = name("false"), 140 | func = function() 141 | local data = false 142 | local encoded = encode(data) 143 | local decoded = decode(encoded) 144 | expect(decoded).to.equal(data) 145 | end 146 | }, 147 | { 148 | name = name("true"), 149 | func = function() 150 | local data = true 151 | local encoded = encode(data) 152 | local decoded = decode(encoded) 153 | expect(decoded).to.equal(data) 154 | end 155 | }, 156 | { 157 | name = name("float"), 158 | func = function() 159 | local numbers = { 160 | 0.0, 161 | -0.0, 162 | 1.0, 163 | -1.0, 164 | 2.0 ^ 0, 165 | 2.0 ^ 1, 166 | 2.0 ^ 10, 167 | 2.0 ^ 20, 168 | 2.0 ^ 30, 169 | 2.0 ^ -10, 170 | 2.0 ^ -30, 171 | 16777216.0, 172 | 16777217.0, 173 | 2147483647.0, 174 | -2147483648.0, 175 | 9007199254740991.0, 176 | 9007199254740992.0, 177 | 9007199254740993.0, 178 | 123456789.0, 179 | -123456789.0, 180 | 0.1, 181 | -0.1, 182 | 0.3, 183 | -0.3, 184 | 0.25, 185 | -0.25, 186 | 0.5, 187 | -0.5, 188 | 0.75, 189 | -0.75, 190 | 1.23456789, 191 | -1.23456789, 192 | 1.33333333, 193 | -1.33333333, 194 | 2.66666667, 195 | -2.66666667, 196 | 3.1415926535, 197 | -3.1415926535, 198 | math.pi, 199 | -math.pi, 200 | 1.0e-45, 201 | -1.0e-45, 202 | 1.0e-38, 203 | -1.0e-38, 204 | 1.0e-300, 205 | -1.0e-300, 206 | 1.0e-308, 207 | -1.0e-308, 208 | 1.17549435e-38, 209 | -1.17549435e-38, 210 | 1.0e38, 211 | -1.0e38, 212 | 1.0e300, 213 | -1.0e300, 214 | 1.0e308, 215 | -1.0e308, 216 | 1.7976931348623157e+308, 217 | -1.7976931348623157e+308, 218 | 1.0e309, 219 | -1.0e309, 220 | 4.9406564584124654e-324, 221 | -4.9406564584124654e-324, 222 | 1.0e-323, 223 | -1.0e-323, 224 | 2.0 ^ -1074, 225 | -2.0 ^ -1074, 226 | math.huge, 227 | -math.huge, 228 | 0 / 0, 229 | -0 / 0, 230 | 1.0 / 0.0 * 0.0, 231 | math.sqrt(-1.0), 232 | 1.401298464e-45, 233 | -1.401298464e-45, 234 | 5.0e-45, 235 | -5.0e-45, 236 | 123.456, 237 | -123.456, 238 | -0, 239 | 1.0e-10, 240 | -1.0e-10, 241 | 1.0e+10, 242 | -1.0e+10, 243 | 6.02214076e+23, 244 | -6.02214076e+23, 245 | 9.10938356e-31, 246 | -9.10938356e-31, 247 | 1.602176634e-19, 248 | -1.602176634e-19, 249 | 2.998e8, 250 | -2.998e8, 251 | 1.380649e-23, 252 | -1.380649e-23, 253 | 6.62607015e-34, 254 | -6.62607015e-34, 255 | 0.2, 256 | -0.2, 257 | 0.3333333333333333, 258 | -0.3333333333333333, 259 | 0.6666666666666666, 260 | -0.6666666666666666, 261 | 3.4028235e+38, 262 | -3.4028235e+38, 263 | 3.4028236e+38, 264 | -3.4028236e+38, 265 | 2.2250738585072014e-308, 266 | -2.2250738585072014e-308, 267 | 1.0e+1000, 268 | -1.0e+1000, 269 | 1.0e-324, 270 | -1.0e-324, 271 | 1.234e+2, 272 | -1.234e+2, 273 | 5.678e-3, 274 | -5.678e-3, 275 | } 276 | -- this is just to make sure that we are testing with actual floats 277 | -- vectors in gmod are single precision floats, so we give them a double and they convert it to a float :) 278 | -- the test will actually fail if we pass it just as it is 279 | local vec = Vector() 280 | local buffer = sfs.new_buffer() 281 | for _, original in ipairs(numbers) do 282 | vec.x = original -- double -> float 283 | original = vec.x -- now it's a float 284 | 285 | sfs.reset_buffer(buffer) 286 | 287 | Encoder.encoders.float(buffer, original) 288 | local encoded = sfs.end_buffer(buffer) 289 | 290 | local decoded = decode(encoded) 291 | expect_same_number(expect, decoded, original) 292 | end 293 | end 294 | }, 295 | { 296 | name = name("double"), 297 | func = function() 298 | local numbers = { 299 | 0.0, 300 | -0.0, 301 | 1.0, 302 | -1.0, 303 | 123.456, 304 | -123.456, 305 | 1.7976931348623157e+308, 306 | 4.9406564584124654e-324, 307 | -4.9406564584124654e-324, 308 | 2.2250738585072014e-308, 309 | 1.7976931348623e308, 310 | -1.7976931348623e308, 311 | math.huge, 312 | -math.huge, 313 | 0 / 0, 314 | 1, 315 | 2, 316 | -1.143243, 317 | 1.23456789e123, 318 | -1.23456789e-123, 319 | 2.0 ^ (-1074), 320 | 2.0 ^ (-1073), 321 | 2.0 ^ (-1022), 322 | 2.0 ^ (-1021), 323 | 2.0 ^ 0, 324 | 2.0 ^ 1, 325 | 2.0 ^ 10, 326 | 2.0 ^ 1023, 327 | 0.5, 328 | 0.25, 329 | 0.125, 330 | -0.5, 331 | -0.25, 332 | -0.125, 333 | 1 - 2.0 ^ (-52), 334 | 1 + 2.0 ^ (-52), 335 | 1 - 2.0 ^ (-53), 336 | 1 + 2.0 ^ (-53), 337 | 2 - 2.0 ^ (-51), 338 | 2 + 2.0 ^ (-51), 339 | 4 - 2.0 ^ (-50), 340 | 4 + 2.0 ^ (-50), 341 | math.pi, 342 | -math.pi, 343 | math.pi * 2, 344 | math.pi / 2, 345 | math.exp(1), 346 | -math.exp(1), 347 | 0.1, 348 | 0.2, 349 | 0.3, 350 | 0.123456789, 351 | -0.123456789, 352 | 1.7976931348623157e+308 / 2, 353 | 1.7976931348623157e+308 / 4, 354 | 1e308, 355 | 1e307, 356 | 1e306, 357 | 2.2250738585072014e-308 * 2, 358 | 2.2250738585072014e-308 * 4, 359 | 1e-307, 360 | 1e-306, 361 | 1e-305, 362 | 16777217.0, 363 | 16777219.0, 364 | -16777217.0, 365 | -16777219.0, 366 | 2.2250738585072009e-308, 367 | 2.2250738585072014e-308, 368 | -0, 369 | 123.456, 370 | -123.456, 371 | 0.0, 372 | -0.0, 373 | 1.0, 374 | -1.0, 375 | 2.0 ^ 0, 376 | 2.0 ^ 1, 377 | 2.0 ^ 10, 378 | 2.0 ^ 20, 379 | 2.0 ^ 30, 380 | 2.0 ^ -10, 381 | 2.0 ^ -30, 382 | 16777216.0, 383 | 16777217.0, 384 | 2147483647.0, 385 | -2147483648.0, 386 | 9007199254740991.0, 387 | 9007199254740992.0, 388 | 9007199254740993.0, 389 | 123456789.0, 390 | -123456789.0, 391 | 0.1, 392 | -0.1, 393 | 0.3, 394 | -0.3, 395 | 0.25, 396 | -0.25, 397 | 0.5, 398 | -0.5, 399 | 0.75, 400 | -0.75, 401 | 1.23456789, 402 | -1.23456789, 403 | 1.33333333, 404 | -1.33333333, 405 | 2.66666667, 406 | -2.66666667, 407 | 3.1415926535, 408 | -3.1415926535, 409 | math.pi, 410 | -math.pi, 411 | 1.0e-45, 412 | -1.0e-45, 413 | 1.0e-38, 414 | -1.0e-38, 415 | 1.0e-300, 416 | -1.0e-300, 417 | 1.0e-308, 418 | -1.0e-308, 419 | 1.17549435e-38, 420 | -1.17549435e-38, 421 | 1.0e38, 422 | -1.0e38, 423 | 1.0e300, 424 | -1.0e300, 425 | 1.0e308, 426 | -1.0e308, 427 | 1.7976931348623157e+308, 428 | -1.7976931348623157e+308, 429 | 1.0e309, 430 | -1.0e309, 431 | 4.9406564584124654e-324, 432 | -4.9406564584124654e-324, 433 | 1.0e-323, 434 | -1.0e-323, 435 | 2.0 ^ -1074, 436 | -2.0 ^ -1074, 437 | math.huge, 438 | -math.huge, 439 | 0 / 0, 440 | -0 / 0, 441 | 1.0 / 0.0 * 0.0, 442 | math.sqrt(-1.0), 443 | 1.401298464e-45, 444 | -1.401298464e-45, 445 | 5.0e-45, 446 | -5.0e-45, 447 | 123.456, 448 | -123.456, 449 | -0, 450 | 1.0e-10, 451 | -1.0e-10, 452 | 1.0e+10, 453 | -1.0e+10, 454 | 6.02214076e+23, 455 | -6.02214076e+23, 456 | 9.10938356e-31, 457 | -9.10938356e-31, 458 | 1.602176634e-19, 459 | -1.602176634e-19, 460 | 2.998e8, 461 | -2.998e8, 462 | 1.380649e-23, 463 | -1.380649e-23, 464 | 6.62607015e-34, 465 | -6.62607015e-34, 466 | 0.2, 467 | -0.2, 468 | 0.3333333333333333, 469 | -0.3333333333333333, 470 | 0.6666666666666666, 471 | -0.6666666666666666, 472 | 3.4028235e+38, 473 | -3.4028235e+38, 474 | 3.4028236e+38, 475 | -3.4028236e+38, 476 | 2.2250738585072014e-308, 477 | -2.2250738585072014e-308, 478 | 1.0e+1000, 479 | -1.0e+1000, 480 | 1.0e-324, 481 | -1.0e-324, 482 | 1.234e+2, 483 | -1.234e+2, 484 | 5.678e-3, 485 | -5.678e-3, 486 | } 487 | local buffer = sfs.new_buffer() 488 | for _, original in ipairs(numbers) do 489 | sfs.reset_buffer(buffer) 490 | 491 | Encoder.encoders.double(buffer, original) 492 | local encoded = sfs.end_buffer(buffer) 493 | 494 | local decoded = decode(encoded) 495 | expect_same_number(expect, decoded, original) 496 | end 497 | end 498 | }, 499 | { 500 | name = name("entity"), 501 | func = function() 502 | local ent = ents.GetAll()[1] 503 | local encoded = encode(ent) 504 | local decoded = decode(encoded) 505 | expect(decoded).to.equal(ent) 506 | end 507 | }, 508 | { 509 | name = name("null entity"), 510 | func = function() 511 | local ent = NULL 512 | local encoded = encode(ent) 513 | local decoded = decode(encoded) 514 | expect(decoded).to.equal(ent) 515 | end 516 | }, 517 | { 518 | name = name("world entity"), 519 | func = function() 520 | local ent = Entity(0) 521 | local encoded = encode(ent) 522 | local decoded = decode(encoded) 523 | expect(decoded).to.equal(ent) 524 | end 525 | }, 526 | { 527 | name = name("player"), 528 | func = function() 529 | if player.GetCount() == 0 then 530 | RunConsoleCommand("bot") 531 | end 532 | 533 | local ply = player.GetAll()[1] 534 | local encoded = encode(ply) 535 | local decoded = decode(encoded) 536 | expect(decoded).to.equal(ply) 537 | end 538 | }, 539 | { 540 | name = name("vector"), 541 | func = function() 542 | local vec = Vector(1, 2, 3) 543 | local encoded = encode(vec) 544 | local decoded = decode(encoded) 545 | expect(decoded).to.equal(vec) 546 | end 547 | }, 548 | { 549 | name = name("angle"), 550 | func = function() 551 | local ang = Angle(1, 2, 3) 552 | local encoded = encode(ang) 553 | local decoded = decode(encoded) 554 | expect(decoded).to.equal(ang) 555 | end 556 | }, 557 | { 558 | name = name("matrix"), 559 | func = function() 560 | local matrix = Matrix({ 561 | { -9, -6, 2, -10 }, 562 | { -3, -1, 2, -8 }, 563 | { 5.6, -1, 0, 1.1 }, 564 | { -7, -7, 3, -8 } 565 | }) 566 | local encoded = encode(matrix) 567 | local decoded = decode(encoded) 568 | expect(decoded).to.equal(matrix) 569 | end 570 | }, 571 | { 572 | name = name("color"), 573 | func = function() 574 | local col = Color(255, 0, 0, 255) 575 | local encoded = encode(col) 576 | local decoded = decode(encoded) 577 | expect(decoded).to.equal(col) 578 | end 579 | }, 580 | { 581 | name = name("positive_fixed"), 582 | func = function() 583 | local buffer = sfs.new_buffer() 584 | for i = 0, sfs.TYPES.positive_fixed.max do 585 | sfs.reset_buffer(buffer) 586 | Encoder.write_byte(buffer, sfs.TYPES.positive_fixed.start + i) 587 | local encoded = sfs.end_buffer(buffer) 588 | local decoded = decode(encoded) 589 | expect(decoded).to.equal(i) 590 | end 591 | expect(#sfs.encode(sfs.TYPES.positive_fixed.max)).to.equal(1) 592 | expect(#sfs.encode(sfs.TYPES.positive_fixed.max + 1)).to.equal(2) 593 | end 594 | }, 595 | { 596 | name = name("positive_u8"), 597 | func = function() 598 | local buffer = sfs.new_buffer() 599 | for i = 0, 255 do 600 | sfs.reset_buffer(buffer) 601 | Encoder.write_byte(buffer, sfs.TYPES.positive_u8.start) 602 | Encoder.write_u8(buffer, i) 603 | local encoded = sfs.end_buffer(buffer) 604 | local decoded = decode(encoded) 605 | expect(decoded).to.equal(i) 606 | end 607 | end 608 | }, 609 | { 610 | name = name("positive_u16"), 611 | func = function() 612 | local buffer = sfs.new_buffer() 613 | for i = 0, 65535 do 614 | sfs.reset_buffer(buffer) 615 | Encoder.write_byte(buffer, sfs.TYPES.positive_u16.start) 616 | Encoder.write_u16(buffer, i) 617 | local encoded = sfs.end_buffer(buffer) 618 | local decoded = decode(encoded) 619 | expect(decoded).to.equal(i) 620 | end 621 | end 622 | }, 623 | { 624 | name = name("positive_u32"), 625 | func = function() 626 | local to_test = generate_test_numbers(0, 4294967295) 627 | local TEST_POSITIVE_U32 = sfs.add_custom_type("bla bla", function() 628 | end, function(ctx) 629 | ctx[1] = ctx[1] + 1 630 | for i = 1, #to_test do 631 | local decoded = Decoder.read_u32(ctx) 632 | expect(decoded).to.equal(to_test[i]) 633 | end 634 | return true 635 | end) 636 | local buffer = sfs.new_buffer() 637 | Encoder.write_byte(buffer, TEST_POSITIVE_U32) 638 | for k, v in ipairs(to_test) do 639 | Encoder.write_u32(buffer, v) 640 | end 641 | local encoded = sfs.end_buffer(buffer) 642 | decode(encoded) 643 | end 644 | }, 645 | { 646 | name = name("positive_u53"), 647 | func = function() 648 | local to_test = generate_test_numbers(0, 9007199254740992) 649 | local TEST_POSITIVE_U53 = sfs.add_custom_type("bla bla 2", function() 650 | end, function(ctx) 651 | ctx[1] = ctx[1] + 1 652 | for i = 1, #to_test do 653 | local decoded = Decoder.read_u53(ctx) 654 | expect(decoded).to.equal(to_test[i]) 655 | end 656 | return true 657 | end) 658 | local buffer = sfs.new_buffer() 659 | Encoder.write_byte(buffer, TEST_POSITIVE_U53) 660 | for k, v in ipairs(to_test) do 661 | Encoder.write_u53(buffer, v) 662 | end 663 | local encoded = sfs.end_buffer(buffer) 664 | decode(encoded) 665 | end 666 | }, 667 | { 668 | name = name("negative_fixed"), 669 | func = function() 670 | local buffer = sfs.new_buffer() 671 | for i = 0, sfs.TYPES.negative_fixed.max do 672 | sfs.reset_buffer(buffer) 673 | Encoder.write_byte(buffer, sfs.TYPES.negative_fixed.start + i) 674 | local encoded = sfs.end_buffer(buffer) 675 | local decoded = decode(encoded) 676 | expect(decoded).to.equal(-i) 677 | end 678 | expect(#sfs.encode(-sfs.TYPES.negative_fixed.max)).to.equal(1) 679 | expect(#sfs.encode(-(sfs.TYPES.negative_fixed.max + 1))).to.equal(2) 680 | end 681 | }, 682 | { 683 | name = name("negative_u8"), 684 | func = function() 685 | local buffer = sfs.new_buffer() 686 | for i = 0, 255 do 687 | sfs.reset_buffer(buffer) 688 | Encoder.write_byte(buffer, sfs.TYPES.negative_u8.start) 689 | Encoder.write_u8(buffer, i) 690 | local encoded = sfs.end_buffer(buffer) 691 | local decoded = decode(encoded) 692 | expect(decoded).to.equal(-i) 693 | end 694 | end 695 | }, 696 | { 697 | name = name("negative_u16"), 698 | func = function() 699 | local buffer = sfs.new_buffer() 700 | for i = 0, 65535 do 701 | sfs.reset_buffer(buffer) 702 | Encoder.write_byte(buffer, sfs.TYPES.negative_u16.start) 703 | Encoder.write_u16(buffer, i) 704 | local encoded = sfs.end_buffer(buffer) 705 | local decoded = decode(encoded) 706 | expect(decoded).to.equal(-i) 707 | end 708 | end 709 | }, 710 | { 711 | name = name("negative_u32"), 712 | func = function() 713 | local to_test = generate_test_numbers(0, 4294967295) 714 | local buffer = sfs.new_buffer() 715 | for k, v in ipairs(to_test) do 716 | sfs.reset_buffer(buffer) 717 | Encoder.write_byte(buffer, sfs.TYPES.negative_u32.start) 718 | Encoder.write_u32(buffer, v) 719 | local encoded = sfs.end_buffer(buffer) 720 | local decoded = decode(encoded) 721 | expect(decoded).to.equal(-v) 722 | end 723 | end 724 | }, 725 | { 726 | name = name("negative_u53"), 727 | func = function() 728 | local to_test = generate_test_numbers(0, 4503599627370495) 729 | local buffer = sfs.new_buffer() 730 | for k, v in ipairs(to_test) do 731 | sfs.reset_buffer(buffer) 732 | Encoder.write_byte(buffer, sfs.TYPES.negative_u53.start) 733 | Encoder.write_u53(buffer, v) 734 | local encoded = sfs.end_buffer(buffer) 735 | local decoded = decode(encoded) 736 | expect(decoded).to.equal(-v) 737 | end 738 | end 739 | }, 740 | { 741 | name = name("i8"), 742 | func = function() 743 | local buffer = sfs.new_buffer() 744 | for i = -128, 127 do 745 | sfs.reset_buffer(buffer) 746 | Encoder.write_i8(buffer, i) 747 | local encoded = sfs.end_buffer(buffer) 748 | local decoder = Decoder.setup_context(encoded) 749 | local decoded = Decoder.read_i8(decoder) 750 | expect(decoded).to.equal(i) 751 | end 752 | end 753 | }, 754 | { 755 | name = name("i16"), 756 | func = function() 757 | local buffer = sfs.new_buffer() 758 | for i = -32768, 32767 do 759 | sfs.reset_buffer(buffer) 760 | Encoder.write_i16(buffer, i) 761 | local encoded = sfs.end_buffer(buffer) 762 | local decoder = Decoder.setup_context(encoded) 763 | local decoded = Decoder.read_i16(decoder) 764 | expect(decoded).to.equal(i) 765 | end 766 | end 767 | }, 768 | { 769 | name = name("i32"), 770 | func = function() 771 | local to_test = generate_test_numbers(-2147483648, 2147483647) 772 | local buffer = sfs.new_buffer() 773 | for k, v in ipairs(to_test) do 774 | sfs.reset_buffer(buffer) 775 | Encoder.write_i32(buffer, v) 776 | local encoded = sfs.end_buffer(buffer) 777 | local decoder = Decoder.setup_context(encoded) 778 | local decoded = Decoder.read_i32(decoder) 779 | expect(decoded).to.equal(v) 780 | end 781 | end 782 | }, 783 | { 784 | name = name("i53"), 785 | func = function() 786 | local to_test = generate_test_numbers(-4503599627370496, 4503599627370495) 787 | local buffer = sfs.new_buffer() 788 | for k, v in ipairs(to_test) do 789 | sfs.reset_buffer(buffer) 790 | Encoder.write_i53(buffer, v) 791 | local encoded = sfs.end_buffer(buffer) 792 | local decoder = Decoder.setup_context(encoded) 793 | local decoded = Decoder.read_i53(decoder) 794 | expect(decoded).to.equal(v) 795 | end 796 | end 797 | }, 798 | { 799 | name = name("string_fixed"), 800 | func = function() 801 | local buffer = sfs.new_buffer() 802 | for i = 0, sfs.TYPES.string_fixed.max do 803 | local str = string.rep("a", i) 804 | sfs.reset_buffer(buffer) 805 | Encoder.write_byte(buffer, sfs.TYPES.string_fixed.start + i) 806 | Encoder.write_str(buffer, str) 807 | local encoded = sfs.end_buffer(buffer) 808 | local decoded = decode(encoded) 809 | expect(decoded).to.equal(str) 810 | end 811 | expect(#sfs.encode(string.rep("a", sfs.TYPES.string_fixed.max))).to.equal(sfs.TYPES.string_fixed.max + 1) 812 | expect(#sfs.encode(string.rep("a", sfs.TYPES.string_fixed.max + 1))).to.equal(sfs.TYPES.string_fixed.max + 813 | 3) 814 | end 815 | }, 816 | { 817 | name = name("string_u8"), 818 | func = function() 819 | local to_test = generate_test_strings(255) 820 | local buffer = sfs.new_buffer() 821 | for k, v in ipairs(to_test) do 822 | sfs.reset_buffer(buffer) 823 | Encoder.write_byte(buffer, sfs.TYPES.string_u8.start) 824 | Encoder.write_u8(buffer, #v) 825 | Encoder.write_str(buffer, v) 826 | local encoded = sfs.end_buffer(buffer) 827 | local decoded = decode(encoded) 828 | expect(decoded).to.equal(v) 829 | end 830 | end 831 | }, 832 | { 833 | name = name("string_u16"), 834 | func = function() 835 | local to_test = generate_test_strings(65535) 836 | local buffer = sfs.new_buffer() 837 | for k, v in ipairs(to_test) do 838 | sfs.reset_buffer(buffer) 839 | Encoder.write_byte(buffer, sfs.TYPES.string_u16.start) 840 | Encoder.write_u16(buffer, #v) 841 | Encoder.write_str(buffer, v) 842 | local encoded = sfs.end_buffer(buffer) 843 | local decoded = decode(encoded) 844 | expect(decoded).to.equal(v) 845 | end 846 | end 847 | }, 848 | { 849 | name = name("string_u32"), 850 | func = function() 851 | local to_test = generate_test_strings(258435456) 852 | local buffer = sfs.new_buffer() 853 | for k, v in ipairs(to_test) do 854 | sfs.reset_buffer(buffer) 855 | Encoder.write_byte(buffer, sfs.TYPES.string_u32.start) 856 | Encoder.write_u32(buffer, #v) 857 | Encoder.write_str(buffer, v) 858 | local encoded = sfs.end_buffer(buffer) 859 | local decoded = decode(encoded) 860 | expect(decoded).to.equal(v) 861 | end 862 | collectgarbage() 863 | end 864 | }, 865 | { 866 | name = name("mixed_table_u8"), 867 | func = function() 868 | local to_test = generate_test_table(255, generate_test_array(255)) 869 | local encoded = sfs.encode(to_test) 870 | local decoded = sfs.decode(encoded) 871 | expect(are_equal(to_test, decoded)).to.beTrue() 872 | collectgarbage() 873 | end 874 | }, 875 | { 876 | name = name("mixed_table_u16"), 877 | func = function() 878 | local to_test = generate_test_table(65535, generate_test_array(65535)) 879 | local encoded = sfs.encode(to_test) 880 | local decoded = sfs.decode(encoded) 881 | expect(are_equal(to_test, decoded)).to.beTrue() 882 | collectgarbage() 883 | end 884 | }, 885 | { 886 | name = name("mixed_table_u32"), 887 | func = function() 888 | local to_test = generate_test_table(5999999, generate_test_array(5999999)) 889 | local encoded = sfs.encode(to_test) 890 | local decoded = sfs.decode(encoded) 891 | expect(are_equal(to_test, decoded)).to.beTrue() 892 | collectgarbage() 893 | end 894 | }, 895 | { 896 | name = name("sfs.encode_table_array_u8"), 897 | func = function() 898 | local to_test = generate_test_array(255) 899 | local encoded = sfs.encode(to_test) 900 | local decoded = sfs.decode(encoded) 901 | expect(are_equal(to_test, decoded)).to.beTrue() 902 | collectgarbage() 903 | end 904 | }, 905 | { 906 | name = name("sfs.encode_table_array_u16"), 907 | func = function() 908 | local to_test = generate_test_array(65535) 909 | local encoded = sfs.encode(to_test) 910 | local decoded = sfs.decode(encoded) 911 | expect(are_equal(to_test, decoded)).to.beTrue() 912 | collectgarbage() 913 | end 914 | }, 915 | { 916 | name = name("sfs.encode_table_array_u32"), 917 | func = function() 918 | local to_test = generate_test_array(5999999) 919 | local encoded = sfs.encode(to_test) 920 | local decoded = sfs.decode(encoded) 921 | expect(are_equal(to_test, decoded)).to.beTrue() 922 | collectgarbage() 923 | end 924 | }, 925 | { 926 | name = name("sfs.encode_table_hash_u8"), 927 | func = function() 928 | local to_test = generate_test_table(255) 929 | local encoded = sfs.encode(to_test) 930 | local decoded = sfs.decode(encoded) 931 | expect(are_equal(to_test, decoded)).to.beTrue() 932 | collectgarbage() 933 | end 934 | }, 935 | { 936 | name = name("sfs.encode_table_hash_u16"), 937 | func = function() 938 | local to_test = generate_test_table(65535) 939 | local encoded = sfs.encode(to_test) 940 | local decoded = sfs.decode(encoded) 941 | expect(are_equal(to_test, decoded)).to.beTrue() 942 | collectgarbage() 943 | end 944 | }, 945 | { 946 | name = name("sfs.encode_table_hash_u32"), 947 | func = function() 948 | local to_test = generate_test_table(5999999) 949 | local encoded = sfs.encode(to_test) 950 | local decoded = sfs.decode(sfs.encode(to_test)) 951 | encoded = nil 952 | collectgarbage() 953 | expect(are_equal(to_test, decoded)).to.beTrue() 954 | collectgarbage() 955 | end 956 | }, 957 | } 958 | } 959 | -------------------------------------------------------------------------------- /lua/sfs.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Copyright (c) 2024 Srlion 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | ]] 10 | 11 | local pairs = pairs 12 | local type = type 13 | local getmetatable = getmetatable 14 | local table_concat = table.concat 15 | local math_floor = math.floor 16 | local math_ldexp = math.ldexp 17 | local math_frexp = math.frexp 18 | 19 | -- string.char is not jit compiled in luajit 2.0.5 20 | local chars = {}; do 21 | for i = 0, 255 do 22 | chars[i] = string.char(i) 23 | end 24 | end 25 | -- 26 | 27 | local TYPES = {} 28 | local new_type; do 29 | local type_count = -1 30 | function new_type(name, n) 31 | n = n or 1 32 | if type_count + n > 255 then 33 | error("types count cannot be more than 256", 2) 34 | end 35 | 36 | local start_type = type_count + 1 37 | type_count = type_count + n 38 | 39 | TYPES[name] = { 40 | start = start_type, 41 | max = n - 1 42 | } 43 | 44 | if n == 1 then 45 | return start_type 46 | else 47 | return start_type, type_count - start_type 48 | end 49 | end 50 | end 51 | 52 | -- Simple types 53 | local NIL = new_type("nil") 54 | local FALSE = new_type("false") 55 | local TRUE = new_type("true") 56 | 57 | local FLOAT = new_type("float") 58 | local DOUBLE = new_type("double") 59 | 60 | -- Garry's Mod types 61 | local ENTITY = new_type("entity") 62 | local PLAYER = new_type("player") 63 | local VECTOR = new_type("vector") 64 | local ANGLE = new_type("angle") 65 | local MATRIX = new_type("matrix") 66 | local COLOR = new_type("color") 67 | 68 | -- reserved for future use to not break backwards compatibility incase we need to add more types 69 | local _ = new_type("reserved_1") 70 | local _ = new_type("reserved_2") 71 | local _ = new_type("reserved_3") 72 | local _ = new_type("reserved_4") 73 | -- 74 | 75 | -- 76 | local POSITIVE_FIXED_START, POSITIVE_FIXED_MAX = new_type("positive_fixed", 101) 77 | local POSITIVE_U8 = new_type("positive_u8") 78 | local POSITIVE_U16 = new_type("positive_u16") 79 | local POSITIVE_U32 = new_type("positive_u32") 80 | local POSITIVE_U53 = new_type("positive_u53") 81 | 82 | local NEGATIVE_FIXED_START, NEGATIVE_FIXED_MAX = new_type("negative_fixed", 55) 83 | local NEGATIVE_U8 = new_type("negative_u8") 84 | local NEGATIVE_U16 = new_type("negative_u16") 85 | local NEGATIVE_U32 = new_type("negative_u32") 86 | local NEGATIVE_U53 = new_type("negative_u53") 87 | 88 | local STRING_FIXED_START, STRING_FIXED_MAX = new_type("string_fixed", 56) 89 | local STRING_U8 = new_type("string_u8") 90 | local STRING_U16 = new_type("string_u16") 91 | local STRING_U32 = new_type("string_u32") 92 | 93 | local ARRAY = new_type("array") 94 | 95 | local TABLE = new_type("table") 96 | 97 | local ARRAY_AND_TABLE = new_type("array_and_table") 98 | 99 | local ENDING = new_type("ending") -- type used to end arrays and tables, can be used for custom types as well 100 | -- 101 | 102 | -- For user defined types 103 | local CUSTOM_START, CUSTOM_MAX = new_type("custom", 14) 104 | -- 105 | 106 | -- To tell Entity(0) (world) and NULL apart (since both have ent index 0), we use this (min i16 number) to represent NULL 107 | -- -1 = non networked entities 108 | -- 0 - 8192 = networked entities 109 | -- Thanks to Redox for reporting the -1 case and to RaphaelIT7 for explaining it 110 | local NULL_ENT_INDEX = -0x8000 111 | 112 | local STRING_TYPES = { 113 | [STRING_U8] = true, 114 | [STRING_U16] = true, 115 | [STRING_U32] = true, 116 | } 117 | for i = 0, STRING_FIXED_MAX do 118 | STRING_TYPES[STRING_FIXED_START + i] = true 119 | end 120 | 121 | local encoders = {} 122 | local Encoder = { 123 | encoders = encoders, 124 | ENDING = ENDING 125 | } 126 | do 127 | local function write_str(buf, str) 128 | local buf_len = buf[0] + 1 129 | buf[0] = buf_len 130 | buf[buf_len] = str 131 | end 132 | Encoder.write_str = write_str 133 | 134 | local function get_encoder_impl(t) 135 | local encoder = encoders[getmetatable(t)] 136 | if encoder == nil then 137 | encoder = encoders[type(t)] 138 | end 139 | return encoder 140 | end 141 | Encoder.get_encoder_impl = get_encoder_impl 142 | 143 | local function get_encoder(buf, t) 144 | local encoder = get_encoder_impl(t) 145 | if encoder == nil then 146 | write_str(buf, "unsupported type: ") 147 | write_str(buf, type(t)) 148 | return nil 149 | end 150 | return encoder 151 | end 152 | Encoder.get_encoder = get_encoder 153 | 154 | local function write_value(buf, val) 155 | local encoder = get_encoder(buf, val) 156 | if encoder == nil then 157 | return true 158 | end 159 | 160 | if encoder(buf, val) == true then 161 | return true 162 | end 163 | 164 | return false 165 | end 166 | Encoder.write_value = write_value 167 | 168 | local function write_byte(buf, chr) 169 | local buf_len = buf[0] + 1 170 | buf[0] = buf_len 171 | -- if chars[chr] == nil then 172 | -- print(true, chr) 173 | -- error("stop") 174 | -- return 175 | -- end 176 | buf[buf_len] = chars[chr] 177 | end 178 | Encoder.write_byte = write_byte 179 | 180 | local function write_u8(buf, num) 181 | write_byte(buf, num) 182 | end 183 | Encoder.write_u8 = write_u8 184 | 185 | local function write_u16(buf, num) 186 | write_byte(buf, math_floor(num / 0x100)) 187 | write_byte(buf, num % 0x100) 188 | end 189 | Encoder.write_u16 = write_u16 190 | 191 | local function write_u32(buf, num) 192 | write_byte(buf, math_floor(num / 0x1000000) % 0x100) 193 | write_byte(buf, math_floor(num / 0x10000) % 0x100) 194 | write_byte(buf, math_floor(num / 0x100) % 0x100) 195 | write_byte(buf, num % 0x100) 196 | end 197 | Encoder.write_u32 = write_u32 198 | 199 | local function write_u53(buf, num) 200 | write_byte(buf, math_floor(num / 0x1000000000000) % 0x100) 201 | write_byte(buf, math_floor(num / 0x10000000000) % 0x100) 202 | write_byte(buf, math_floor(num / 0x100000000) % 0x100) 203 | write_byte(buf, math_floor(num / 0x1000000) % 0x100) 204 | write_byte(buf, math_floor(num / 0x10000) % 0x100) 205 | write_byte(buf, math_floor(num / 0x100) % 0x100) 206 | write_byte(buf, num % 0x100) 207 | end 208 | Encoder.write_u53 = write_u53 209 | 210 | local function write_i8(buf, num) 211 | write_byte(buf, num % 0x100) 212 | end 213 | Encoder.write_i8 = write_i8 214 | 215 | local function write_i16(buf, num) 216 | write_u16(buf, num % 0x10000) 217 | end 218 | Encoder.write_i16 = write_i16 219 | 220 | local function write_i32(buf, num) 221 | write_u32(buf, num % 0x100000000) 222 | end 223 | Encoder.write_i32 = write_i32 224 | 225 | local function write_i53(buf, num) 226 | write_u53(buf, num % 0x20000000000000) 227 | end 228 | Encoder.write_i53 = write_i53 229 | 230 | local function write_varint(buf, tag, num) 231 | if num <= 255 then -- 0 - 255 (8 bits) 232 | write_byte(buf, tag) 233 | write_u8(buf, num) 234 | elseif num <= 65535 then -- 0 - 65535 (16 bits) 235 | write_byte(buf, tag + 1) 236 | write_u16(buf, num) 237 | elseif num <= 4294967295 then -- 0 - 4294967295 (32 bits) 238 | write_byte(buf, tag + 2) 239 | write_u32(buf, num) 240 | else -- 0 - 9007199254740992 (53 bits) 241 | write_byte(buf, tag + 3) 242 | write_u53(buf, num) 243 | end 244 | end 245 | Encoder.write_varint = write_varint 246 | 247 | -- write float expects a float not a double (you need to pass values that are actually floats) 248 | -- this is here for gmod types that are floats (eg. Vector, Angle) 249 | local function write_float(buf, num) 250 | local u32 = 0 251 | 252 | if num == 0 then 253 | u32 = 0x00000000 -- Positive zero 254 | if 1 / num < 0 then 255 | u32 = 0x80000000 -- Negative zero 256 | end 257 | write_u32(buf, u32) 258 | return u32 259 | elseif num ~= num then -- NaN check 260 | u32 = 0x7FFFFFFF 261 | write_u32(buf, u32) 262 | return u32 263 | end 264 | 265 | local sign = num < 0 and 1 or 0 266 | num = sign == 1 and -num or num 267 | 268 | if num == 1 / 0 then -- math.huge 269 | -- (sign << 31) + (0xFF << 23) 270 | u32 = (sign * (2 ^ 31)) + (0xFF * (2 ^ 23)) 271 | write_u32(buf, u32) 272 | return u32 273 | end 274 | 275 | local mantissa, exponent = math_frexp(num) 276 | mantissa = mantissa * 2 277 | exponent = exponent - 1 278 | 279 | local ieee_exponent = exponent + 127 -- IEEE 754 bias 280 | if ieee_exponent <= 0 then 281 | -- Handle subnormal numbers 282 | mantissa = math_ldexp(mantissa, ieee_exponent - 1) 283 | ieee_exponent = 0 284 | elseif ieee_exponent >= 255 then 285 | -- Handle overflow 286 | ieee_exponent = 255 287 | mantissa = 0 288 | end 289 | 290 | -- Scale mantissa to 23 bits and round 291 | local mantissa_bits = math_floor( 292 | ((mantissa - 1) * (2 ^ 23)) + 0.5 293 | ) 294 | 295 | -- Ensure mantissa doesn't exceed 23 bits 296 | mantissa_bits = mantissa_bits % (2 ^ 23) 297 | 298 | -- Combine all parts 299 | -- (sign << 31) | (ieee_exponent << 23) | mantissa_bits 300 | u32 = (sign * (2 ^ 31)) + (ieee_exponent * (2 ^ 23)) + mantissa_bits 301 | 302 | write_u32(buf, u32) 303 | return u32 304 | end 305 | Encoder.write_float = write_float 306 | 307 | local function write_double(buf, num) 308 | local u32_1 = 0 309 | local u32_2 = 0 310 | 311 | if num == 0 then 312 | u32_1 = 0x00000000 313 | if 1 / num < 0 then 314 | u32_1 = 0x80000000 315 | end 316 | write_u32(buf, u32_1) 317 | write_u32(buf, u32_2) 318 | return 319 | elseif num ~= num then -- NaN check 320 | u32_1 = 0x7FFFFFFF 321 | u32_2 = 1 322 | write_u32(buf, u32_1) 323 | write_u32(buf, u32_2) 324 | return 325 | end 326 | 327 | local sign = num < 0 and 1 or 0 328 | num = sign == 1 and -num or num 329 | 330 | if num == 1 / 0 then -- Infinity 331 | -- (sign << 31) | (0x7FF << 20) 332 | u32_1 = (sign * (2 ^ 31)) + (0x7FF * (2 ^ 20)) 333 | write_u32(buf, u32_1) 334 | write_u32(buf, u32_2) 335 | return 336 | end 337 | 338 | local mantissa, exponent = math_frexp(num) 339 | 340 | local ieee_exponent = exponent + 1022 341 | if ieee_exponent > 0 then 342 | -- Normal numbers 343 | local mantissa_scaled = (mantissa * 2 - 1) * (2 ^ 52) 344 | local mantissa_upper = math_floor(mantissa_scaled / (2 ^ 32)) -- (mantissa_scaled >> 32) 345 | local mantissa_lower = mantissa_scaled % (2 ^ 32) -- (mantissa_scaled & 0xFFFFFFFF) 346 | 347 | -- (sign << 31) | (ieee_exponent << 20) | (mantissa_upper % 2^20) 348 | u32_1 = (sign * (2 ^ 31)) + (ieee_exponent * (2 ^ 20)) + (mantissa_upper % (2 ^ 20)) 349 | u32_2 = mantissa_lower 350 | else 351 | -- Subnormal numbers 352 | local mantissa_scaled = mantissa * math_ldexp(1, 52 + ieee_exponent) 353 | local mantissa_upper = math_floor(mantissa_scaled / (2 ^ 32)) -- (mantissa_scaled >> 32) 354 | local mantissa_lower = mantissa_scaled % (2 ^ 32) -- (mantissa_scaled & 0xFFFFFFFF) 355 | 356 | -- (sign << 31) | (mantissa_upper & 0xFFFFF) 357 | u32_1 = (sign * (2 ^ 31)) + (mantissa_upper % (2 ^ 20)) 358 | u32_2 = mantissa_lower 359 | end 360 | 361 | write_u32(buf, u32_1) 362 | write_u32(buf, u32_2) 363 | end 364 | Encoder.write_double = write_double 365 | 366 | local function write_array(buf, arr, size) 367 | for i = 1, size do 368 | if write_value(buf, arr[i]) then 369 | return true 370 | end 371 | end 372 | end 373 | Encoder.write_array = write_array 374 | 375 | local function write_table(buf, tbl) 376 | for key, val in pairs(tbl) do 377 | if write_value(buf, key) or write_value(buf, val) then 378 | return true 379 | end 380 | end 381 | end 382 | Encoder.write_table = write_table 383 | 384 | function Encoder.read_error(buf) 385 | return table_concat(buf, nil, buf[0] - 1, buf[0]) 386 | end 387 | 388 | do 389 | local buffer = { 390 | [0] = 0 -- length 391 | } 392 | 393 | function Encoder.encode(val, max_cache_size) 394 | max_cache_size = max_cache_size or 2000 395 | buffer[0] = 0 396 | 397 | -- returns true when failed to encode 398 | -- error is never compiled, so we never error to avoid that 399 | -- concatenating in luajit 2.0.5 is NYI, we make sure that all encoders' functions get jit compiled 400 | if write_value(buffer, val) then 401 | return nil, Encoder.read_error(buffer) 402 | end 403 | 404 | local result = table_concat(buffer, nil, 1, buffer[0]) 405 | 406 | if #buffer > max_cache_size then 407 | buffer = { 408 | [0] = 0 -- buffer length 409 | } 410 | end 411 | 412 | return result 413 | end 414 | end 415 | 416 | encoders["nil"] = function(buf, v) 417 | write_byte(buf, NIL) 418 | end 419 | 420 | encoders.boolean = function(buf, v) 421 | if v == false then 422 | write_byte(buf, FALSE) 423 | else 424 | write_byte(buf, TRUE) 425 | end 426 | end 427 | 428 | encoders.float = function(buf, num) 429 | write_byte(buf, FLOAT) 430 | write_float(buf, num) 431 | end 432 | 433 | encoders.double = function(buf, num) 434 | write_byte(buf, DOUBLE) 435 | write_double(buf, num) 436 | end 437 | 438 | encoders.string = function(buf, str) 439 | local str_len = #str 440 | 441 | if str_len <= STRING_FIXED_MAX then 442 | write_byte(buf, STRING_FIXED_START + str_len) 443 | else 444 | write_varint(buf, STRING_U8, str_len) 445 | end 446 | 447 | if str_len > 0 then 448 | write_str(buf, str) 449 | end 450 | end 451 | 452 | encoders.array = function(buf, arr, size) 453 | if size then 454 | if size < 0 then 455 | write_str(buf, "array size cannot be negative: ") 456 | write_str(buf, size) 457 | return true 458 | end 459 | else 460 | size = #arr 461 | end 462 | write_byte(buf, ARRAY) 463 | write_array(buf, arr, size) 464 | write_byte(buf, ENDING) 465 | end 466 | 467 | encoders.table = function(buf, tbl) 468 | -- save position where we'll write the tag 469 | local tag_pos = buf[0] + 1 470 | buf[0] = tag_pos 471 | buf[tag_pos] = chars[ARRAY] -- assume array initially 472 | 473 | local n = 0 474 | local is_pure_array = true 475 | 476 | for k, v in pairs(tbl) do 477 | if is_pure_array then 478 | -- check if this key breaks array assumption 479 | if type(k) ~= "number" or k ~= n + 1 or k % 1 ~= 0 then 480 | -- if it's pure hash, then write as table directly 481 | if n == 0 then 482 | buf[tag_pos] = chars[TABLE] 483 | else 484 | buf[tag_pos] = chars[ARRAY_AND_TABLE] 485 | -- write ENDING to mark end of array part 486 | write_byte(buf, ENDING) 487 | end 488 | 489 | is_pure_array = false 490 | 491 | -- write current key-value (the one that broke the array) 492 | if write_value(buf, k) or write_value(buf, v) then 493 | return true 494 | end 495 | else 496 | -- still an array 497 | n = n + 1 498 | if write_value(buf, v) then 499 | return true 500 | end 501 | end 502 | else 503 | -- already in hash mode, write key-value 504 | if write_value(buf, k) or write_value(buf, v) then 505 | return true 506 | end 507 | end 508 | end 509 | 510 | write_byte(buf, ENDING) 511 | end 512 | 513 | encoders.number = function(buf, num) 514 | -- a number like 1.7976931348623e308 will fail with % 1 ~= 0, but if you subtract 1 from it, it will still equal itself 515 | if num % 1 ~= 0 or num - 1 == num then -- DOUBLE 516 | write_byte(buf, DOUBLE) 517 | write_double(buf, num) 518 | return 519 | end 520 | 521 | -- check if it's a positive number (this is weird but to check for -0) 522 | if 1 / num > 0 then 523 | if num <= POSITIVE_FIXED_MAX then 524 | write_byte(buf, POSITIVE_FIXED_START + num) 525 | else 526 | write_varint(buf, POSITIVE_U8, num) 527 | end 528 | else 529 | num = -num 530 | if num <= NEGATIVE_FIXED_MAX then 531 | write_byte(buf, NEGATIVE_FIXED_START + num) 532 | else 533 | write_varint(buf, NEGATIVE_U8, num) 534 | end 535 | end 536 | end 537 | 538 | -- Garry's Mod types 539 | local Entity_EntIndex = FindMetaTable and FindMetaTable("Entity").EntIndex 540 | encoders.Entity = function(buf, ent) 541 | write_byte(buf, ENTITY) 542 | if ent == NULL then 543 | write_i16(buf, NULL_ENT_INDEX) 544 | else 545 | write_i16(buf, Entity_EntIndex(ent)) 546 | end 547 | end 548 | 549 | -- All of these are reported as their own type but are otherwise identical in handling to entities 550 | encoders.Weapon = encoders.Entity 551 | encoders.Vehicle = encoders.Entity 552 | encoders.NextBot = encoders.Entity 553 | encoders.NPC = encoders.Entity 554 | 555 | -- range between 1 and 128 for players, so we can safely use uint8 556 | encoders.Player = function(buf, ply) 557 | write_byte(buf, PLAYER) 558 | write_u8(buf, Entity_EntIndex(ply)) 559 | end 560 | 561 | local Vector_Unpack = FindMetaTable and FindMetaTable("Vector").Unpack 562 | encoders.Vector = function(buf, vec) 563 | write_byte(buf, VECTOR) 564 | 565 | local x, y, z = Vector_Unpack(vec) 566 | write_float(buf, x) 567 | write_float(buf, y) 568 | write_float(buf, z) 569 | end 570 | 571 | local Angle_Unpack = FindMetaTable and FindMetaTable("Angle").Unpack 572 | encoders.Angle = function(buf, ang) 573 | write_byte(buf, ANGLE) 574 | 575 | local p, y, r = Angle_Unpack(ang) 576 | write_float(buf, p) 577 | write_float(buf, y) 578 | write_float(buf, r) 579 | end 580 | 581 | -- :] 582 | local MATRIX_ToTable = FindMetaTable and FindMetaTable("VMatrix").ToTable 583 | encoders.VMatrix = function(buf, mat) 584 | write_byte(buf, MATRIX) 585 | 586 | local matrix = MATRIX_ToTable(mat) 587 | for i = 1, 4 do 588 | for j = 1, 4 do 589 | write_float(buf, matrix[i][j]) 590 | end 591 | end 592 | end 593 | 594 | local COLOR_META = FindMetaTable and FindMetaTable("Color") 595 | if COLOR_META then 596 | encoders[COLOR_META] = function(buf, col) 597 | write_byte(buf, COLOR) 598 | 599 | write_u8(buf, math_floor(col.r)) 600 | write_u8(buf, math_floor(col.g)) 601 | write_u8(buf, math_floor(col.b)) 602 | write_u8(buf, math_floor(col.a)) 603 | end 604 | end 605 | 606 | -- function encoding will never be supported, so just skip it 607 | encoders["function"] = function() 608 | end 609 | end 610 | 611 | local decoders = {} 612 | local Decoder = { 613 | decoders = decoders 614 | } 615 | do 616 | local string_byte = string.byte 617 | local string_sub = string.sub 618 | 619 | -- Context Structure 620 | local context = { 621 | 1, -- index 622 | "", -- bytes 623 | 0, -- bytes length 624 | 1 / 0 -- max size for decode (math.huge) 625 | } 626 | 627 | local function peak_type(ctx) 628 | return string_byte(ctx[2], ctx[1]) 629 | end 630 | Decoder.peak_type = peak_type 631 | 632 | local function get_decoder(ctx) 633 | local tpy = peak_type(ctx) 634 | local decoder = decoders[tpy] 635 | if decoder == nil then 636 | return nil, "unsupported type: ", tpy 637 | end 638 | return decoder 639 | end 640 | Decoder.get_decoder = get_decoder 641 | 642 | local function read_value(ctx) 643 | local decoder, val, err, err2 644 | 645 | decoder, err, err2 = get_decoder(ctx) 646 | if err then 647 | if err2 then 648 | return nil, err .. err2 649 | end 650 | return nil, err 651 | end 652 | 653 | val, err = decoder(ctx) 654 | if err then 655 | return nil, err 656 | end 657 | 658 | return val 659 | end 660 | Decoder.read_value = read_value 661 | 662 | local function read_byte(ctx, size) 663 | local idx = ctx[1] 664 | if idx + size - 1 > ctx[3] then -- ctx[3] bytes length 665 | return nil, "bytes underflow" 666 | elseif idx + size - 1 > ctx[4] then -- ctx[4] max size 667 | return nil, "bytes overflow" 668 | end 669 | ctx[1] = idx + size 670 | return string_byte(ctx[2], idx, idx + size - 1) 671 | end 672 | Decoder.read_byte = read_byte 673 | 674 | local function read_str(ctx, size) 675 | local idx = ctx[1] 676 | if idx + size - 1 > ctx[3] then -- ctx[3] bytes length 677 | return nil, "bytes underflow" 678 | elseif idx + size - 1 > ctx[4] then -- ctx[4] max size 679 | return nil, "bytes overflow" 680 | end 681 | ctx[1] = idx + size 682 | return string_sub(ctx[2], idx, idx + size - 1) 683 | end 684 | Decoder.read_str = read_str 685 | 686 | local function read_u8(ctx) 687 | local bty, err = read_byte(ctx, 1) 688 | if err then 689 | return nil, err 690 | end 691 | return bty 692 | end 693 | Decoder.read_u8 = read_u8 694 | 695 | local function read_u16(ctx) 696 | local b1, b2 = read_byte(ctx, 2) -- read_byte returns multiple values, but error can be the second value 697 | if b1 == nil then 698 | return nil, b2 699 | end 700 | return b1 * 0x100 + b2 701 | end 702 | Decoder.read_u16 = read_u16 703 | 704 | local function read_u32(ctx) 705 | local b1, b2, b3, b4 = read_byte(ctx, 4) 706 | if b1 == nil then 707 | return nil, b2 708 | end 709 | return b1 * 0x1000000 + b2 * 0x10000 + b3 * 0x100 + b4 710 | end 711 | Decoder.read_u32 = read_u32 712 | 713 | local function read_u53(ctx) 714 | local b1, b2, b3, b4, b5, b6, b7 = read_byte(ctx, 7) 715 | if b1 == nil then 716 | return nil, b2 717 | end 718 | return b1 * 0x1000000000000 719 | + b2 * 0x10000000000 720 | + b3 * 0x100000000 721 | + b4 * 0x1000000 722 | + b5 * 0x10000 723 | + b6 * 0x100 724 | + b7 725 | end 726 | Decoder.read_u53 = read_u53 727 | 728 | local function read_i8(ctx) 729 | local u, err = read_u8(ctx); if err then return nil, err end 730 | if u >= 0x80 then u = u - 0x100 end 731 | return u 732 | end 733 | Decoder.read_i8 = read_i8 734 | 735 | local function read_i16(ctx) 736 | local u, err = read_u16(ctx); if err then return nil, err end 737 | if u >= 0x8000 then u = u - 0x10000 end 738 | return u 739 | end 740 | Decoder.read_i16 = read_i16 741 | 742 | local function read_i32(ctx) 743 | local u, err = read_u32(ctx); if err then return nil, err end 744 | if u >= 0x80000000 then u = u - 0x100000000 end 745 | return u 746 | end 747 | Decoder.read_i32 = read_i32 748 | 749 | local function read_i53(ctx) 750 | local u, err = read_u53(ctx); if err then return nil, err end 751 | if u >= 0x10000000000000 then u = u - 0x20000000000000 end 752 | return u 753 | end 754 | Decoder.read_i53 = read_i53 755 | 756 | local function read_float(ctx) 757 | local u32, err = read_u32(ctx) 758 | if err then 759 | return nil, err 760 | end 761 | 762 | -- ((u32 >> 31) & 1) == 1 and -1 or 1 763 | local sign = math_floor(u32 / (2 ^ 31)) % 2 == 1 and -1 or 1 764 | -- (u32 >> 23) & 0xFF 765 | local exponent_field = math_floor(u32 / (2 ^ 23)) % (2 ^ 8) 766 | -- u32 & 0x7FFFFF 767 | local mantissa = u32 % (2 ^ 23) 768 | 769 | if exponent_field == 0xFF then 770 | if mantissa == 0 then 771 | return sign * (1 / 0) -- math.huge 772 | end 773 | return 0 / 0 -- NaN 774 | end 775 | 776 | if exponent_field == 0 and mantissa == 0 then 777 | return sign * 0 -- Zero 778 | end 779 | 780 | -- mantissa >> 23 781 | local mantissa_scaled = mantissa / (2 ^ 23) 782 | 783 | if exponent_field ~= 0 then 784 | -- Normal numbers 785 | mantissa_scaled = mantissa_scaled + 1 786 | local actual_exponent = exponent_field - 127 787 | return sign * math_ldexp(mantissa_scaled, actual_exponent) 788 | else 789 | -- Subnormal numbers 790 | return sign * math_ldexp(mantissa_scaled, -126) 791 | end 792 | end 793 | Decoder.read_float = read_float 794 | 795 | local function read_double(ctx) 796 | local u32_1, u32_2, err 797 | 798 | u32_1, err = read_u32(ctx) 799 | if err then return nil, err end 800 | 801 | u32_2, err = read_u32(ctx) 802 | if err then return nil, err end 803 | 804 | -- ((u32_1 >> 31) & 1) == 1 and -1 or 1 805 | local sign = math_floor(u32_1 / (2 ^ 31)) % 2 == 1 and -1 or 1 806 | -- (u32_1 >> 20) & 0x7FF 807 | local exponent_field = math_floor(u32_1 / (2 ^ 20)) % (2 ^ 11) 808 | -- u32_1 & 0xFFFFF 809 | local mantissa_upper = u32_1 % (2 ^ 20) 810 | 811 | if exponent_field == 0x7FF then 812 | if mantissa_upper == 0 and u32_2 == 0 then 813 | return sign * (1 / 0) -- math.huge 814 | end 815 | return 0 / 0 -- NaN 816 | end 817 | 818 | if exponent_field == 0 and mantissa_upper == 0 and u32_2 == 0 then 819 | return sign * 0 -- Zero 820 | end 821 | 822 | -- mantissa_upper << 32 + u32_2 823 | local mantissa_scaled = mantissa_upper * (2 ^ 32) + u32_2 824 | 825 | if exponent_field ~= 0 then 826 | -- Normal numbers 827 | mantissa_scaled = (mantissa_scaled / (2 ^ 52)) + 1 828 | local actual_exponent = exponent_field - 1023 829 | return sign * math_ldexp(mantissa_scaled, actual_exponent) 830 | else 831 | -- Subnormal numbers 832 | mantissa_scaled = mantissa_scaled / (2 ^ 52) 833 | return sign * math_ldexp(mantissa_scaled, -1022) 834 | end 835 | end 836 | Decoder.read_double = read_double 837 | 838 | local function read_array(ctx, till) 839 | local arr = { nil, nil, nil, nil, nil, nil, nil, nil, nil, nil } -- initialize with size of 10 840 | local size = 0 841 | while peak_type(ctx) ~= till do 842 | local val, err = read_value(ctx) 843 | if err then 844 | return nil, err 845 | end 846 | size = size + 1 847 | arr[size] = val 848 | end 849 | ctx[1] = ctx[1] + 1 -- skip the ending type 850 | return arr, nil, size 851 | end 852 | Decoder.read_array = read_array 853 | 854 | local function read_table(ctx, till) 855 | local tbl = { nil, nil, nil, nil, nil, nil, nil, nil, nil, nil } -- initialize with size of 10 856 | while peak_type(ctx) ~= till do 857 | local key, val, err 858 | key, err = read_value(ctx) 859 | if err then 860 | return nil, err 861 | end 862 | val, err = read_value(ctx) 863 | if err then 864 | return nil, err 865 | end 866 | tbl[key] = val 867 | end 868 | ctx[1] = ctx[1] + 1 -- skip the ending type 869 | return tbl 870 | end 871 | Decoder.read_table = read_table 872 | 873 | function Decoder.setup_context(bytes, max_size) 874 | if type(bytes) ~= "string" then 875 | return nil, "bytes must be a string" 876 | end 877 | 878 | if max_size == nil then 879 | max_size = 1 / 0 -- math.huge 880 | elseif type(max_size) ~= "number" then 881 | return nil, "max_size must be a number" 882 | elseif max_size < 1 then 883 | return nil, "max_size must be greater than 0" 884 | end 885 | 886 | context[1] = 1 887 | context[2] = bytes 888 | context[3] = #bytes 889 | context[4] = max_size 890 | 891 | if context[3] < 1 then 892 | return nil, "no bytes to decode" 893 | end 894 | 895 | return context 896 | end 897 | 898 | function Decoder.decode(bytes, max_size) 899 | do 900 | local _, err = Decoder.setup_context(bytes, max_size) 901 | if err then 902 | return nil, err 903 | end 904 | end 905 | 906 | local val, err = read_value(context) 907 | if err then 908 | return nil, err 909 | end 910 | 911 | return val 912 | end 913 | 914 | decoders[NIL] = function(ctx) 915 | ctx[1] = ctx[1] + 1 916 | return nil 917 | end 918 | 919 | decoders[FALSE] = function(ctx) 920 | ctx[1] = ctx[1] + 1 921 | return false 922 | end 923 | 924 | decoders[TRUE] = function(ctx) 925 | ctx[1] = ctx[1] + 1 926 | return true 927 | end 928 | 929 | decoders[FLOAT] = function(ctx) 930 | ctx[1] = ctx[1] + 1 931 | return read_float(ctx) 932 | end 933 | 934 | decoders[DOUBLE] = function(ctx) 935 | ctx[1] = ctx[1] + 1 936 | return read_double(ctx) 937 | end 938 | 939 | -- Garry's Mod types 940 | local Entity = Entity 941 | decoders[ENTITY] = function(ctx) 942 | ctx[1] = ctx[1] + 1 943 | local ent_idx, err = read_i16(ctx) 944 | if err then 945 | return nil, err 946 | end 947 | if ent_idx == NULL_ENT_INDEX then 948 | return NULL 949 | end 950 | return Entity(ent_idx) 951 | end 952 | 953 | decoders[PLAYER] = function(ctx) 954 | ctx[1] = ctx[1] + 1 955 | local ply_uid, err = read_u8(ctx) 956 | if err then 957 | return nil, err 958 | end 959 | return Entity(ply_uid) 960 | end 961 | 962 | local Vector = Vector 963 | decoders[VECTOR] = function(ctx) 964 | ctx[1] = ctx[1] + 1 965 | 966 | local x, y, z, err 967 | 968 | x, err = read_float(ctx) 969 | if err then return nil, err end 970 | 971 | y, err = read_float(ctx) 972 | if err then return nil, err end 973 | 974 | z, err = read_float(ctx) 975 | if err then return nil, err end 976 | 977 | return Vector(x, y, z) 978 | end 979 | 980 | local Angle = Angle 981 | decoders[ANGLE] = function(ctx) 982 | ctx[1] = ctx[1] + 1 983 | 984 | local p, y, r, err 985 | 986 | p, err = read_float(ctx) 987 | if err then return nil, err end 988 | 989 | y, err = read_float(ctx) 990 | if err then return nil, err end 991 | 992 | r, err = read_float(ctx) 993 | if err then return nil, err end 994 | 995 | return Angle(p, y, r) 996 | end 997 | 998 | local Matrix = Matrix 999 | decoders[MATRIX] = function(ctx) 1000 | ctx[1] = ctx[1] + 1 1001 | 1002 | local matrix, err = {}, nil 1003 | for i = 1, 4 do 1004 | matrix[i] = {} 1005 | for j = 1, 4 do 1006 | matrix[i][j], err = read_float(ctx) 1007 | if err then 1008 | return nil, err 1009 | end 1010 | end 1011 | end 1012 | 1013 | return Matrix(matrix) 1014 | end 1015 | 1016 | local Color = Color 1017 | decoders[COLOR] = function(ctx) 1018 | ctx[1] = ctx[1] + 1 1019 | 1020 | local r, g, b, a, err 1021 | 1022 | r, err = read_u8(ctx) 1023 | if err then return nil, err end 1024 | 1025 | g, err = read_u8(ctx) 1026 | if err then return nil, err end 1027 | 1028 | b, err = read_u8(ctx) 1029 | if err then return nil, err end 1030 | 1031 | a, err = read_u8(ctx) 1032 | if err then return nil, err end 1033 | 1034 | return Color(r, g, b, a) 1035 | end 1036 | 1037 | -- 1038 | decoders[POSITIVE_U8] = function(ctx) 1039 | ctx[1] = ctx[1] + 1 1040 | 1041 | local num, err = read_u8(ctx) 1042 | if err then return nil, err end 1043 | return num 1044 | end 1045 | 1046 | decoders[POSITIVE_U16] = function(ctx) 1047 | ctx[1] = ctx[1] + 1 1048 | 1049 | local num, err = read_u16(ctx) 1050 | if err then return nil, err end 1051 | return num 1052 | end 1053 | 1054 | decoders[POSITIVE_U32] = function(ctx) 1055 | ctx[1] = ctx[1] + 1 1056 | 1057 | local num, err = read_u32(ctx) 1058 | if err then return nil, err end 1059 | return num 1060 | end 1061 | 1062 | decoders[POSITIVE_U53] = function(ctx) 1063 | ctx[1] = ctx[1] + 1 1064 | 1065 | local num, err = read_u53(ctx) 1066 | if err then return nil, err end 1067 | return num 1068 | end 1069 | -- 1070 | 1071 | -- 1072 | decoders[NEGATIVE_U8] = function(ctx) 1073 | ctx[1] = ctx[1] + 1 1074 | 1075 | local num, err = read_u8(ctx) 1076 | if err then return nil, err end 1077 | return -num 1078 | end 1079 | 1080 | decoders[NEGATIVE_U16] = function(ctx) 1081 | ctx[1] = ctx[1] + 1 1082 | 1083 | local num, err = read_u16(ctx) 1084 | if err then return nil, err end 1085 | return -num 1086 | end 1087 | 1088 | decoders[NEGATIVE_U32] = function(ctx) 1089 | ctx[1] = ctx[1] + 1 1090 | 1091 | local num, err = read_u32(ctx) 1092 | if err then return nil, err end 1093 | return -num 1094 | end 1095 | 1096 | decoders[NEGATIVE_U53] = function(ctx) 1097 | ctx[1] = ctx[1] + 1 1098 | 1099 | local num, err = read_u53(ctx) 1100 | if err then return nil, err end 1101 | return -num 1102 | end 1103 | -- 1104 | 1105 | -- 1106 | decoders[STRING_U8] = function(ctx) 1107 | ctx[1] = ctx[1] + 1 1108 | 1109 | local str_len, str, err 1110 | 1111 | str_len, err = read_u8(ctx) 1112 | if err then return nil, err end 1113 | 1114 | str, err = read_str(ctx, str_len) 1115 | if err then return nil, err end 1116 | 1117 | return str 1118 | end 1119 | 1120 | decoders[STRING_U16] = function(ctx) 1121 | ctx[1] = ctx[1] + 1 1122 | 1123 | local str_len, str, err 1124 | 1125 | str_len, err = read_u16(ctx) 1126 | if err then return nil, err end 1127 | 1128 | str, err = read_str(ctx, str_len) 1129 | if err then return nil, err end 1130 | 1131 | return str 1132 | end 1133 | 1134 | decoders[STRING_U32] = function(ctx) 1135 | ctx[1] = ctx[1] + 1 1136 | 1137 | local str_len, str, err 1138 | 1139 | str_len, err = read_u32(ctx) 1140 | if err then return nil, err end 1141 | 1142 | str, err = read_str(ctx, str_len) 1143 | if err then return nil, err end 1144 | 1145 | return str 1146 | end 1147 | -- 1148 | 1149 | -- 1150 | decoders[ARRAY] = function(ctx) 1151 | ctx[1] = ctx[1] + 1 1152 | local arr, err = read_array(ctx, ENDING) 1153 | if err then return nil, err end 1154 | return arr 1155 | end 1156 | 1157 | decoders[TABLE] = function(ctx) 1158 | ctx[1] = ctx[1] + 1 1159 | local tbl, err = read_table(ctx, ENDING) 1160 | if err then return nil, err end 1161 | return tbl 1162 | end 1163 | 1164 | decoders[ARRAY_AND_TABLE] = function(ctx) 1165 | ctx[1] = ctx[1] + 1 1166 | 1167 | -- array part first 1168 | local arr, err = read_array(ctx, ENDING) 1169 | if err then return nil, err end 1170 | 1171 | -- hash part 1172 | while peak_type(ctx) ~= ENDING do 1173 | local key, val 1174 | key, err = read_value(ctx) 1175 | if err then return nil, err end 1176 | val, err = read_value(ctx) 1177 | if err then return nil, err end 1178 | arr[key] = val 1179 | end 1180 | 1181 | ctx[1] = ctx[1] + 1 -- skip final ENDING 1182 | return arr 1183 | end 1184 | 1185 | 1186 | -- 1187 | decoders[STRING_FIXED_START] = function(ctx) 1188 | local bty, str, err 1189 | 1190 | bty, err = read_byte(ctx, 1) 1191 | if err then return nil, err end 1192 | 1193 | local str_len = bty - STRING_FIXED_START 1194 | 1195 | str, err = read_str(ctx, str_len) 1196 | if err then return nil, err end 1197 | 1198 | return str 1199 | end 1200 | 1201 | for i = 1, STRING_FIXED_MAX do 1202 | decoders[STRING_FIXED_START + i] = decoders[STRING_FIXED_START] 1203 | end 1204 | -- 1205 | -- 1206 | decoders[POSITIVE_FIXED_START] = function(ctx) 1207 | local bty, num, err 1208 | 1209 | bty, err = read_byte(ctx, 1) 1210 | if err then return nil, err end 1211 | 1212 | num = bty - POSITIVE_FIXED_START 1213 | return num 1214 | end 1215 | 1216 | for i = 1, POSITIVE_FIXED_MAX do 1217 | decoders[POSITIVE_FIXED_START + i] = decoders[POSITIVE_FIXED_START] 1218 | end 1219 | -- 1220 | 1221 | -- 1222 | decoders[NEGATIVE_FIXED_START] = function(ctx) 1223 | local bty, num, err 1224 | 1225 | bty, err = read_byte(ctx, 1) 1226 | if err then return nil, err end 1227 | 1228 | num = bty - NEGATIVE_FIXED_START 1229 | return -num 1230 | end 1231 | 1232 | for i = 1, NEGATIVE_FIXED_MAX do 1233 | decoders[NEGATIVE_FIXED_START + i] = decoders[NEGATIVE_FIXED_START] 1234 | end 1235 | -- 1236 | 1237 | decoders.string = function(ctx) 1238 | local bty = peak_type(ctx) 1239 | if not STRING_TYPES[bty] then 1240 | return nil, "expected string type" 1241 | end 1242 | return read_value(ctx) 1243 | end 1244 | end 1245 | 1246 | local encode_to_hex, decode_from_hex; do 1247 | local byte = string.byte 1248 | local char = string.char 1249 | local string_format = string.format 1250 | local string_gsub = string.gsub 1251 | local tonumber = tonumber 1252 | 1253 | local function hex(c) 1254 | local b = byte(c) 1255 | return (string_format("%02X", b)) 1256 | end 1257 | 1258 | local function string_to_hex(str) 1259 | return (string_gsub(str, ".", hex)) 1260 | end 1261 | 1262 | function encode_to_hex(val) 1263 | local encoded, err = Encoder.encode(val) 1264 | if err then 1265 | return nil, err 1266 | end 1267 | local hexed = string_to_hex(encoded) 1268 | return hexed 1269 | end 1270 | 1271 | local function from_hex(c) 1272 | return char(tonumber(c, 16)) 1273 | end 1274 | 1275 | local function hex_to_string(str) 1276 | return (string_gsub(str, "..", from_hex)) 1277 | end 1278 | 1279 | function decode_from_hex(str) 1280 | local ok, unhexed = pcall(hex_to_string, str) 1281 | if not ok then 1282 | return nil, unhexed 1283 | end 1284 | local decoded, err = Decoder.decode(unhexed) 1285 | if err then 1286 | return nil, err 1287 | end 1288 | return decoded 1289 | end 1290 | end 1291 | 1292 | return { 1293 | TYPES = TYPES, 1294 | STRING_TYPES = STRING_TYPES, 1295 | 1296 | Encoder = Encoder, -- to allow usage of internal functions 1297 | Decoder = Decoder, -- to allow usage of internal functions 1298 | 1299 | encode = Encoder.encode, 1300 | decode = Decoder.decode, 1301 | 1302 | encode_to_hex = encode_to_hex, 1303 | decode_from_hex = decode_from_hex, 1304 | 1305 | new_buffer = function() 1306 | return { 1307 | [0] = 0 1308 | } 1309 | end, 1310 | end_buffer = function(buf) 1311 | return table_concat(buf, nil, 1, buf[0]) 1312 | end, 1313 | reset_buffer = function(buf) 1314 | buf[0] = 0 1315 | end, 1316 | 1317 | set_type_function = function(t_fn) -- this is for me as I have custom type function in sam/scb to allow type function to get jit compiled :c 1318 | type = t_fn 1319 | end, 1320 | 1321 | add_custom_type = function(ty, encoder, decoder) 1322 | if CUSTOM_START == CUSTOM_MAX then 1323 | return error("cannot add more custom types") 1324 | end 1325 | 1326 | if encoders[ty] or decoders[ty] then 1327 | -- this just prints incase you mistakenly add a type that already exists 1328 | ErrorNoHaltWithStack("type already exists: `" .. ty .. "`") 1329 | end 1330 | 1331 | encoders[ty] = encoder 1332 | decoders[CUSTOM_START] = decoder 1333 | 1334 | CUSTOM_START = CUSTOM_START + 1 1335 | return CUSTOM_START - 1 1336 | end, 1337 | 1338 | set_custom_type_with_id = function(id, ty, encoder, decoder) 1339 | if encoders[ty] or decoders[ty] then 1340 | -- this just prints incase you mistakenly add a type that already exists 1341 | ErrorNoHaltWithStack("type already exists: `" .. ty .. "`") 1342 | end 1343 | 1344 | encoders[ty] = encoder 1345 | decoders[id] = decoder 1346 | end, 1347 | 1348 | chars = chars, 1349 | VERSION = "5.0.0" 1350 | } 1351 | --------------------------------------------------------------------------------