├── .eslintrc.json ├── .github ├── dependabot.yml └── workflows │ └── npm-publish.yml ├── .gitignore ├── .npmignore ├── .remembrance.json ├── CDN.md ├── LICENSE ├── README.md ├── cjs ├── base-ex.cjs └── base-ex.cjs.map ├── dist ├── base-ex.esm.js ├── base-ex.esm.min.js ├── base-ex.iife.js ├── base-ex.iife.min.js └── converters │ ├── Base1 │ ├── base-1.esm.js │ ├── base-1.esm.min.js │ ├── base-1.iife.js │ └── base-1.iife.min.js │ ├── Base16 │ ├── base-16.esm.js │ ├── base-16.esm.min.js │ ├── base-16.iife.js │ └── base-16.iife.min.js │ ├── Base2048 │ ├── base-2048.esm.js │ ├── base-2048.esm.min.js │ ├── base-2048.iife.js │ └── base-2048.iife.min.js │ ├── Base32 │ ├── base-32.esm.js │ ├── base-32.esm.min.js │ ├── base-32.iife.js │ └── base-32.iife.min.js │ ├── Base58 │ ├── base-58.esm.js │ ├── base-58.esm.min.js │ ├── base-58.iife.js │ └── base-58.iife.min.js │ ├── Base64 │ ├── base-64.esm.js │ ├── base-64.esm.min.js │ ├── base-64.iife.js │ └── base-64.iife.min.js │ ├── Base85 │ ├── base-85.esm.js │ ├── base-85.esm.min.js │ ├── base-85.iife.js │ └── base-85.iife.min.js │ ├── Base91 │ ├── base-91.esm.js │ ├── base-91.esm.min.js │ ├── base-91.iife.js │ └── base-91.iife.min.js │ ├── BasePhi │ ├── base-phi.esm.js │ ├── base-phi.esm.min.js │ ├── base-phi.iife.js │ └── base-phi.iife.min.js │ ├── ByteConverter │ ├── byte-converter.esm.js │ ├── byte-converter.esm.min.js │ ├── byte-converter.iife.js │ └── byte-converter.iife.min.js │ ├── Ecoji │ ├── ecoji.esm.js │ ├── ecoji.esm.min.js │ ├── ecoji.iife.js │ └── ecoji.iife.min.js │ ├── LEB128 │ ├── leb-128.esm.js │ ├── leb-128.esm.min.js │ ├── leb-128.iife.js │ └── leb-128.iife.min.js │ ├── SimpleBase │ ├── simple-base.esm.js │ ├── simple-base.esm.min.js │ ├── simple-base.iife.js │ └── simple-base.iife.min.js │ └── UUencode │ ├── uuencode.esm.js │ ├── uuencode.esm.min.js │ ├── uuencode.iife.js │ └── uuencode.iife.min.js ├── examples ├── assets │ ├── prism.css │ └── prism.js ├── demo.html └── live-examples.html ├── lib └── big.js │ ├── big.min.js │ └── big.mjs ├── package-lock.json ├── package.json ├── rollup.config.mjs ├── src ├── base-ex.js ├── converters │ ├── base-1.js │ ├── base-16.js │ ├── base-2048.js │ ├── base-32.js │ ├── base-58.js │ ├── base-64.js │ ├── base-85.js │ ├── base-91.js │ ├── base-phi.js │ ├── byte-converter.js │ ├── ecoji.js │ ├── leb-128.js │ ├── simple-base.js │ └── uuencode.js ├── core.js ├── io-handlers.js └── utils.js ├── test ├── base-1.test.js ├── ecoji-orig.test.js ├── fixtures │ ├── ecoji │ │ ├── ascii.garbage │ │ ├── concat_v1_1.enc │ │ ├── concat_v1_1.plaind │ │ ├── concat_v1_2.enc │ │ ├── concat_v1_2.plaind │ │ ├── concat_v2_1.enc │ │ ├── concat_v2_1.plaind │ │ ├── concat_v2_2.enc │ │ ├── concat_v2_2.plaind │ │ ├── eight_byte.ev1 │ │ ├── eight_byte.ev2 │ │ ├── eight_byte.plain │ │ ├── exhaustive.ev1 │ │ ├── exhaustive.ev2 │ │ ├── exhaustive.plain │ │ ├── five_byte.ev1 │ │ ├── five_byte.ev2 │ │ ├── five_byte.plain │ │ ├── four_byte_1.ev1 │ │ ├── four_byte_1.ev2 │ │ ├── four_byte_1.plain │ │ ├── four_byte_2.ev1 │ │ ├── four_byte_2.ev2 │ │ ├── four_byte_2.plain │ │ ├── four_byte_3.ev1 │ │ ├── four_byte_3.ev2 │ │ ├── four_byte_3.plain │ │ ├── four_byte_4.ev1 │ │ ├── four_byte_4.ev2 │ │ ├── four_byte_4.plain │ │ ├── incorrect_v1_padding.garbage │ │ ├── misplaced_padding_1.garbage │ │ ├── misplaced_padding_2.garbage │ │ ├── misplaced_padding_3.garbage │ │ ├── misplaced_padding_4.garbage │ │ ├── misplaced_padding_5.garbage │ │ ├── misplaced_padding_6.garbage │ │ ├── misplaced_padding_7.garbage │ │ ├── missing_padding_1.garbage │ │ ├── missing_padding_2.garbage │ │ ├── mixed_1.garbage │ │ ├── mixed_2.garbage │ │ ├── mixed_3.garbage │ │ ├── mixed_4.garbage │ │ ├── mixed_5.garbage │ │ ├── mixed_6.garbage │ │ ├── mixed_7.garbage │ │ ├── nine_byte_0.ev1 │ │ ├── nine_byte_0.ev2 │ │ ├── nine_byte_0.plain │ │ ├── nine_byte_1.ev1 │ │ ├── nine_byte_1.ev2 │ │ ├── nine_byte_1.plain │ │ ├── nine_byte_2.ev1 │ │ ├── nine_byte_2.ev2 │ │ ├── nine_byte_2.plain │ │ ├── nine_byte_3.ev1 │ │ ├── nine_byte_3.ev2 │ │ ├── nine_byte_3.plain │ │ ├── non_ecoji_emoji.garbage │ │ ├── one_byte.ev1 │ │ ├── one_byte.ev2 │ │ ├── one_byte.plain │ │ ├── phrase.ev1 │ │ ├── phrase.ev2 │ │ ├── phrase.plain │ │ ├── seven_byte.ev1 │ │ ├── seven_byte.ev2 │ │ ├── seven_byte.plain │ │ ├── six_byte.ev1 │ │ ├── six_byte.ev2 │ │ ├── six_byte.plain │ │ ├── three_byte.ev1 │ │ ├── three_byte.ev2 │ │ ├── three_byte.plain │ │ ├── two_byte.ev1 │ │ ├── two_byte.ev2 │ │ ├── two_byte.plain │ │ ├── windows_newline_v2_1.enc │ │ ├── windows_newline_v2_1.plaind │ │ ├── windows_newline_v2_2.enc │ │ ├── windows_newline_v2_2.plaind │ │ ├── zero_byte.ev1 │ │ ├── zero_byte.ev2 │ │ └── zero_byte.plain │ ├── encoding-map.json │ ├── helpers.js │ └── load-json.js ├── map.test.js ├── number-mode.test.js ├── random-io.test.js └── simple-base.test.js └── third-party-licenses ├── BASE2048-LICENSE ├── BASE91-LICENSE ├── BIG.JS-LICENCE.md └── ECOJI-LICENSE /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es2022": true, 5 | "node": true 6 | }, 7 | "extends": "eslint:recommended", 8 | "parserOptions": { 9 | "ecmaVersion": "latest", 10 | "sourceType": "module" 11 | }, 12 | "rules": { 13 | "accessor-pairs": "error", 14 | "array-bracket-newline": "error", 15 | "array-bracket-spacing": "off", 16 | "array-callback-return": "error", 17 | "array-element-newline": "off", 18 | "arrow-body-style": "error", 19 | "arrow-parens": "off", 20 | "arrow-spacing": "off", 21 | "block-scoped-var": "error", 22 | "block-spacing": [ 23 | "error", 24 | "never" 25 | ], 26 | "brace-style": "off", 27 | "capitalized-comments": "off", 28 | "class-methods-use-this": "off", 29 | "comma-dangle": "off", 30 | "comma-spacing": "off", 31 | "comma-style": [ 32 | "error", 33 | "last" 34 | ], 35 | "complexity": ["warn", 28], 36 | "computed-property-spacing": [ 37 | "error", 38 | "never" 39 | ], 40 | "consistent-return": "error", 41 | "consistent-this": "error", 42 | "curly": "off", 43 | "default-case": "error", 44 | "default-case-last": "error", 45 | "default-param-last": "error", 46 | "dot-location": ["error", "property"], 47 | "dot-notation": "error", 48 | "eol-last": "error", 49 | "eqeqeq": "off", 50 | "func-call-spacing": "error", 51 | "func-name-matching": "error", 52 | "func-names": "off", 53 | "func-style": [ 54 | "error", 55 | "declaration", 56 | { 57 | "allowArrowFunctions": true 58 | } 59 | ], 60 | "function-paren-newline": "off", 61 | "generator-star-spacing": "error", 62 | "grouped-accessor-pairs": "error", 63 | "guard-for-in": "off", 64 | "id-denylist": "error", 65 | "id-length": "off", 66 | "id-match": "error", 67 | "implicit-arrow-linebreak": [ 68 | "error", 69 | "beside" 70 | ], 71 | "indent": "off", 72 | "init-declarations": "off", 73 | "jsx-quotes": "error", 74 | "key-spacing": "off", 75 | "keyword-spacing": "off", 76 | "line-comment-position": "off", 77 | "linebreak-style": [ 78 | "error", 79 | "unix" 80 | ], 81 | "lines-around-comment": "off", 82 | "lines-between-class-members": [ 83 | "error", 84 | "always", 85 | { 86 | "exceptAfterSingleLine": true 87 | } 88 | ], 89 | "max-classes-per-file": "off", 90 | "max-depth": "off", 91 | "max-len": "off", 92 | "max-lines": "off", 93 | "max-lines-per-function": "off", 94 | "max-nested-callbacks": "error", 95 | "max-params": "off", 96 | "max-statements": "off", 97 | "max-statements-per-line": "off", 98 | "multiline-comment-style": "off", 99 | "new-parens": "off", 100 | "newline-per-chained-call": "error", 101 | "no-alert": "error", 102 | "no-array-constructor": "off", 103 | "no-await-in-loop": "error", 104 | "no-bitwise": "off", 105 | "no-caller": "error", 106 | "no-cond-assign": [ 107 | "error", 108 | "except-parens" 109 | ], 110 | "no-confusing-arrow": "off", 111 | "no-console": "off", 112 | "no-constructor-return": "error", 113 | "no-continue": "error", 114 | "no-div-regex": "error", 115 | "no-duplicate-imports": "error", 116 | "no-else-return": "off", 117 | "no-empty-function": "error", 118 | "no-eq-null": "error", 119 | "no-eval": "error", 120 | "no-extend-native": "error", 121 | "no-extra-bind": "error", 122 | "no-extra-label": "error", 123 | "no-extra-parens": "off", 124 | "no-floating-decimal": "error", 125 | "no-implicit-coercion": "error", 126 | "no-implicit-globals": "error", 127 | "no-implied-eval": "error", 128 | "no-inline-comments": "off", 129 | "no-invalid-this": "error", 130 | "no-iterator": "error", 131 | "no-label-var": "error", 132 | "no-labels": "error", 133 | "no-lone-blocks": "error", 134 | "no-lonely-if": "error", 135 | "no-loop-func": "error", 136 | "no-loss-of-precision": "error", 137 | "no-magic-numbers": "off", 138 | "no-mixed-operators": "off", 139 | "no-multi-assign": "error", 140 | "no-multi-spaces": "off", 141 | "no-multi-str": "error", 142 | "no-multiple-empty-lines": "error", 143 | "no-negated-condition": "off", 144 | "no-nested-ternary": "off", 145 | "no-new": "error", 146 | "no-new-func": "error", 147 | "no-new-object": "off", 148 | "no-new-wrappers": "error", 149 | "no-nonoctal-decimal-escape": "error", 150 | "no-octal-escape": "error", 151 | "no-param-reassign": "off", 152 | "no-plusplus": "off", 153 | "no-promise-executor-return": "error", 154 | "no-proto": "error", 155 | "no-restricted-exports": "error", 156 | "no-restricted-globals": "error", 157 | "no-restricted-imports": "error", 158 | "no-restricted-properties": "error", 159 | "no-restricted-syntax": "error", 160 | "no-return-assign": "off", 161 | "no-return-await": "error", 162 | "no-script-url": "error", 163 | "no-self-compare": "error", 164 | "no-sequences": "off", 165 | "no-shadow": "off", 166 | "no-tabs": "error", 167 | "no-template-curly-in-string": "error", 168 | "no-ternary": "off", 169 | "no-throw-literal": "error", 170 | "no-trailing-spaces": "off", 171 | "no-undef-init": "error", 172 | "no-undefined": "error", 173 | "no-underscore-dangle": "error", 174 | "no-unmodified-loop-condition": "error", 175 | "no-unneeded-ternary": "error", 176 | "no-unreachable-loop": "error", 177 | "no-unsafe-optional-chaining": "error", 178 | "no-unused-expressions": "off", 179 | "no-use-before-define": "off", 180 | "no-useless-backreference": "error", 181 | "no-useless-call": "error", 182 | "no-useless-computed-key": "error", 183 | "no-useless-concat": "error", 184 | "no-useless-constructor": "error", 185 | "no-useless-rename": "error", 186 | "no-useless-return": "error", 187 | "no-var": "off", 188 | "no-void": "error", 189 | "no-warning-comments": "error", 190 | "no-whitespace-before-property": "error", 191 | "nonblock-statement-body-position": "error", 192 | "object-curly-newline": "error", 193 | "object-curly-spacing": "off", 194 | "object-shorthand": "error", 195 | "one-var": "off", 196 | "one-var-declaration-per-line": "off", 197 | "operator-assignment": [ 198 | "error", 199 | "always" 200 | ], 201 | "operator-linebreak": "error", 202 | "padded-blocks": "off", 203 | "padding-line-between-statements": "error", 204 | "prefer-arrow-callback": "error", 205 | "prefer-const": "off", 206 | "prefer-destructuring": "off", 207 | "prefer-exponentiation-operator": "error", 208 | "prefer-named-capture-group": "error", 209 | "prefer-numeric-literals": "error", 210 | "prefer-object-spread": "error", 211 | "prefer-promise-reject-errors": "error", 212 | "prefer-regex-literals": "error", 213 | "prefer-rest-params": "error", 214 | "prefer-spread": "error", 215 | "prefer-template": "error", 216 | "quote-props": "off", 217 | "quotes": "off", 218 | "radix": [ 219 | "error", 220 | "always" 221 | ], 222 | "require-atomic-updates": "error", 223 | "require-await": "off", 224 | "require-unicode-regexp": "off", 225 | "rest-spread-spacing": [ 226 | "error", 227 | "never" 228 | ], 229 | "semi": "off", 230 | "semi-spacing": "off", 231 | "semi-style": [ 232 | "error", 233 | "last" 234 | ], 235 | "sort-imports": "error", 236 | "sort-keys": "off", 237 | "sort-vars": "off", 238 | "space-before-blocks": "off", 239 | "space-before-function-paren": "off", 240 | "space-in-parens": [ 241 | "error", 242 | "never" 243 | ], 244 | "space-infix-ops": "off", 245 | "space-unary-ops": "error", 246 | "spaced-comment": "off", 247 | "strict": "off", 248 | "switch-colon-spacing": "error", 249 | "symbol-description": "error", 250 | "template-curly-spacing": [ 251 | "error", 252 | "never" 253 | ], 254 | "template-tag-spacing": "error", 255 | "unicode-bom": [ 256 | "error", 257 | "never" 258 | ], 259 | "vars-on-top": "error", 260 | "wrap-iife": "off", 261 | "wrap-regex": "error", 262 | "yield-star-spacing": "error", 263 | "yoda": "off" 264 | } 265 | } 266 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "npm" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "weekly" 12 | -------------------------------------------------------------------------------- /.github/workflows/npm-publish.yml: -------------------------------------------------------------------------------- 1 | # This workflow will run tests using node and then publish a package to GitHub Packages when a release is created 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/publishing-nodejs-packages 3 | 4 | name: Node.js Package 5 | 6 | on: 7 | release: 8 | types: [created] 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v3 15 | - uses: actions/setup-node@v3 16 | with: 17 | node-version: 16 18 | - run: npm ci 19 | - run: npm test 20 | 21 | publish-npm: 22 | needs: build 23 | runs-on: ubuntu-latest 24 | steps: 25 | - uses: actions/checkout@v3 26 | - uses: actions/setup-node@v3 27 | with: 28 | node-version: 16 29 | registry-url: https://registry.npmjs.org/ 30 | - run: npm ci 31 | - run: npm publish 32 | env: 33 | NODE_AUTH_TOKEN: ${{secrets.npm_key}} 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | BaseEx.code-workspace 2 | node_modules 3 | .vscode/* 4 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | BaseEx.code-workspace 2 | .vscode/* 3 | .github -------------------------------------------------------------------------------- /.remembrance.json: -------------------------------------------------------------------------------- 1 | { 2 | "src": "./src/**", 3 | "dist": [ 4 | "./cjs/**", 5 | "./dist/**" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /CDN.md: -------------------------------------------------------------------------------- 1 | # CDN links (jsdelivr) 2 | 3 | ### Full Build 4 | 5 | ##### BaseEx 6 | ###### esm 7 | ```js 8 | import BaseEx from "https://cdn.jsdelivr.net/npm/base-ex@latest/dist/base-ex.esm.min.js"; 9 | ``` 10 | ###### iife 11 | ```html 12 | 13 | ``` 14 | 15 | 16 | ### Standalone Builds 17 | 18 | ##### Base1 19 | ###### esm 20 | ```js 21 | import Base1 from "https://cdn.jsdelivr.net/npm/base-ex@latest/dist/converters/Base1/base-1.esm.min.js"; 22 | ``` 23 | ###### iife 24 | ```html 25 | 26 | ``` 27 | 28 | 29 | ##### Base16 30 | ###### esm 31 | ```js 32 | import Base16 from "https://cdn.jsdelivr.net/npm/base-ex@latest/dist/converters/Base16/base-16.esm.min.js"; 33 | ``` 34 | ###### iife 35 | ```html 36 | 37 | ``` 38 | 39 | 40 | ##### Base32 41 | ###### esm 42 | ```js 43 | import Base32 from "https://cdn.jsdelivr.net/npm/base-ex@latest/dist/converters/Base32/base-32.esm.min.js"; 44 | ``` 45 | ###### iife 46 | ```html 47 | 48 | ``` 49 | 50 | 51 | ##### Base58 52 | ###### esm 53 | ```js 54 | import Base58 from "https://cdn.jsdelivr.net/npm/base-ex@latest/dist/converters/Base58/base-58.esm.min.js"; 55 | ``` 56 | ###### iife 57 | ```html 58 | 59 | ``` 60 | 61 | 62 | ##### Base64 63 | ###### esm 64 | ```js 65 | import Base64 from "https://cdn.jsdelivr.net/npm/base-ex@latest/dist/converters/Base64/base-64.esm.min.js"; 66 | ``` 67 | ###### iife 68 | ```html 69 | 70 | ``` 71 | 72 | 73 | ##### UUencode 74 | ###### esm 75 | ```js 76 | import UUencode from "https://cdn.jsdelivr.net/npm/base-ex@latest/dist/converters/UUencode/uuencode.esm.min.js"; 77 | ``` 78 | ###### iife 79 | ```html 80 | 81 | ``` 82 | 83 | 84 | ##### Base85 85 | ###### esm 86 | ```js 87 | import Base85 from "https://cdn.jsdelivr.net/npm/base-ex@latest/dist/converters/Base85/base-85.esm.min.js"; 88 | ``` 89 | ###### iife 90 | ```html 91 | 92 | ``` 93 | 94 | 95 | ##### Base91 96 | ###### esm 97 | ```js 98 | import Base91 from "https://cdn.jsdelivr.net/npm/base-ex@latest/dist/converters/Base91/base-91.esm.min.js"; 99 | ``` 100 | ###### iife 101 | ```html 102 | 103 | ``` 104 | 105 | 106 | ##### LEB128 107 | ###### esm 108 | ```js 109 | import LEB128 from "https://cdn.jsdelivr.net/npm/base-ex@latest/dist/converters/LEB128/leb-128.esm.min.js"; 110 | ``` 111 | ###### iife 112 | ```html 113 | 114 | ``` 115 | 116 | 117 | ##### Ecoji 118 | ###### esm 119 | ```js 120 | import Ecoji from "https://cdn.jsdelivr.net/npm/base-ex@latest/dist/converters/Ecoji/ecoji.esm.min.js"; 121 | ``` 122 | ###### iife 123 | ```html 124 | 125 | ``` 126 | 127 | 128 | ##### Base2048 129 | ###### esm 130 | ```js 131 | import Base2048 from "https://cdn.jsdelivr.net/npm/base-ex@latest/dist/converters/Base2048/base-2048.esm.min.js"; 132 | ``` 133 | ###### iife 134 | ```html 135 | 136 | ``` 137 | 138 | 139 | ##### SimpleBase 140 | ###### esm 141 | ```js 142 | import SimpleBase from "https://cdn.jsdelivr.net/npm/base-ex@latest/dist/converters/SimpleBase/simple-base.esm.min.js"; 143 | ``` 144 | ###### iife 145 | ```html 146 | 147 | ``` 148 | 149 | 150 | ##### BasePhi 151 | ###### esm 152 | ```js 153 | import BasePhi from "https://cdn.jsdelivr.net/npm/base-ex@latest/dist/converters/BasePhi/base-phi.esm.min.js"; 154 | ``` 155 | ###### iife 156 | ```html 157 | 158 | ``` 159 | 160 | 161 | ##### ByteConverter 162 | ###### esm 163 | ```js 164 | import ByteConverter from "https://cdn.jsdelivr.net/npm/base-ex@latest/dist/converters/ByteConverter/byte-converter.esm.min.js"; 165 | ``` 166 | ###### iife 167 | ```html 168 | 169 | ``` 170 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 UmamiAppearance 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. -------------------------------------------------------------------------------- /dist/converters/Base16/base-16.esm.min.js: -------------------------------------------------------------------------------- 1 | class t{static toBytes(t){return!ArrayBuffer.isView(t)||"undefined"!=typeof Buffer&&t instanceof Buffer||(t=t.buffer),[new Uint8Array(t),!1,"bytes"]}}class e{static get typeList(){return["buffer","bytes","uint8","view"]}static getType(t){if(!e.typeList.includes(t))throw new TypeError(`Unknown output type: '${t}'`);return t}static compile(t,n){let i;return i="buffer"===(n=e.getType(n))?t.buffer:"view"===n?new DataView(t.buffer):t,i}}class n{static makeDataView(t){const e=new ArrayBuffer(t);return new DataView(e)}static floatingPoints(t,e=!1){const n=this.makeDataView(8);return n.setFloat64(0,t,e),n}static numbers(t,e=!1){let n,i;if(Number.isInteger(t)){if(i="int",!Number.isSafeInteger(t)){let e,n,i;throw t<0?(e=Number.MIN_SAFE_INTEGER,n="smaller",i="MIN"):(e=Number.MAX_SAFE_INTEGER,n="bigger",i="MAX"),new RangeError(`The provided integer is ${n} than ${i}_SAFE_INTEGER: '${e}'\nData integrity is not guaranteed. Use a BigInt to avoid this issue.\n(If you see this error although a float was provided, the input has to many digits before the decimal point to store the decimal places in a float with 64 bits.)`)}t<0?t<-2147483648?(n=this.makeDataView(8),n.setBigInt64(0,BigInt(t),e)):t<-32768?(n=this.makeDataView(4),n.setInt32(0,t,e)):(n=this.makeDataView(2),n.setInt16(0,t,e)):t>0?t>4294967295?(n=this.makeDataView(8),n.setBigUint64(0,BigInt(t),e)):t>65535?(n=this.makeDataView(4),n.setUint32(0,t,e)):(n=this.makeDataView(2),n.setInt16(0,t,e)):n=new Uint16Array([0])}else i="float",n=this.floatingPoints(t,e);return[new Uint8Array(n.buffer),i]}static bigInts(t,e=!1){const n=new Array,i=e?"push":"unshift",r=18446744073709551616n;if(t<0)for(;t<-9223372036854775808n;)n[i](t%r),t>>=64n;else for(;t>=r;)n[i](t%r),t>>=64n;n[i](t);const s=8*n.length,o=this.makeDataView(s);return n.forEach(((t,n)=>{const i=8*n;o.setBigUint64(i,t,e)})),new Uint8Array(o.buffer)}static toBytes(t,e){let n,i=!1,r="bytes";if(t instanceof ArrayBuffer)n=new Uint8Array(t.slice());else if(ArrayBuffer.isView(t))n="undefined"!=typeof Buffer&&t instanceof Buffer?new Uint8Array(t):new Uint8Array(t.buffer.slice());else if("string"==typeof t||t instanceof String)n=(new TextEncoder).encode(t);else if("number"==typeof t){if(isNaN(t))throw new TypeError("Cannot proceed. Input is NaN.");if(t==1/0)throw new TypeError("Cannot proceed. Input is Infinity.");if(e.signed&&t<0&&(i=!0,t=-t),e.numberMode){const i=this.floatingPoints(t,e.littleEndian);n=new Uint8Array(i.buffer),r="float"}else[n,r]=this.numbers(t,e.littleEndian)}else if("bigint"==typeof t)e.signed&&t<0&&(i=!0,t*=-1n),n=this.bigInts(t,e.littleEndian),r="int";else{if(!Array.isArray(t))throw new TypeError("The provided input type can not be processed.");{const i=new Array;for(const n of t)i.push(...this.toBytes(n,e)[0]);n=Uint8Array.from(i)}}return[n,i,r]}}const i=n,r=class{static get typeList(){return["bigint64","bigint_n","biguint64","buffer","bytes","float32","float64","float_n","int8","int16","int32","int_n","str","uint8","uint16","uint32","uint_n","view"]}static getType(t){if(!this.typeList.includes(t))throw new TypeError(`Unknown output type: '${t}'`);return t}static makeTypedArrayBuffer(t,e,n,i){const r=t.byteLength,s=(e-t.byteLength%e)%e,o=i&&r>1?255:0;let a=t;if(s){a=new Uint8Array(r+s),a.fill(o);const e=n?0:s;a.set(t,e)}return a.buffer}static makeTypedArray(t,e,n,i){let r;if("int16"===e||"uint16"===e){const s=this.makeTypedArrayBuffer(t,2,n,i);r="int16"===e?new Int16Array(s):new Uint16Array(s)}else if("int32"===e||"uint32"===e||"float32"===e){const s=this.makeTypedArrayBuffer(t,4,n,i);r="int32"===e?new Int32Array(s):"uint32"===e?new Uint32Array(s):new Float32Array(s)}else if("bigint64"===e||"biguint64"===e||"float64"===e){const s=this.makeTypedArrayBuffer(t,8,n,i);r="bigint64"===e?new BigInt64Array(s):"biguint64"===e?new BigUint64Array(s):new Float64Array(s)}return r}static compile(t,e,i=!1,r=!1){let s;if(e=this.getType(e),r){let r;if(r=e.match(/^float/)?-this.compile(t,"float_n",i):-this.compile(t,"uint_n",i),"float_n"===e)return r;t=n.toBytes(r,{littleEndian:i,numberMode:!1,signed:!1})[0]}if("buffer"===e)s=t.buffer;else if("bytes"===e||"uint8"===e)s=t;else if("int8"===e)s=new Int8Array(t.buffer);else if("view"===e)s=new DataView(t.buffer);else if("str"===e)s=(new TextDecoder).decode(t);else if("uint_n"===e||"int_n"===e||"bigint_n"===e){if(1===t.length){const e=this.makeTypedArrayBuffer(t,2,i,r);t=new Uint8Array(e)}i&&t.reverse();let n=0n;t.forEach((t=>n=(n<<8n)+BigInt(t))),"uint_n"!==e&&(n=BigInt.asIntN(8*t.length,n)),s="bigint_n"!==e&&n>=Number.MIN_SAFE_INTEGER&&n<=Number.MAX_SAFE_INTEGER?Number(n):n}else if("float_n"===e)if(t.length<=4){let e;e=4===t.length?t:this.makeTypedArray(t,"float32",!1,r);s=new DataView(e.buffer).getFloat32(0,i)}else{if(!(t.length<=8))throw new RangeError("The provided input is to complex to be converted into a floating point.");{let e;e=8===t.length?t:this.makeTypedArray(t,"float64",!1,r);s=new DataView(e.buffer).getFloat64(0,i)}}else if("number"===e){if(8!==t.length)throw new TypeError("Type mismatch. Cannot convert into number.");const e=new Float64Array(t.buffer);s=Number(e)}else s=this.makeTypedArray(t,e,i,r);return s}};class s extends TypeError{constructor(){super("The input is signed but the converter is not set to treat input as signed.\nYou can pass the string 'signed' to the decode function or when constructing the converter."),this.name="SignError"}}class o extends TypeError{constructor(t,e=null){null===e&&(e=`Character '${t}' is not part of the charset.`),super(e),this.name="DecodingError"}}class a{constructor(t){this.root=t,this.converterArgs={},this.#t()}setIOHandlers(t=i,e=r){this.inputHandler=t,this.outputHandler=e}#t(){this.root.addCharset=(t,e,n=[],i=!0)=>{const r=(t,n,i)=>{if(0===i&&n.length)return console.warn(`This converter has no ${t}. The following argument was ignored:\n'${n}'`),[];let r=i;if("string"==typeof n&&(n=[...n]),Array.isArray(n))r=n.length,n=new Set(n);else if(!(n instanceof Set))throw new TypeError(`The ${t} must be one of the types:\n'str', 'set', 'array'."`);if(n.size===i)return[...n];if(r!==i)throw new Error(`Your ${t} has a length of ${r}. The converter requires a length of ${i}.`);{const n={};(e=[...e]).forEach((t=>{t in n?n[t]++:n[t]=1}));let r="";i<100&&(r=`${e.join("")}\n`,e.forEach((t=>{n[t]>1?r+="^":r+=" "})));const s=Object.keys(n).filter((t=>n[t]>1));throw new Error(`You have repetitive char(s) [ ${s.join(" | ")} ] in your ${t}. Make sure each character is unique.\n${r}`)}};if(this.root.frozenCharsets)throw new Error("The charsets of this converter cannot be changed.");if("string"!=typeof t)throw new TypeError("The charset name must be a string.");i&&t in this.root.charsets&&console.warn(`An existing charset with name ${t} will get replaced.`);const s=r("charset",e,this.root.converter.radix),o=r("padding set",n,this.root.padCharAmount);this.root.charsets[t]=s,o.length&&(this.root.padChars[t]=o),i&&console.info(`New charset '${t}' was added and is ready to use`)},this.root.setDefaultCharset=t=>{if(!(t in this.root.charsets)){const e=Object.keys(this.root.charsets).join("\n * ");throw new TypeError(`Charset ${t} was not found. Available charsets are:\n * ${e}`)}this.root.version=t}}#e(t){return t.map((t=>`'${t}'`)).join(", ")}toSignedStr(t,e){return t=t.replace(/^0+(?!$)/,""),e&&(t="-".concat(t)),t}extractSign(t){let e=!1;return"-"===t[0]&&(e=!0,t=t.slice(1)),[t,e]}#n(t,e,n,i){throw new TypeError([`'${t}'\n\nParameters:`,i?"\n * valid declarations for IO handlers are 'bytesOnly', 'bytesIn', 'bytesOut'":"",this.root.isMutable.signed?"\n * pass 'signed' to disable, 'unsigned' to enable the use of the twos's complement for negative integers":"",this.root.isMutable.littleEndian?"\n * 'be' for big , 'le' for little endian byte order for case conversion":"",this.root.isMutable.padding?"\n * pass 'pad' to fill up, 'nopad' to not fill up the output with the particular padding":"",this.root.isMutable.upper?"\n * valid args for changing the encoded output case are 'upper' and 'lower'":"",`\n * valid args for the output type are ${this.#e(n)}`,e?`\n * the option(s) for version/charset are: ${this.#e(e)}`:"","\n * valid args for integrity check are: 'integrity' and 'nointegrity'",this.root.hasDecimalMode?"\n * 'decimal' for decimal-mode (directly converts Numbers including decimal values, without byte-conversion)":"","\n * 'number' for number-mode (converts every number into a Float64Array to keep the natural js number type)",Object.keys(this.converterArgs).length?`\n * converter specific args:\n - ${(()=>Object.keys(this.converterArgs).map((t=>this.converterArgs[t].map((t=>`'${t}'`)).join(" and "))).join("\n - "))()}`:"","\n\nTraceback:"].join(""))}validateArgs(n,s=!1){const o={decimalMode:this.root.decimalMode,integrity:this.root.integrity,littleEndian:this.root.littleEndian,numberMode:this.root.numberMode,options:this.root.options,outputType:this.root.outputType,padding:this.root.padding,signed:this.root.signed,upper:this.root.upper,version:this.root.version};for(const t in this.converterArgs)o[t]=this.root[t];if(!n.length)return s&&this.setIOHandlers(),o;const a=t=>!!n.includes(t)&&(n.splice(n.indexOf(t),1),!0),l=Object.keys(this.root.charsets),h={integrity:["nointegrity","integrity"],littleEndian:["be","le"],padding:["nopad","pad"],signed:["unsigned","signed"],upper:["lower","upper"],...this.converterArgs};if(s)if(a("bytes_only"))this.setIOHandlers(t,e);else{const n=a("bytes_in")?t:i,s=a("bytes_out")?e:r;this.setIOHandlers(n,s)}const u=this.outputHandler.typeList;if(a("number")&&(o.numberMode=!0,o.outputType="float_n"),a("decimal")){if(!this.root.hasDecimalMode)throw TypeError("Argument 'decimal' is only allowed for converters with a non-integer base.");o.decimalMode=!0,o.outputType="decimal",o.numberMode&&(o.numberMode=!1,console.warn("-> number-mode was disabled due to the decimal-mode"))}if(n.forEach((t=>{if("object"!=typeof t)if(t=String(t).toLowerCase(),l.includes(t))o.version=t;else if(u.includes(t))o.outputType=t;else{let e=!0;for(const n in h)if(h[n].includes(t)){if(e=!1,!this.root.isMutable[n])throw TypeError(`Argument '${t}' is not allowed for this type of converter.`);o[n]=Boolean(h[n].indexOf(t))}e&&this.#n(t,l,u,s)}else o.options={...o.options,...t}})),o.padding&&o.signed&&(o.padding=!1,console.warn("-> padding was set to false due to the signed conversion")),s)for(const t in o)this.root[t]=o[t];return o}signError(){throw new s}wrapOutput(t,e=0){if(!e)return t;const n=new RegExp(`.{1,${e}}`,"gu");return t.match(n).join("\n")}normalizeInput(t,e=!1){return e?String(t):String(t).replace(/\s/g,"")}}class l{constructor(t,e=null,n=null,i=0){this.radix=t,null!==e&&null!==n?(this.bsEnc=e,this.bsDec=n):[this.bsEnc,this.bsDec]=this.constructor.guessBS(t),this.decPadVal=i,this.powers={}}static guessBS(t){let e=t<8?t:Math.ceil(256/t);for(;e>8&&!(e%8);)e/=8;let n=0;for(;8*n*Math.log(2)/Math.log(t)=this.radix;)[u,h]=this.divmod(u,this.radix),a.unshift(parseInt(h,10));for(a.unshift(parseInt(u,10));a.lengthc=c.concat(e[t]))),i&&(c=i(c,o)),s=s.concat(c)}return[s,o]}decode(t,e,n=[],i=!0,r=!1){if(!t)return new Uint8Array(0);let s=this.bsDec;const a=[];let l;if([...t].forEach((t=>{const r=e.indexOf(t);if(r>-1)a.push(r);else if(i&&-1===n.indexOf(t))throw new o(t)})),0===s)s=a.length;else{l=(s-a.length%s)%s;const t=new Array(l).fill(this.decPadVal);r?a.unshift(...t):a.push(...t)}let h=new Array;for(let t=0,e=a.length;t(this.powers[i]=BigInt(this.pow(i)),this.powers[i]))();e+=BigInt(a[t+n])*r}const n=[];let i,r=e;for(;r>=256;)[r,i]=this.divmod(r,256),n.unshift(parseInt(i,10));for(n.unshift(parseInt(r,10));n.length1){for(;!h[0];)h.shift();h.length||h.push(0),h.reverse()}}else if(this.bsDec){const t=this.padChars(l);h.splice(h.length-t)}return Uint8Array.from(h)}padBytes(t){return Math.floor(t*this.bsDec/this.bsEnc)}padChars(t){return Math.ceil(t*this.bsEnc/this.bsDec)}pow(t){return BigInt(this.radix)**BigInt(t)}divmod(t,e){return[t,e]=[BigInt(t),BigInt(e)],[t/e,t%e]}}class h{constructor(t=!0){this.charsets={},this.decimalMode=!1,this.frozenCharsets=!1,this.hasDecimalMode=!1,this.hasSignedMode=!1,this.integrity=!0,this.littleEndian=!1,this.numberMode=!1,this.outputType="buffer",this.padding=!1,this.padCharAmount=0,this.padChars={},this.nonASCII=!1,this.signed=!1,this.upper=null,t&&(this.utils=new a(this)),this.version="default",this.options={lineWrap:0},this.isMutable={integrity:!0,littleEndian:!1,padding:!1,signed:!1,upper:!1}}encode(t,e,n,...i){const r=this.utils.validateArgs(i);let[s,o,a]=this.utils.inputHandler.toBytes(t,r),l=null;e&&(l=e(r));let[h,u]=this.converter.encode(s,this.charsets[r.version],r.littleEndian,l);return r.signed&&(h=this.utils.toSignedStr(h,o)),r.upper&&(h=h.toUpperCase()),n&&(h=n({inputBytes:s,output:h,settings:r,zeroPadding:u,type:a})),this.utils.wrapOutput(h,r.options.lineWrap)}decode(t,e,n,i,...r){const s=this.utils.validateArgs(r);t=this.utils.normalizeInput(t,i);let o=!1;this.hasSignedMode&&([t,o]=this.utils.extractSign(t),o&&!s.signed&&this.utils.signError()),this.isMutable.upper&&(t=t.toLowerCase()),e&&(t=e({input:t,settings:s}));let a=this.converter.decode(t,this.charsets[s.version],this.padChars[s.version],s.integrity,s.littleEndian);return n&&(a=n({input:t,output:a,settings:s})),this.utils.outputHandler.compile(a,s.outputType,s.littleEndian,o)}} 2 | /** 3 | * [BaseEx|Base16 Converter]{@link https://github.com/UmamiAppearance/BaseExJS/blob/main/src/converters/base-16.js} 4 | * 5 | * @version 0.8.1 6 | * @author UmamiAppearance [mail@umamiappearance.eu] 7 | * @license MIT 8 | */class u extends h{constructor(...t){super(),this.converter=new l(16,1,2),this.charsets.default=[..."0123456789abcdef"],this.padChars.default=[],this.hasSignedMode=!0,this.isMutable.signed=!0,this.isMutable.upper=!0,this.utils.validateArgs(t,!0)}encode(t,...e){return super.encode(t,null,null,...e)}decode(t,...e){return super.decode(t,(({input:t,settings:e})=>(t=t.replace(/^0x/,""),e.integrity||(t=t.toLowerCase().replace(/[^0-9a-f]/g,"")),t.length%2&&(t="0".concat(t)),t)),null,!1,...e)}}export{u as default}; 9 | -------------------------------------------------------------------------------- /dist/converters/Base91/base-91.esm.min.js: -------------------------------------------------------------------------------- 1 | class t{static toBytes(t){return!ArrayBuffer.isView(t)||"undefined"!=typeof Buffer&&t instanceof Buffer||(t=t.buffer),[new Uint8Array(t),!1,"bytes"]}}class e{static get typeList(){return["buffer","bytes","uint8","view"]}static getType(t){if(!e.typeList.includes(t))throw new TypeError(`Unknown output type: '${t}'`);return t}static compile(t,i){let n;return n="buffer"===(i=e.getType(i))?t.buffer:"view"===i?new DataView(t.buffer):t,n}}class i{static makeDataView(t){const e=new ArrayBuffer(t);return new DataView(e)}static floatingPoints(t,e=!1){const i=this.makeDataView(8);return i.setFloat64(0,t,e),i}static numbers(t,e=!1){let i,n;if(Number.isInteger(t)){if(n="int",!Number.isSafeInteger(t)){let e,i,n;throw t<0?(e=Number.MIN_SAFE_INTEGER,i="smaller",n="MIN"):(e=Number.MAX_SAFE_INTEGER,i="bigger",n="MAX"),new RangeError(`The provided integer is ${i} than ${n}_SAFE_INTEGER: '${e}'\nData integrity is not guaranteed. Use a BigInt to avoid this issue.\n(If you see this error although a float was provided, the input has to many digits before the decimal point to store the decimal places in a float with 64 bits.)`)}t<0?t<-2147483648?(i=this.makeDataView(8),i.setBigInt64(0,BigInt(t),e)):t<-32768?(i=this.makeDataView(4),i.setInt32(0,t,e)):(i=this.makeDataView(2),i.setInt16(0,t,e)):t>0?t>4294967295?(i=this.makeDataView(8),i.setBigUint64(0,BigInt(t),e)):t>65535?(i=this.makeDataView(4),i.setUint32(0,t,e)):(i=this.makeDataView(2),i.setInt16(0,t,e)):i=new Uint16Array([0])}else n="float",i=this.floatingPoints(t,e);return[new Uint8Array(i.buffer),n]}static bigInts(t,e=!1){const i=new Array,n=e?"push":"unshift",r=18446744073709551616n;if(t<0)for(;t<-9223372036854775808n;)i[n](t%r),t>>=64n;else for(;t>=r;)i[n](t%r),t>>=64n;i[n](t);const s=8*i.length,o=this.makeDataView(s);return i.forEach(((t,i)=>{const n=8*i;o.setBigUint64(n,t,e)})),new Uint8Array(o.buffer)}static toBytes(t,e){let i,n=!1,r="bytes";if(t instanceof ArrayBuffer)i=new Uint8Array(t.slice());else if(ArrayBuffer.isView(t))i="undefined"!=typeof Buffer&&t instanceof Buffer?new Uint8Array(t):new Uint8Array(t.buffer.slice());else if("string"==typeof t||t instanceof String)i=(new TextEncoder).encode(t);else if("number"==typeof t){if(isNaN(t))throw new TypeError("Cannot proceed. Input is NaN.");if(t==1/0)throw new TypeError("Cannot proceed. Input is Infinity.");if(e.signed&&t<0&&(n=!0,t=-t),e.numberMode){const n=this.floatingPoints(t,e.littleEndian);i=new Uint8Array(n.buffer),r="float"}else[i,r]=this.numbers(t,e.littleEndian)}else if("bigint"==typeof t)e.signed&&t<0&&(n=!0,t*=-1n),i=this.bigInts(t,e.littleEndian),r="int";else{if(!Array.isArray(t))throw new TypeError("The provided input type can not be processed.");{const n=new Array;for(const i of t)n.push(...this.toBytes(i,e)[0]);i=Uint8Array.from(n)}}return[i,n,r]}}const n=i,r=class{static get typeList(){return["bigint64","bigint_n","biguint64","buffer","bytes","float32","float64","float_n","int8","int16","int32","int_n","str","uint8","uint16","uint32","uint_n","view"]}static getType(t){if(!this.typeList.includes(t))throw new TypeError(`Unknown output type: '${t}'`);return t}static makeTypedArrayBuffer(t,e,i,n){const r=t.byteLength,s=(e-t.byteLength%e)%e,o=n&&r>1?255:0;let a=t;if(s){a=new Uint8Array(r+s),a.fill(o);const e=i?0:s;a.set(t,e)}return a.buffer}static makeTypedArray(t,e,i,n){let r;if("int16"===e||"uint16"===e){const s=this.makeTypedArrayBuffer(t,2,i,n);r="int16"===e?new Int16Array(s):new Uint16Array(s)}else if("int32"===e||"uint32"===e||"float32"===e){const s=this.makeTypedArrayBuffer(t,4,i,n);r="int32"===e?new Int32Array(s):"uint32"===e?new Uint32Array(s):new Float32Array(s)}else if("bigint64"===e||"biguint64"===e||"float64"===e){const s=this.makeTypedArrayBuffer(t,8,i,n);r="bigint64"===e?new BigInt64Array(s):"biguint64"===e?new BigUint64Array(s):new Float64Array(s)}return r}static compile(t,e,n=!1,r=!1){let s;if(e=this.getType(e),r){let r;if(r=e.match(/^float/)?-this.compile(t,"float_n",n):-this.compile(t,"uint_n",n),"float_n"===e)return r;t=i.toBytes(r,{littleEndian:n,numberMode:!1,signed:!1})[0]}if("buffer"===e)s=t.buffer;else if("bytes"===e||"uint8"===e)s=t;else if("int8"===e)s=new Int8Array(t.buffer);else if("view"===e)s=new DataView(t.buffer);else if("str"===e)s=(new TextDecoder).decode(t);else if("uint_n"===e||"int_n"===e||"bigint_n"===e){if(1===t.length){const e=this.makeTypedArrayBuffer(t,2,n,r);t=new Uint8Array(e)}n&&t.reverse();let i=0n;t.forEach((t=>i=(i<<8n)+BigInt(t))),"uint_n"!==e&&(i=BigInt.asIntN(8*t.length,i)),s="bigint_n"!==e&&i>=Number.MIN_SAFE_INTEGER&&i<=Number.MAX_SAFE_INTEGER?Number(i):i}else if("float_n"===e)if(t.length<=4){let e;e=4===t.length?t:this.makeTypedArray(t,"float32",!1,r);s=new DataView(e.buffer).getFloat32(0,n)}else{if(!(t.length<=8))throw new RangeError("The provided input is to complex to be converted into a floating point.");{let e;e=8===t.length?t:this.makeTypedArray(t,"float64",!1,r);s=new DataView(e.buffer).getFloat64(0,n)}}else if("number"===e){if(8!==t.length)throw new TypeError("Type mismatch. Cannot convert into number.");const e=new Float64Array(t.buffer);s=Number(e)}else s=this.makeTypedArray(t,e,n,r);return s}};class s extends TypeError{constructor(){super("The input is signed but the converter is not set to treat input as signed.\nYou can pass the string 'signed' to the decode function or when constructing the converter."),this.name="SignError"}}class o extends TypeError{constructor(t,e=null){null===e&&(e=`Character '${t}' is not part of the charset.`),super(e),this.name="DecodingError"}}class a{constructor(t){this.root=t,this.converterArgs={},this.#t()}setIOHandlers(t=n,e=r){this.inputHandler=t,this.outputHandler=e}#t(){this.root.addCharset=(t,e,i=[],n=!0)=>{const r=(t,i,n)=>{if(0===n&&i.length)return console.warn(`This converter has no ${t}. The following argument was ignored:\n'${i}'`),[];let r=n;if("string"==typeof i&&(i=[...i]),Array.isArray(i))r=i.length,i=new Set(i);else if(!(i instanceof Set))throw new TypeError(`The ${t} must be one of the types:\n'str', 'set', 'array'."`);if(i.size===n)return[...i];if(r!==n)throw new Error(`Your ${t} has a length of ${r}. The converter requires a length of ${n}.`);{const i={};(e=[...e]).forEach((t=>{t in i?i[t]++:i[t]=1}));let r="";n<100&&(r=`${e.join("")}\n`,e.forEach((t=>{i[t]>1?r+="^":r+=" "})));const s=Object.keys(i).filter((t=>i[t]>1));throw new Error(`You have repetitive char(s) [ ${s.join(" | ")} ] in your ${t}. Make sure each character is unique.\n${r}`)}};if(this.root.frozenCharsets)throw new Error("The charsets of this converter cannot be changed.");if("string"!=typeof t)throw new TypeError("The charset name must be a string.");n&&t in this.root.charsets&&console.warn(`An existing charset with name ${t} will get replaced.`);const s=r("charset",e,this.root.converter.radix),o=r("padding set",i,this.root.padCharAmount);this.root.charsets[t]=s,o.length&&(this.root.padChars[t]=o),n&&console.info(`New charset '${t}' was added and is ready to use`)},this.root.setDefaultCharset=t=>{if(!(t in this.root.charsets)){const e=Object.keys(this.root.charsets).join("\n * ");throw new TypeError(`Charset ${t} was not found. Available charsets are:\n * ${e}`)}this.root.version=t}}#e(t){return t.map((t=>`'${t}'`)).join(", ")}toSignedStr(t,e){return t=t.replace(/^0+(?!$)/,""),e&&(t="-".concat(t)),t}extractSign(t){let e=!1;return"-"===t[0]&&(e=!0,t=t.slice(1)),[t,e]}#i(t,e,i,n){throw new TypeError([`'${t}'\n\nParameters:`,n?"\n * valid declarations for IO handlers are 'bytesOnly', 'bytesIn', 'bytesOut'":"",this.root.isMutable.signed?"\n * pass 'signed' to disable, 'unsigned' to enable the use of the twos's complement for negative integers":"",this.root.isMutable.littleEndian?"\n * 'be' for big , 'le' for little endian byte order for case conversion":"",this.root.isMutable.padding?"\n * pass 'pad' to fill up, 'nopad' to not fill up the output with the particular padding":"",this.root.isMutable.upper?"\n * valid args for changing the encoded output case are 'upper' and 'lower'":"",`\n * valid args for the output type are ${this.#e(i)}`,e?`\n * the option(s) for version/charset are: ${this.#e(e)}`:"","\n * valid args for integrity check are: 'integrity' and 'nointegrity'",this.root.hasDecimalMode?"\n * 'decimal' for decimal-mode (directly converts Numbers including decimal values, without byte-conversion)":"","\n * 'number' for number-mode (converts every number into a Float64Array to keep the natural js number type)",Object.keys(this.converterArgs).length?`\n * converter specific args:\n - ${(()=>Object.keys(this.converterArgs).map((t=>this.converterArgs[t].map((t=>`'${t}'`)).join(" and "))).join("\n - "))()}`:"","\n\nTraceback:"].join(""))}validateArgs(i,s=!1){const o={decimalMode:this.root.decimalMode,integrity:this.root.integrity,littleEndian:this.root.littleEndian,numberMode:this.root.numberMode,options:this.root.options,outputType:this.root.outputType,padding:this.root.padding,signed:this.root.signed,upper:this.root.upper,version:this.root.version};for(const t in this.converterArgs)o[t]=this.root[t];if(!i.length)return s&&this.setIOHandlers(),o;const a=t=>!!i.includes(t)&&(i.splice(i.indexOf(t),1),!0),l=Object.keys(this.root.charsets),u={integrity:["nointegrity","integrity"],littleEndian:["be","le"],padding:["nopad","pad"],signed:["unsigned","signed"],upper:["lower","upper"],...this.converterArgs};if(s)if(a("bytes_only"))this.setIOHandlers(t,e);else{const i=a("bytes_in")?t:n,s=a("bytes_out")?e:r;this.setIOHandlers(i,s)}const h=this.outputHandler.typeList;if(a("number")&&(o.numberMode=!0,o.outputType="float_n"),a("decimal")){if(!this.root.hasDecimalMode)throw TypeError("Argument 'decimal' is only allowed for converters with a non-integer base.");o.decimalMode=!0,o.outputType="decimal",o.numberMode&&(o.numberMode=!1,console.warn("-> number-mode was disabled due to the decimal-mode"))}if(i.forEach((t=>{if("object"!=typeof t)if(t=String(t).toLowerCase(),l.includes(t))o.version=t;else if(h.includes(t))o.outputType=t;else{let e=!0;for(const i in u)if(u[i].includes(t)){if(e=!1,!this.root.isMutable[i])throw TypeError(`Argument '${t}' is not allowed for this type of converter.`);o[i]=Boolean(u[i].indexOf(t))}e&&this.#i(t,l,h,s)}else o.options={...o.options,...t}})),o.padding&&o.signed&&(o.padding=!1,console.warn("-> padding was set to false due to the signed conversion")),s)for(const t in o)this.root[t]=o[t];return o}signError(){throw new s}wrapOutput(t,e=0){if(!e)return t;const i=new RegExp(`.{1,${e}}`,"gu");return t.match(i).join("\n")}normalizeInput(t,e=!1){return e?String(t):String(t).replace(/\s/g,"")}}class l{constructor(t=!0){this.charsets={},this.decimalMode=!1,this.frozenCharsets=!1,this.hasDecimalMode=!1,this.hasSignedMode=!1,this.integrity=!0,this.littleEndian=!1,this.numberMode=!1,this.outputType="buffer",this.padding=!1,this.padCharAmount=0,this.padChars={},this.nonASCII=!1,this.signed=!1,this.upper=null,t&&(this.utils=new a(this)),this.version="default",this.options={lineWrap:0},this.isMutable={integrity:!0,littleEndian:!1,padding:!1,signed:!1,upper:!1}}encode(t,e,i,...n){const r=this.utils.validateArgs(n);let[s,o,a]=this.utils.inputHandler.toBytes(t,r),l=null;e&&(l=e(r));let[u,h]=this.converter.encode(s,this.charsets[r.version],r.littleEndian,l);return r.signed&&(u=this.utils.toSignedStr(u,o)),r.upper&&(u=u.toUpperCase()),i&&(u=i({inputBytes:s,output:u,settings:r,zeroPadding:h,type:a})),this.utils.wrapOutput(u,r.options.lineWrap)}decode(t,e,i,n,...r){const s=this.utils.validateArgs(r);t=this.utils.normalizeInput(t,n);let o=!1;this.hasSignedMode&&([t,o]=this.utils.extractSign(t),o&&!s.signed&&this.utils.signError()),this.isMutable.upper&&(t=t.toLowerCase()),e&&(t=e({input:t,settings:s}));let a=this.converter.decode(t,this.charsets[s.version],this.padChars[s.version],s.integrity,s.littleEndian);return i&&(a=i({input:t,output:a,settings:s})),this.utils.outputHandler.compile(a,s.outputType,s.littleEndian,o)}} 2 | /** 3 | * [BaseEx|Base91 Converter]{@link https://github.com/UmamiAppearance/BaseExJS/blob/main/src/converters/base-91.js} 4 | * 5 | * @version 0.8.1 6 | * @author UmamiAppearance [mail@umamiappearance.eu] 7 | * @license MIT AND BSD-3-Clause (Base91, Copyright (c) 2000-2006 Joachim Henke) 8 | */class u extends l{constructor(...t){super(),this.converter={radix:91,bsEnc:0,bsDec:0},this.charsets.default=[...'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!#$%&()*+,./:;<=>?@[]^_`{|}~"'],this.version="default",this.utils.validateArgs(t,!0)}encode(t,...e){const i=this.utils.validateArgs(e),n=this.utils.inputHandler.toBytes(t,i)[0];let r=0,s=0,o="";const a=this.charsets[i.version];if(n.forEach((t=>{if(s+=t<13){let t,e,i=13,n=s%8192;n<89&&(i=14,n=s%16384),s>>=i,r-=i,[t,e]=this.#n(n,91),o=`${o}${a[e]}${a[t]}`}})),r){let t,e;[t,e]=this.#n(s,91),o=o.concat(a[e]),(r>7||s>90)&&(o=o.concat(a[t]))}return this.utils.wrapOutput(o,i.options.lineWrap)}decode(t,...e){const i=this.utils.validateArgs(e),n=this.charsets[i.version];t=this.utils.normalizeInput(t);let r=[...t];i.integrity||(r=r.filter((t=>n.includes(t))));let s=r.length,a=!1;s%2&&(a=!0,s--);let l=0,u=0;const h=new Array;for(let t=0;t88?13:14;do{h.push(l%256),l>>=8,u-=8}while(u>7)}if(a){const t=r.at(s),e=n.indexOf(t);h.push(((e<0?t>4294967295?(i=this.makeDataView(8),i.setBigUint64(0,BigInt(t),e)):t>65535?(i=this.makeDataView(4),i.setUint32(0,t,e)):(i=this.makeDataView(2),i.setInt16(0,t,e)):i=new Uint16Array([0])}else n="float",i=this.floatingPoints(t,e);return[new Uint8Array(i.buffer),n]}static bigInts(t,e=!1){const i=new Array,n=e?"push":"unshift",r=18446744073709551616n;if(t<0)for(;t<-9223372036854775808n;)i[n](t%r),t>>=64n;else for(;t>=r;)i[n](t%r),t>>=64n;i[n](t);const s=8*i.length,o=this.makeDataView(s);return i.forEach(((t,i)=>{const n=8*i;o.setBigUint64(n,t,e)})),new Uint8Array(o.buffer)}static toBytes(t,e){let i,n=!1,r="bytes";if(t instanceof ArrayBuffer)i=new Uint8Array(t.slice());else if(ArrayBuffer.isView(t))i="undefined"!=typeof Buffer&&t instanceof Buffer?new Uint8Array(t):new Uint8Array(t.buffer.slice());else if("string"==typeof t||t instanceof String)i=(new TextEncoder).encode(t);else if("number"==typeof t){if(isNaN(t))throw new TypeError("Cannot proceed. Input is NaN.");if(t==1/0)throw new TypeError("Cannot proceed. Input is Infinity.");if(e.signed&&t<0&&(n=!0,t=-t),e.numberMode){const n=this.floatingPoints(t,e.littleEndian);i=new Uint8Array(n.buffer),r="float"}else[i,r]=this.numbers(t,e.littleEndian)}else if("bigint"==typeof t)e.signed&&t<0&&(n=!0,t*=-1n),i=this.bigInts(t,e.littleEndian),r="int";else{if(!Array.isArray(t))throw new TypeError("The provided input type can not be processed.");{const n=new Array;for(const i of t)n.push(...this.toBytes(i,e)[0]);i=Uint8Array.from(n)}}return[i,n,r]}}const n=i,r=class{static get typeList(){return["bigint64","bigint_n","biguint64","buffer","bytes","float32","float64","float_n","int8","int16","int32","int_n","str","uint8","uint16","uint32","uint_n","view"]}static getType(t){if(!this.typeList.includes(t))throw new TypeError(`Unknown output type: '${t}'`);return t}static makeTypedArrayBuffer(t,e,i,n){const r=t.byteLength,s=(e-t.byteLength%e)%e,o=n&&r>1?255:0;let a=t;if(s){a=new Uint8Array(r+s),a.fill(o);const e=i?0:s;a.set(t,e)}return a.buffer}static makeTypedArray(t,e,i,n){let r;if("int16"===e||"uint16"===e){const s=this.makeTypedArrayBuffer(t,2,i,n);r="int16"===e?new Int16Array(s):new Uint16Array(s)}else if("int32"===e||"uint32"===e||"float32"===e){const s=this.makeTypedArrayBuffer(t,4,i,n);r="int32"===e?new Int32Array(s):"uint32"===e?new Uint32Array(s):new Float32Array(s)}else if("bigint64"===e||"biguint64"===e||"float64"===e){const s=this.makeTypedArrayBuffer(t,8,i,n);r="bigint64"===e?new BigInt64Array(s):"biguint64"===e?new BigUint64Array(s):new Float64Array(s)}return r}static compile(t,e,n=!1,r=!1){let s;if(e=this.getType(e),r){let r;if(r=e.match(/^float/)?-this.compile(t,"float_n",n):-this.compile(t,"uint_n",n),"float_n"===e)return r;t=i.toBytes(r,{littleEndian:n,numberMode:!1,signed:!1})[0]}if("buffer"===e)s=t.buffer;else if("bytes"===e||"uint8"===e)s=t;else if("int8"===e)s=new Int8Array(t.buffer);else if("view"===e)s=new DataView(t.buffer);else if("str"===e)s=(new TextDecoder).decode(t);else if("uint_n"===e||"int_n"===e||"bigint_n"===e){if(1===t.length){const e=this.makeTypedArrayBuffer(t,2,n,r);t=new Uint8Array(e)}n&&t.reverse();let i=0n;t.forEach((t=>i=(i<<8n)+BigInt(t))),"uint_n"!==e&&(i=BigInt.asIntN(8*t.length,i)),s="bigint_n"!==e&&i>=Number.MIN_SAFE_INTEGER&&i<=Number.MAX_SAFE_INTEGER?Number(i):i}else if("float_n"===e)if(t.length<=4){let e;e=4===t.length?t:this.makeTypedArray(t,"float32",!1,r);s=new DataView(e.buffer).getFloat32(0,n)}else{if(!(t.length<=8))throw new RangeError("The provided input is to complex to be converted into a floating point.");{let e;e=8===t.length?t:this.makeTypedArray(t,"float64",!1,r);s=new DataView(e.buffer).getFloat64(0,n)}}else if("number"===e){if(8!==t.length)throw new TypeError("Type mismatch. Cannot convert into number.");const e=new Float64Array(t.buffer);s=Number(e)}else s=this.makeTypedArray(t,e,n,r);return s}};class s extends TypeError{constructor(){super("The input is signed but the converter is not set to treat input as signed.\nYou can pass the string 'signed' to the decode function or when constructing the converter."),this.name="SignError"}}class o extends TypeError{constructor(t,e=null){null===e&&(e=`Character '${t}' is not part of the charset.`),super(e),this.name="DecodingError"}}class a{constructor(t){this.root=t,this.converterArgs={},this.#t()}setIOHandlers(t=n,e=r){this.inputHandler=t,this.outputHandler=e}#t(){this.root.addCharset=(t,e,i=[],n=!0)=>{const r=(t,i,n)=>{if(0===n&&i.length)return console.warn(`This converter has no ${t}. The following argument was ignored:\n'${i}'`),[];let r=n;if("string"==typeof i&&(i=[...i]),Array.isArray(i))r=i.length,i=new Set(i);else if(!(i instanceof Set))throw new TypeError(`The ${t} must be one of the types:\n'str', 'set', 'array'."`);if(i.size===n)return[...i];if(r!==n)throw new Error(`Your ${t} has a length of ${r}. The converter requires a length of ${n}.`);{const i={};(e=[...e]).forEach((t=>{t in i?i[t]++:i[t]=1}));let r="";n<100&&(r=`${e.join("")}\n`,e.forEach((t=>{i[t]>1?r+="^":r+=" "})));const s=Object.keys(i).filter((t=>i[t]>1));throw new Error(`You have repetitive char(s) [ ${s.join(" | ")} ] in your ${t}. Make sure each character is unique.\n${r}`)}};if(this.root.frozenCharsets)throw new Error("The charsets of this converter cannot be changed.");if("string"!=typeof t)throw new TypeError("The charset name must be a string.");n&&t in this.root.charsets&&console.warn(`An existing charset with name ${t} will get replaced.`);const s=r("charset",e,this.root.converter.radix),o=r("padding set",i,this.root.padCharAmount);this.root.charsets[t]=s,o.length&&(this.root.padChars[t]=o),n&&console.info(`New charset '${t}' was added and is ready to use`)},this.root.setDefaultCharset=t=>{if(!(t in this.root.charsets)){const e=Object.keys(this.root.charsets).join("\n * ");throw new TypeError(`Charset ${t} was not found. Available charsets are:\n * ${e}`)}this.root.version=t}}#e(t){return t.map((t=>`'${t}'`)).join(", ")}toSignedStr(t,e){return t=t.replace(/^0+(?!$)/,""),e&&(t="-".concat(t)),t}extractSign(t){let e=!1;return"-"===t[0]&&(e=!0,t=t.slice(1)),[t,e]}#i(t,e,i,n){throw new TypeError([`'${t}'\n\nParameters:`,n?"\n * valid declarations for IO handlers are 'bytesOnly', 'bytesIn', 'bytesOut'":"",this.root.isMutable.signed?"\n * pass 'signed' to disable, 'unsigned' to enable the use of the twos's complement for negative integers":"",this.root.isMutable.littleEndian?"\n * 'be' for big , 'le' for little endian byte order for case conversion":"",this.root.isMutable.padding?"\n * pass 'pad' to fill up, 'nopad' to not fill up the output with the particular padding":"",this.root.isMutable.upper?"\n * valid args for changing the encoded output case are 'upper' and 'lower'":"",`\n * valid args for the output type are ${this.#e(i)}`,e?`\n * the option(s) for version/charset are: ${this.#e(e)}`:"","\n * valid args for integrity check are: 'integrity' and 'nointegrity'",this.root.hasDecimalMode?"\n * 'decimal' for decimal-mode (directly converts Numbers including decimal values, without byte-conversion)":"","\n * 'number' for number-mode (converts every number into a Float64Array to keep the natural js number type)",Object.keys(this.converterArgs).length?`\n * converter specific args:\n - ${(()=>Object.keys(this.converterArgs).map((t=>this.converterArgs[t].map((t=>`'${t}'`)).join(" and "))).join("\n - "))()}`:"","\n\nTraceback:"].join(""))}validateArgs(i,s=!1){const o={decimalMode:this.root.decimalMode,integrity:this.root.integrity,littleEndian:this.root.littleEndian,numberMode:this.root.numberMode,options:this.root.options,outputType:this.root.outputType,padding:this.root.padding,signed:this.root.signed,upper:this.root.upper,version:this.root.version};for(const t in this.converterArgs)o[t]=this.root[t];if(!i.length)return s&&this.setIOHandlers(),o;const a=t=>!!i.includes(t)&&(i.splice(i.indexOf(t),1),!0),l=Object.keys(this.root.charsets),u={integrity:["nointegrity","integrity"],littleEndian:["be","le"],padding:["nopad","pad"],signed:["unsigned","signed"],upper:["lower","upper"],...this.converterArgs};if(s)if(a("bytes_only"))this.setIOHandlers(t,e);else{const i=a("bytes_in")?t:n,s=a("bytes_out")?e:r;this.setIOHandlers(i,s)}const h=this.outputHandler.typeList;if(a("number")&&(o.numberMode=!0,o.outputType="float_n"),a("decimal")){if(!this.root.hasDecimalMode)throw TypeError("Argument 'decimal' is only allowed for converters with a non-integer base.");o.decimalMode=!0,o.outputType="decimal",o.numberMode&&(o.numberMode=!1,console.warn("-> number-mode was disabled due to the decimal-mode"))}if(i.forEach((t=>{if("object"!=typeof t)if(t=String(t).toLowerCase(),l.includes(t))o.version=t;else if(h.includes(t))o.outputType=t;else{let e=!0;for(const i in u)if(u[i].includes(t)){if(e=!1,!this.root.isMutable[i])throw TypeError(`Argument '${t}' is not allowed for this type of converter.`);o[i]=Boolean(u[i].indexOf(t))}e&&this.#i(t,l,h,s)}else o.options={...o.options,...t}})),o.padding&&o.signed&&(o.padding=!1,console.warn("-> padding was set to false due to the signed conversion")),s)for(const t in o)this.root[t]=o[t];return o}signError(){throw new s}wrapOutput(t,e=0){if(!e)return t;const i=new RegExp(`.{1,${e}}`,"gu");return t.match(i).join("\n")}normalizeInput(t,e=!1){return e?String(t):String(t).replace(/\s/g,"")}}class l{constructor(t=!0){this.charsets={},this.decimalMode=!1,this.frozenCharsets=!1,this.hasDecimalMode=!1,this.hasSignedMode=!1,this.integrity=!0,this.littleEndian=!1,this.numberMode=!1,this.outputType="buffer",this.padding=!1,this.padCharAmount=0,this.padChars={},this.nonASCII=!1,this.signed=!1,this.upper=null,t&&(this.utils=new a(this)),this.version="default",this.options={lineWrap:0},this.isMutable={integrity:!0,littleEndian:!1,padding:!1,signed:!1,upper:!1}}encode(t,e,i,...n){const r=this.utils.validateArgs(n);let[s,o,a]=this.utils.inputHandler.toBytes(t,r),l=null;e&&(l=e(r));let[u,h]=this.converter.encode(s,this.charsets[r.version],r.littleEndian,l);return r.signed&&(u=this.utils.toSignedStr(u,o)),r.upper&&(u=u.toUpperCase()),i&&(u=i({inputBytes:s,output:u,settings:r,zeroPadding:h,type:a})),this.utils.wrapOutput(u,r.options.lineWrap)}decode(t,e,i,n,...r){const s=this.utils.validateArgs(r);t=this.utils.normalizeInput(t,n);let o=!1;this.hasSignedMode&&([t,o]=this.utils.extractSign(t),o&&!s.signed&&this.utils.signError()),this.isMutable.upper&&(t=t.toLowerCase()),e&&(t=e({input:t,settings:s}));let a=this.converter.decode(t,this.charsets[s.version],this.padChars[s.version],s.integrity,s.littleEndian);return i&&(a=i({input:t,output:a,settings:s})),this.utils.outputHandler.compile(a,s.outputType,s.littleEndian,o)}} 2 | /** 3 | * [BaseEx|Base91 Converter]{@link https://github.com/UmamiAppearance/BaseExJS/blob/main/src/converters/base-91.js} 4 | * 5 | * @version 0.8.1 6 | * @author UmamiAppearance [mail@umamiappearance.eu] 7 | * @license MIT AND BSD-3-Clause (Base91, Copyright (c) 2000-2006 Joachim Henke) 8 | */return class extends l{constructor(...t){super(),this.converter={radix:91,bsEnc:0,bsDec:0},this.charsets.default=[...'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!#$%&()*+,./:;<=>?@[]^_`{|}~"'],this.version="default",this.utils.validateArgs(t,!0)}encode(t,...e){const i=this.utils.validateArgs(e),n=this.utils.inputHandler.toBytes(t,i)[0];let r=0,s=0,o="";const a=this.charsets[i.version];if(n.forEach((t=>{if(s+=t<13){let t,e,i=13,n=s%8192;n<89&&(i=14,n=s%16384),s>>=i,r-=i,[t,e]=this.#n(n,91),o=`${o}${a[e]}${a[t]}`}})),r){let t,e;[t,e]=this.#n(s,91),o=o.concat(a[e]),(r>7||s>90)&&(o=o.concat(a[t]))}return this.utils.wrapOutput(o,i.options.lineWrap)}decode(t,...e){const i=this.utils.validateArgs(e),n=this.charsets[i.version];t=this.utils.normalizeInput(t);let r=[...t];i.integrity||(r=r.filter((t=>n.includes(t))));let s=r.length,a=!1;s%2&&(a=!0,s--);let l=0,u=0;const h=new Array;for(let t=0;t88?13:14;do{h.push(l%256),l>>=8,u-=8}while(u>7)}if(a){const t=r.at(s),e=n.indexOf(t);h.push(((e<0?t>4294967295?(n=this.makeDataView(8),n.setBigUint64(0,BigInt(t),e)):t>65535?(n=this.makeDataView(4),n.setUint32(0,t,e)):(n=this.makeDataView(2),n.setInt16(0,t,e)):n=new Uint16Array([0])}else i="float",n=this.floatingPoints(t,e);return[new Uint8Array(n.buffer),i]}static bigInts(t,e=!1){const n=new Array,i=e?"push":"unshift",r=18446744073709551616n;if(t<0)for(;t<-9223372036854775808n;)n[i](t%r),t>>=64n;else for(;t>=r;)n[i](t%r),t>>=64n;n[i](t);const a=8*n.length,s=this.makeDataView(a);return n.forEach(((t,n)=>{const i=8*n;s.setBigUint64(i,t,e)})),new Uint8Array(s.buffer)}static toBytes(t,e){let n,i=!1,r="bytes";if(t instanceof ArrayBuffer)n=new Uint8Array(t.slice());else if(ArrayBuffer.isView(t))n="undefined"!=typeof Buffer&&t instanceof Buffer?new Uint8Array(t):new Uint8Array(t.buffer.slice());else if("string"==typeof t||t instanceof String)n=(new TextEncoder).encode(t);else if("number"==typeof t){if(isNaN(t))throw new TypeError("Cannot proceed. Input is NaN.");if(t==1/0)throw new TypeError("Cannot proceed. Input is Infinity.");if(e.signed&&t<0&&(i=!0,t=-t),e.numberMode){const i=this.floatingPoints(t,e.littleEndian);n=new Uint8Array(i.buffer),r="float"}else[n,r]=this.numbers(t,e.littleEndian)}else if("bigint"==typeof t)e.signed&&t<0&&(i=!0,t*=-1n),n=this.bigInts(t,e.littleEndian),r="int";else{if(!Array.isArray(t))throw new TypeError("The provided input type can not be processed.");{const i=new Array;for(const n of t)i.push(...this.toBytes(n,e)[0]);n=Uint8Array.from(i)}}return[n,i,r]}}class e{static get typeList(){return["bigint64","bigint_n","biguint64","buffer","bytes","float32","float64","float_n","int8","int16","int32","int_n","str","uint8","uint16","uint32","uint_n","view"]}static getType(t){if(!this.typeList.includes(t))throw new TypeError(`Unknown output type: '${t}'`);return t}static makeTypedArrayBuffer(t,e,n,i){const r=t.byteLength,a=(e-t.byteLength%e)%e,s=i&&r>1?255:0;let o=t;if(a){o=new Uint8Array(r+a),o.fill(s);const e=n?0:a;o.set(t,e)}return o.buffer}static makeTypedArray(t,e,n,i){let r;if("int16"===e||"uint16"===e){const a=this.makeTypedArrayBuffer(t,2,n,i);r="int16"===e?new Int16Array(a):new Uint16Array(a)}else if("int32"===e||"uint32"===e||"float32"===e){const a=this.makeTypedArrayBuffer(t,4,n,i);r="int32"===e?new Int32Array(a):"uint32"===e?new Uint32Array(a):new Float32Array(a)}else if("bigint64"===e||"biguint64"===e||"float64"===e){const a=this.makeTypedArrayBuffer(t,8,n,i);r="bigint64"===e?new BigInt64Array(a):"biguint64"===e?new BigUint64Array(a):new Float64Array(a)}return r}static compile(e,n,i=!1,r=!1){let a;if(n=this.getType(n),r){let r;if(r=n.match(/^float/)?-this.compile(e,"float_n",i):-this.compile(e,"uint_n",i),"float_n"===n)return r;e=t.toBytes(r,{littleEndian:i,numberMode:!1,signed:!1})[0]}if("buffer"===n)a=e.buffer;else if("bytes"===n||"uint8"===n)a=e;else if("int8"===n)a=new Int8Array(e.buffer);else if("view"===n)a=new DataView(e.buffer);else if("str"===n)a=(new TextDecoder).decode(e);else if("uint_n"===n||"int_n"===n||"bigint_n"===n){if(1===e.length){const t=this.makeTypedArrayBuffer(e,2,i,r);e=new Uint8Array(t)}i&&e.reverse();let t=0n;e.forEach((e=>t=(t<<8n)+BigInt(e))),"uint_n"!==n&&(t=BigInt.asIntN(8*e.length,t)),a="bigint_n"!==n&&t>=Number.MIN_SAFE_INTEGER&&t<=Number.MAX_SAFE_INTEGER?Number(t):t}else if("float_n"===n)if(e.length<=4){let t;t=4===e.length?e:this.makeTypedArray(e,"float32",!1,r);a=new DataView(t.buffer).getFloat32(0,i)}else{if(!(e.length<=8))throw new RangeError("The provided input is to complex to be converted into a floating point.");{let t;t=8===e.length?e:this.makeTypedArray(e,"float64",!1,r);a=new DataView(t.buffer).getFloat64(0,i)}}else if("number"===n){if(8!==e.length)throw new TypeError("Type mismatch. Cannot convert into number.");const t=new Float64Array(e.buffer);a=Number(t)}else a=this.makeTypedArray(e,n,i,r);return a}} 2 | /** 3 | * [BaseEx|Byte Converter]{@link https://github.com/UmamiAppearance/BaseExJS/blob/main/src/converters/byte-converter.js} 4 | * 5 | * @version 0.8.1 6 | * @author UmamiAppearance [mail@umamiappearance.eu] 7 | * @license MIT 8 | */const n=(()=>{const t=new Uint16Array([1]),e=new Uint8Array(t.buffer);return Boolean(e.at(0))})();class i{constructor(...t){this.littleEndian=n,this.numberMode=!1,this.outputType="buffer",this.utils={validateArgs:(t,n=!1)=>{const i={littleEndian:this.littleEndian,numberMode:this.numberMode,outputType:this.outputType,signed:!1};if(!t.length)return i;t.includes("number")&&(t.splice(t.indexOf("number"),1),i.numberMode=!0,i.outputType="float_n");const r=e.typeList.map((t=>`'${t}'`)).join(", ");if(t.forEach((t=>{if("le"===(t=String(t).toLowerCase()))i.littleEndian=!0;else if("be"===t)i.littleEndian=!1;else{if(!e.typeList.includes(t))throw new TypeError(`Invalid argument: '${t}.\nValid arguments are:\n'le', 'be', ${r}`);i.outputType=t}})),n)for(const t in i)this[t]=i[t];return i}},this.utils.validateArgs(t,!0)}encode(e,...n){const i=this.utils.validateArgs(n);return t.toBytes(e,i)[0]}decode(t,...n){const i=this.utils.validateArgs(n);return e.compile(t,i.outputType,i.littleEndian)}}export{i as default}; 9 | -------------------------------------------------------------------------------- /dist/converters/ByteConverter/byte-converter.iife.min.js: -------------------------------------------------------------------------------- 1 | var ByteConverter=function(){"use strict";class t{static makeDataView(t){const e=new ArrayBuffer(t);return new DataView(e)}static floatingPoints(t,e=!1){const n=this.makeDataView(8);return n.setFloat64(0,t,e),n}static numbers(t,e=!1){let n,i;if(Number.isInteger(t)){if(i="int",!Number.isSafeInteger(t)){let e,n,i;throw t<0?(e=Number.MIN_SAFE_INTEGER,n="smaller",i="MIN"):(e=Number.MAX_SAFE_INTEGER,n="bigger",i="MAX"),new RangeError(`The provided integer is ${n} than ${i}_SAFE_INTEGER: '${e}'\nData integrity is not guaranteed. Use a BigInt to avoid this issue.\n(If you see this error although a float was provided, the input has to many digits before the decimal point to store the decimal places in a float with 64 bits.)`)}t<0?t<-2147483648?(n=this.makeDataView(8),n.setBigInt64(0,BigInt(t),e)):t<-32768?(n=this.makeDataView(4),n.setInt32(0,t,e)):(n=this.makeDataView(2),n.setInt16(0,t,e)):t>0?t>4294967295?(n=this.makeDataView(8),n.setBigUint64(0,BigInt(t),e)):t>65535?(n=this.makeDataView(4),n.setUint32(0,t,e)):(n=this.makeDataView(2),n.setInt16(0,t,e)):n=new Uint16Array([0])}else i="float",n=this.floatingPoints(t,e);return[new Uint8Array(n.buffer),i]}static bigInts(t,e=!1){const n=new Array,i=e?"push":"unshift",r=18446744073709551616n;if(t<0)for(;t<-9223372036854775808n;)n[i](t%r),t>>=64n;else for(;t>=r;)n[i](t%r),t>>=64n;n[i](t);const a=8*n.length,s=this.makeDataView(a);return n.forEach(((t,n)=>{const i=8*n;s.setBigUint64(i,t,e)})),new Uint8Array(s.buffer)}static toBytes(t,e){let n,i=!1,r="bytes";if(t instanceof ArrayBuffer)n=new Uint8Array(t.slice());else if(ArrayBuffer.isView(t))n="undefined"!=typeof Buffer&&t instanceof Buffer?new Uint8Array(t):new Uint8Array(t.buffer.slice());else if("string"==typeof t||t instanceof String)n=(new TextEncoder).encode(t);else if("number"==typeof t){if(isNaN(t))throw new TypeError("Cannot proceed. Input is NaN.");if(t==1/0)throw new TypeError("Cannot proceed. Input is Infinity.");if(e.signed&&t<0&&(i=!0,t=-t),e.numberMode){const i=this.floatingPoints(t,e.littleEndian);n=new Uint8Array(i.buffer),r="float"}else[n,r]=this.numbers(t,e.littleEndian)}else if("bigint"==typeof t)e.signed&&t<0&&(i=!0,t*=-1n),n=this.bigInts(t,e.littleEndian),r="int";else{if(!Array.isArray(t))throw new TypeError("The provided input type can not be processed.");{const i=new Array;for(const n of t)i.push(...this.toBytes(n,e)[0]);n=Uint8Array.from(i)}}return[n,i,r]}}class e{static get typeList(){return["bigint64","bigint_n","biguint64","buffer","bytes","float32","float64","float_n","int8","int16","int32","int_n","str","uint8","uint16","uint32","uint_n","view"]}static getType(t){if(!this.typeList.includes(t))throw new TypeError(`Unknown output type: '${t}'`);return t}static makeTypedArrayBuffer(t,e,n,i){const r=t.byteLength,a=(e-t.byteLength%e)%e,s=i&&r>1?255:0;let o=t;if(a){o=new Uint8Array(r+a),o.fill(s);const e=n?0:a;o.set(t,e)}return o.buffer}static makeTypedArray(t,e,n,i){let r;if("int16"===e||"uint16"===e){const a=this.makeTypedArrayBuffer(t,2,n,i);r="int16"===e?new Int16Array(a):new Uint16Array(a)}else if("int32"===e||"uint32"===e||"float32"===e){const a=this.makeTypedArrayBuffer(t,4,n,i);r="int32"===e?new Int32Array(a):"uint32"===e?new Uint32Array(a):new Float32Array(a)}else if("bigint64"===e||"biguint64"===e||"float64"===e){const a=this.makeTypedArrayBuffer(t,8,n,i);r="bigint64"===e?new BigInt64Array(a):"biguint64"===e?new BigUint64Array(a):new Float64Array(a)}return r}static compile(e,n,i=!1,r=!1){let a;if(n=this.getType(n),r){let r;if(r=n.match(/^float/)?-this.compile(e,"float_n",i):-this.compile(e,"uint_n",i),"float_n"===n)return r;e=t.toBytes(r,{littleEndian:i,numberMode:!1,signed:!1})[0]}if("buffer"===n)a=e.buffer;else if("bytes"===n||"uint8"===n)a=e;else if("int8"===n)a=new Int8Array(e.buffer);else if("view"===n)a=new DataView(e.buffer);else if("str"===n)a=(new TextDecoder).decode(e);else if("uint_n"===n||"int_n"===n||"bigint_n"===n){if(1===e.length){const t=this.makeTypedArrayBuffer(e,2,i,r);e=new Uint8Array(t)}i&&e.reverse();let t=0n;e.forEach((e=>t=(t<<8n)+BigInt(e))),"uint_n"!==n&&(t=BigInt.asIntN(8*e.length,t)),a="bigint_n"!==n&&t>=Number.MIN_SAFE_INTEGER&&t<=Number.MAX_SAFE_INTEGER?Number(t):t}else if("float_n"===n)if(e.length<=4){let t;t=4===e.length?e:this.makeTypedArray(e,"float32",!1,r);a=new DataView(t.buffer).getFloat32(0,i)}else{if(!(e.length<=8))throw new RangeError("The provided input is to complex to be converted into a floating point.");{let t;t=8===e.length?e:this.makeTypedArray(e,"float64",!1,r);a=new DataView(t.buffer).getFloat64(0,i)}}else if("number"===n){if(8!==e.length)throw new TypeError("Type mismatch. Cannot convert into number.");const t=new Float64Array(e.buffer);a=Number(t)}else a=this.makeTypedArray(e,n,i,r);return a}} 2 | /** 3 | * [BaseEx|Byte Converter]{@link https://github.com/UmamiAppearance/BaseExJS/blob/main/src/converters/byte-converter.js} 4 | * 5 | * @version 0.8.1 6 | * @author UmamiAppearance [mail@umamiappearance.eu] 7 | * @license MIT 8 | */const n=(()=>{const t=new Uint16Array([1]),e=new Uint8Array(t.buffer);return Boolean(e.at(0))})();return class{constructor(...t){this.littleEndian=n,this.numberMode=!1,this.outputType="buffer",this.utils={validateArgs:(t,n=!1)=>{const i={littleEndian:this.littleEndian,numberMode:this.numberMode,outputType:this.outputType,signed:!1};if(!t.length)return i;t.includes("number")&&(t.splice(t.indexOf("number"),1),i.numberMode=!0,i.outputType="float_n");const r=e.typeList.map((t=>`'${t}'`)).join(", ");if(t.forEach((t=>{if("le"===(t=String(t).toLowerCase()))i.littleEndian=!0;else if("be"===t)i.littleEndian=!1;else{if(!e.typeList.includes(t))throw new TypeError(`Invalid argument: '${t}.\nValid arguments are:\n'le', 'be', ${r}`);i.outputType=t}})),n)for(const t in i)this[t]=i[t];return i}},this.utils.validateArgs(t,!0)}encode(e,...n){const i=this.utils.validateArgs(n);return t.toBytes(e,i)[0]}decode(t,...n){const i=this.utils.validateArgs(n);return e.compile(t,i.outputType,i.littleEndian)}}}(); 9 | -------------------------------------------------------------------------------- /examples/assets/prism.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Prism.js Custom Theme for https://github.com/UmamiAppearance/JSLiveExamples 3 | * 4 | * Based on: 5 | * Coldark Theme for Prism.js (variation: Cold) 6 | * from: Armand Philippot 7 | * homepage: https://github.com/ArmandPhilippot/coldark-prism 8 | * license: MIT 9 | * 10 | * variations inspired by: 11 | * JavaScript code prettifier 12 | * from: Google 13 | * homepage: https://github.com/googlearchive/code-prettify 14 | * 15 | * NOTE: This is not a fully featured Theme for Prism.js 16 | */ 17 | 18 | code[class*="language-"], 19 | pre[class*="language-"] { 20 | color: #111b27; 21 | font-family: monospace; 22 | text-align: left; 23 | white-space: pre; 24 | word-spacing: normal; 25 | word-break: normal; 26 | word-wrap: normal; 27 | line-height: 1.5; 28 | -moz-tab-size: 4; 29 | -o-tab-size: 4; 30 | tab-size: 4; 31 | -webkit-hyphens: none; 32 | -moz-hyphens: none; 33 | -ms-hyphens: none; 34 | hyphens: none; 35 | } 36 | 37 | /* Code blocks */ 38 | pre[class*="language-"] { 39 | padding: 1em; 40 | margin: 0.5em 0; 41 | overflow: auto; 42 | } 43 | 44 | /* Inline code */ 45 | :not(pre) > code[class*="language-"] { 46 | white-space: normal; 47 | } 48 | 49 | .token.comment, 50 | .token.prolog, 51 | .token.doctype, 52 | .token.cdata { 53 | color: #800; 54 | } 55 | 56 | .token.punctuation { 57 | color: #111b27; 58 | } 59 | 60 | .token.delimiter.important, 61 | .token.selector .parent, 62 | .token.tag, 63 | .token.tag .token.punctuation { 64 | color: #006d6d; 65 | } 66 | 67 | .token.attr-name, 68 | .token.boolean, 69 | .token.boolean.important, 70 | .token.number, 71 | .token.constant, 72 | .token.selector .token.attribute { 73 | color: #755f00; 74 | } 75 | 76 | .token.class-name, 77 | .token.key, 78 | .token.parameter, 79 | .token.property, 80 | .token.property-access, 81 | .token.variable { 82 | color: #005a8e; 83 | } 84 | 85 | .token.attr-value, 86 | .token.inserted, 87 | .token.color, 88 | .token.selector .token.value, 89 | .token.string, 90 | .token.string .token.url-link { 91 | color: #080; 92 | } 93 | 94 | .token.builtin, 95 | .token.keyword-array, 96 | .token.package, 97 | .token.regex { 98 | color: #af00af; 99 | } 100 | 101 | .token.function, 102 | .token.selector .token.class, 103 | .token.selector .token.id { 104 | color: #7c00aa; 105 | } 106 | 107 | .token.atrule .token.rule, 108 | .token.combinator, 109 | .token.keyword, 110 | .token.operator, 111 | .token.pseudo-class, 112 | .token.pseudo-element, 113 | .token.selector, 114 | .token.unit { 115 | color: #008; 116 | } 117 | 118 | .token.deleted, 119 | .token.important { 120 | color: #c22f2e; 121 | } 122 | 123 | .token.keyword-this, 124 | .token.this { 125 | color: #005a8e; 126 | } 127 | 128 | .token.important, 129 | .token.keyword-this, 130 | .token.this, 131 | .token.bold { 132 | font-weight: bold; 133 | } 134 | 135 | .token.delimiter.important { 136 | font-weight: inherit; 137 | } 138 | 139 | .token.italic { 140 | font-style: italic; 141 | } 142 | 143 | .token.entity { 144 | cursor: help; 145 | } 146 | 147 | .language-markdown .token.title, 148 | .language-markdown .token.title .token.punctuation { 149 | color: #005a8e; 150 | font-weight: bold; 151 | } 152 | 153 | .language-markdown .token.blockquote.punctuation { 154 | color: #af00af; 155 | } 156 | 157 | .language-markdown .token.code { 158 | color: #006d6d; 159 | } 160 | 161 | .language-markdown .token.hr.punctuation { 162 | color: #005a8e; 163 | } 164 | 165 | .language-markdown .token.url > .token.content { 166 | color: #116b00; 167 | } 168 | 169 | .language-markdown .token.url-link { 170 | color: #755f00; 171 | } 172 | 173 | .language-markdown .token.list.punctuation { 174 | color: #af00af; 175 | } 176 | 177 | .language-markdown .token.table-header { 178 | color: #111b27; 179 | } 180 | 181 | .language-json .token.operator { 182 | color: #111b27; 183 | } 184 | 185 | .language-scss .token.variable { 186 | color: #006d6d; 187 | } 188 | -------------------------------------------------------------------------------- /lib/big.js/big.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * big.js v6.2.1 // Copyright (c) 2022 Michael Mclaughlin // https://github.com/MikeMcl/big.js/LICENCE.md // Modified (reduced) and minified for BaseEx 3 | */ 4 | let DP=20,RM=1,MAX_DP=1e6,NE=-7,PE=21,STRICT=!1,NAME="[big.js] ",INVALID=NAME+"Invalid ",INVALID_DP=INVALID+"decimal places",INVALID_RM=INVALID+"rounding mode",P={},NUMERIC=/^-?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i;function _Big_(){function Big(n){let x=this;if(!(x instanceof Big))return void 0===n?_Big_():new Big(n);if(n instanceof Big)x.s=n.s,x.e=n.e,x.c=n.c.slice();else{if("string"!=typeof n){if(!0===Big.strict&&"bigint"!=typeof n)throw TypeError(INVALID+"value");n=0===n&&1/n<0?"-0":String(n)}parse(x,n)}x.constructor=Big}return Big.prototype=P,Big.DP=DP,Big.RM=RM,Big.NE=NE,Big.PE=PE,Big.strict=STRICT,Big.roundDown=0,Big.roundHalfUp=1,Big.roundHalfEven=2,Big.roundUp=3,Big}function parse(x,n){let e,i,nl;if(!NUMERIC.test(n))throw Error(`${INVALID}number`);for(x.s="-"==n.charAt(0)?(n=n.slice(1),-1):1,(e=n.indexOf("."))>-1&&(n=n.replace(".","")),(i=n.search(/e/i))>0?(e<0&&(e=i),e+=+n.slice(i+1),n=n.substring(0,i)):e<0&&(e=n.length),nl=n.length,i=0;i0&&"0"==n.charAt(--nl););for(x.e=e-i-1,x.c=[],e=0;i<=nl;)x.c[e++]=+n.charAt(i++)}return x}function round(x,sd,rm,more){let xc=x.c;if(void 0===rm&&(rm=x.constructor.RM),0!==rm&&1!==rm&&2!==rm&&3!==rm)throw Error(INVALID_RM);if(sd<1)more=3===rm&&(more||!!xc[0])||0===sd&&(1===rm&&xc[0]>=5||2===rm&&(xc[0]>5||5===xc[0]&&(more||void 0!==xc[1]))),xc.length=1,more?(x.e=x.e-sd+1,xc[0]=1):xc[0]=x.e=0;else if(sd=5||2===rm&&(xc[sd]>5||5===xc[sd]&&(more||void 0!==xc[sd+1]||1&xc[sd-1]))||3===rm&&(more||!!xc[0]),xc.length=sd,more)for(;++xc[--sd]>9;)if(xc[sd]=0,0===sd){++x.e,xc.unshift(1);break}for(sd=xc.length;!xc[--sd];)xc.pop()}return x}function stringify(x,doExponential,isNonzero){let e=x.e,s=x.c.join(""),n=s.length;if(doExponential)s=s.charAt(0)+(n>1?"."+s.slice(1):"")+(e<0?"e":"e+")+e;else if(e<0){for(;++e;)s="0"+s;s="0."+s}else if(e>0)if(++e>n)for(e-=n;e--;)s+="0";else e1&&(s=s.charAt(0)+"."+s.slice(1));return x.s<0&&isNonzero?"-"+s:s}P.abs=function(){let x=new this.constructor(this);return x.s=1,x},P.cmp=function(y){let isneg,x=this,xc=x.c,yc=(y=new x.constructor(y)).c,i=x.s,j=y.s,k=x.e,l=y.e;if(!xc[0]||!yc[0])return xc[0]?i:yc[0]?-j:0;if(i!=j)return i;if(isneg=i<0,k!=l)return k>l^isneg?1:-1;for(j=(k=xc.length)<(l=yc.length)?k:l,i=-1;++iyc[i]^isneg?1:-1;return k==l?0:k>l^isneg?1:-1},P.eq=function(y){return 0===this.cmp(y)},P.gt=function(y){return this.cmp(y)>0},P.gte=function(y){return this.cmp(y)>-1},P.lt=function(y){return this.cmp(y)<0},P.lte=function(y){return this.cmp(y)<1},P.minus=P.sub=function(y){let i,j,t,xlty,x=this,Big=x.constructor,a=x.s,b=(y=new Big(y)).s;if(a!=b)return y.s=-b,x.plus(y);let xc=x.c.slice(),xe=x.e,yc=y.c,ye=y.e;if(!xc[0]||!yc[0])return yc[0]?y.s=-b:xc[0]?y=new Big(x):y.s=1,y;if(a=xe-ye){for((xlty=a<0)?(a=-a,t=xc):(ye=xe,t=yc),t.reverse(),b=a;b--;)t.push(0);t.reverse()}else for(j=((xlty=xc.length0)for(;b--;)xc[i++]=0;for(b=i;j>a;){if(xc[--j]0?(ye=xe,t=yc):(e=-e,t=xc),t.reverse();e--;)t.push(0);t.reverse()}for(xc.length-yc.length<0&&(t=yc,yc=xc,xc=t),e=yc.length,k=0;e;xc[e]%=10)k=(xc[--e]=xc[e]+yc[e]+k)/10|0;for(k&&(xc.unshift(k),++ye),e=xc.length;0===xc[--e];)xc.pop();return y.c=xc,y.e=ye,y},P.round=function(dp,rm){if(void 0===dp)dp=0;else if(dp!==~~dp||dp<-MAX_DP||dp>MAX_DP)throw Error(INVALID_DP);return round(new this.constructor(this),dp+this.e+1,rm)},P.toFixed=function(dp,rm){let x=this,n=x.c[0];if(void 0!==dp){if(dp!==~~dp||dp<0||dp>MAX_DP)throw Error(INVALID_DP);for(x=round(new x.constructor(x),dp+x.e+1,rm),dp=dp+x.e+1;x.c.length=Big.PE,!!x.c[0])},P.toNumber=function(){let n=Number(stringify(this,!0,!0));if(!0===this.constructor.strict&&!this.eq(n.toString()))throw Error(NAME+"Imprecise conversion");return n};export const Big=_Big_();export default Big; 5 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "base-ex", 3 | "version": "0.8.1", 4 | "description": "A collection of classes for data representation written in JavaScript.", 5 | "main": "./cjs/base-ex.cjs", 6 | "module": "./src/base-ex.js", 7 | "exports": { 8 | "import": "./src/base-ex.js", 9 | "require": "./cjs/base-ex.cjs" 10 | }, 11 | "type": "module", 12 | "directories": { 13 | "examples": "examples", 14 | "cjs": "cjs", 15 | "dist": "dist", 16 | "test": "test", 17 | "src": "src" 18 | }, 19 | "scripts": { 20 | "build": "rollup -c", 21 | "build:bytes": "rollup -c --environment BYTES_ONLY", 22 | "build:cjs": "rollup src/base-ex.js --file cjs/base-ex.cjs --format cjs -m", 23 | "lint": "eslint ./src/*", 24 | "lint:fix": "eslint ./src/* --fix", 25 | "start": "http-server -a localhost -o ./examples/demo.html", 26 | "start:lan": "http-server -o ./examples/demo.html", 27 | "test": "remembrance && ava", 28 | "test:dev": "ava" 29 | }, 30 | "repository": { 31 | "type": "git", 32 | "url": "git+https://github.com/UmamiAppearance/BaseExJS.git" 33 | }, 34 | "keywords": [ 35 | "unary", 36 | "binary", 37 | "bytes", 38 | "base conversion", 39 | "Base2", 40 | "Base8", 41 | "Base10", 42 | "Base16", 43 | "Base32", 44 | "Base36", 45 | "Base58", 46 | "Base62", 47 | "Base64", 48 | "UUencode", 49 | "Base85", 50 | "Base91", 51 | "LEB128", 52 | "Ecoji", 53 | "Base2048", 54 | "BasePhi", 55 | "Golden Ratio Base" 56 | ], 57 | "author": "UmamiAppearance", 58 | "license": "MIT", 59 | "bugs": { 60 | "url": "https://github.com/UmamiAppearance/BaseExJS/issues", 61 | "email": "mail@umamiappearance.eu" 62 | }, 63 | "homepage": "https://github.com/UmamiAppearance/BaseExJS#readme", 64 | "devDependencies": { 65 | "@rollup/plugin-terser": "^0.4.3", 66 | "ava": "^5.3.1", 67 | "big.js": "^6.2.1", 68 | "eslint": "^8.44.0", 69 | "http-server": "^14.1.1", 70 | "remembrance": "^0.3.1", 71 | "rollup": "^3.26.1", 72 | "rollup-plugin-your-function": "^0.5.3" 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /rollup.config.mjs: -------------------------------------------------------------------------------- 1 | import { readdirSync } from "fs"; 2 | import terser from "@rollup/plugin-terser"; 3 | import { yourFunction } from "rollup-plugin-your-function"; 4 | 5 | const toInitCap = str => { 6 | if (str === "uuencode") { 7 | return "UUencode"; 8 | } 9 | 10 | if (str === "leb-128") { 11 | return "LEB128"; 12 | } 13 | 14 | return str 15 | .at(0) 16 | .toUpperCase() 17 | .concat( 18 | str.slice(1)) 19 | .replaceAll(/-./g, (s) => s 20 | .at(1) 21 | .toUpperCase() 22 | ); 23 | } 24 | const converters = new Array(); 25 | const bytesOnly = process.argv.includes("BYTES_ONLY"); 26 | 27 | const makeConverter = (inputFile, srcDir, distDir, useGroupDir, t=terser()) => { 28 | const filename = inputFile.replace(/\.js$/, ""); 29 | const modName = toInitCap(filename); 30 | const groupDir = (useGroupDir) ? `${modName}/`: ""; 31 | 32 | const converter = { 33 | input: `${srcDir}${inputFile}`, 34 | output: [ 35 | { 36 | format: "iife", 37 | name: modName, 38 | file: `${distDir}${groupDir}${filename}.iife.js` 39 | }, 40 | { 41 | format: "iife", 42 | name: modName, 43 | file: `${distDir}${groupDir}${filename}.iife.min.js`, 44 | plugins: [t] 45 | }, 46 | { 47 | format: "es", 48 | name: modName, 49 | file: `${distDir}${groupDir}${filename}.esm.js` 50 | }, 51 | { 52 | format: "es", 53 | name: modName, 54 | file: `${distDir}${groupDir}${filename}.esm.min.js`, 55 | plugins: [t] 56 | }, 57 | ] 58 | }; 59 | 60 | if (bytesOnly) { 61 | converter.plugins = [ 62 | yourFunction({ 63 | include: "**/utils.js", 64 | fn: source => { 65 | const code = source 66 | .replace( 67 | /DEFAULT_INPUT_HANDLER ?= ?SmartInput/, 68 | "DEFAULT_INPUT_HANDLER = BytesInput" 69 | ) 70 | .replace( 71 | /DEFAULT_OUTPUT_HANDLER ?= ?SmartOutput/, 72 | "DEFAULT_OUTPUT_HANDLER = BytesOutput" 73 | ); 74 | return code; 75 | } 76 | }) 77 | ] 78 | } 79 | 80 | converters.push(converter); 81 | } 82 | 83 | // allow only the main license for base-ex class 84 | const selectiveTerser = terser({ 85 | format: { 86 | comments: (_, comment) => { 87 | const text = comment.value; 88 | const type = comment.type; 89 | return ( 90 | type === "comment2" && 91 | !(/BaseEx\|\w+/).test(text) && 92 | (/@license/i).test(text) 93 | ); 94 | } 95 | } 96 | }); 97 | 98 | makeConverter("base-ex.js", "src/", "dist/", false, selectiveTerser); 99 | 100 | readdirSync("./src/converters").forEach(inputFile => { 101 | makeConverter(inputFile, "src/converters/", "dist/converters/", true) 102 | }); 103 | 104 | 105 | export default converters; 106 | -------------------------------------------------------------------------------- /src/base-ex.js: -------------------------------------------------------------------------------- 1 | /** 2 | * [BaseEx]{@link https://github.com/UmamiAppearance/BaseExJS} 3 | * 4 | * @version 0.8.1 5 | * @author UmamiAppearance [mail@umamiappearance.eu] 6 | * @license MIT 7 | */ 8 | 9 | /* eslint-disable sort-imports */ 10 | 11 | import Base1 from "./converters/base-1.js"; 12 | import Base16 from "./converters/base-16.js"; 13 | import Base32 from "./converters/base-32.js"; 14 | import Base58 from "./converters/base-58.js"; 15 | import Base64 from "./converters/base-64.js"; 16 | import UUencode from "./converters/uuencode.js"; 17 | import Base85 from "./converters/base-85.js"; 18 | import Base91 from "./converters/base-91.js"; 19 | import LEB128 from "./converters/leb-128.js"; 20 | import Ecoji from "./converters/ecoji.js"; 21 | import Base2048 from "./converters/base-2048.js"; 22 | import SimpleBase from "./converters/simple-base.js"; 23 | import BasePhi from "./converters/base-phi.js"; 24 | import ByteConverter from "./converters/byte-converter.js"; 25 | 26 | import { DEFAULT_OUTPUT_HANDLER } from "./utils.js"; 27 | 28 | /** 29 | * BaseEx Converter Collection. 30 | * --------------------------- 31 | * This class holds almost any available converter 32 | * of the whole BaseEx converter collection. The 33 | * instances are ready to use. Various input can be 34 | * converted to a base string or the base string can be 35 | * decoded into various formats. 36 | */ 37 | class BaseEx { 38 | 39 | /** 40 | * BaseEx Base Collection Constructor. 41 | * @param {string} [outputType] - Output type. 42 | */ 43 | constructor(outputType="buffer") { 44 | 45 | if (!DEFAULT_OUTPUT_HANDLER.typeList.includes(outputType)) { 46 | let message = `Invalid argument '${outputType}' for output type. Allowed types are:\n`; 47 | message = message.concat(DEFAULT_OUTPUT_HANDLER.typeList.join(", ")); 48 | 49 | throw new TypeError(message); 50 | } 51 | 52 | this.base1 = new Base1("default", outputType); 53 | this.base16 = new Base16("default", outputType); 54 | this.base32_crockford = new Base32("rfc4648", outputType); 55 | this.base32_rfc3548 = new Base32("rfc3548", outputType); 56 | this.base32_rfc4648 = new Base32("rfc4648", outputType); 57 | this.base32_zbase32 = new Base32("zbase32", outputType); 58 | this.base58 = new Base58("default", outputType); 59 | this.base58_bitcoin = new Base58("bitcoin", outputType); 60 | this.base58_flickr = new Base58("flickr", outputType); 61 | this.base64 = new Base64("default", outputType); 62 | this.base64_urlsafe = new Base64("urlsafe", outputType); 63 | this.uuencode = new UUencode("default", outputType); 64 | this.uuencode_original = new UUencode("original", outputType); 65 | this.xxencode = new UUencode("xx", outputType); 66 | this.base85_adobe = new Base85("adobe", outputType); 67 | this.base85_ascii = new Base85("ascii85", outputType); 68 | this.base85_z85 = new Base85("z85", outputType); 69 | this.base91 = new Base91("default",outputType); 70 | this.leb128 = new LEB128("default", outputType); 71 | this.ecoji_v1 = new Ecoji("emojis_v1", outputType); 72 | this.ecoji_v2 = new Ecoji("emojis_v2", outputType); 73 | this.base2048 = new Base2048("default", outputType); 74 | this.basePhi = new BasePhi("default", outputType); 75 | this.byteConverter = new ByteConverter(outputType); 76 | 77 | this.simpleBase = {}; 78 | for (let i=2; i<=62; i++) { 79 | this.simpleBase[`base${i}`] = new SimpleBase(i, outputType); 80 | } 81 | } 82 | } 83 | 84 | export { 85 | Base1, 86 | Base16, 87 | Base32, 88 | Base58, 89 | Base64, 90 | UUencode, 91 | Base85, 92 | Base91, 93 | LEB128, 94 | Ecoji, 95 | Base2048, 96 | SimpleBase, 97 | BasePhi, 98 | ByteConverter, 99 | BaseEx 100 | }; 101 | -------------------------------------------------------------------------------- /src/converters/base-1.js: -------------------------------------------------------------------------------- 1 | /** 2 | * [BaseEx|Base1 Converter]{@link https://github.com/UmamiAppearance/BaseExJS/blob/main/src/converters/base-1.js} 3 | * 4 | * @version 0.8.1 5 | * @author UmamiAppearance [mail@umamiappearance.eu] 6 | * @license MIT 7 | */ 8 | 9 | import { BaseConverter, BaseTemplate } from "../core.js"; 10 | 11 | /** 12 | * BaseEx Base 1 Converter. 13 | * ----------------------- 14 | * This is a unary/base1 converter. It is converting input 15 | * to a decimal number, which is converted into an unary 16 | * string. Due to the limitations on string (or array) length 17 | * it is only suitable for the conversions of numbers up to 18 | * roughly 2^28. 19 | */ 20 | export default class Base1 extends BaseTemplate { 21 | 22 | /** 23 | * BaseEx Base1 Constructor. 24 | * @param {...string} [args] - Converter settings. 25 | */ 26 | constructor(...args) { 27 | super(); 28 | 29 | // All chars in the string are used and picked randomly (prob. suitable for obfuscation) 30 | this.charsets.all = [..." !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"]; 31 | 32 | // The sequence is used from left to right again and again 33 | this.charsets.sequence = [..."Hello World!"]; 34 | 35 | // Standard unary string with one character 36 | this.charsets.default = ["1"]; 37 | 38 | // Telly Mark string, using hash for 5 and vertical bar for 1 39 | this.charsets.tmark = ["|", "#"]; 40 | 41 | // Base 10 converter 42 | this.converter = new BaseConverter(10, 0, 0); 43 | 44 | // converter settings 45 | this.hasSignedMode = true; 46 | this.littleEndian = true; 47 | this.signed = true; 48 | 49 | // mutable extra args 50 | this.isMutable.charsets = false; 51 | this.isMutable.signed = true; 52 | this.isMutable.upper = true; 53 | 54 | // apply user settings 55 | this.utils.validateArgs(args, true); 56 | } 57 | 58 | 59 | /** 60 | * BaseEx Base1 Encoder. 61 | * @param {*} input - Input according to the used byte converter. 62 | * @param {...str} [args] - Converter settings. 63 | * @returns {string} - Base1 encoded string. 64 | */ 65 | encode(input, ...args) { 66 | 67 | // argument validation and input settings 68 | const settings = this.utils.validateArgs(args); 69 | 70 | let inputBytes, negative; 71 | [inputBytes, negative,] = this.utils.inputHandler.toBytes(input, settings); 72 | 73 | // Convert to BaseRadix string 74 | let base10 = this.converter.encode(inputBytes, null, settings.littleEndian)[0]; 75 | 76 | let n = BigInt(base10); 77 | 78 | // Limit the input before it even starts. 79 | // The executing engine will most likely 80 | // give up much earlier. 81 | // (2**29-24 during tests) 82 | 83 | if (n > Number.MAX_SAFE_INTEGER) { 84 | throw new RangeError("Invalid string length."); 85 | } else if (n > 16777216) { 86 | console.warn("The string length is really long. The JavaScript engine may have memory issues generating the output string."); 87 | } 88 | 89 | n = Number(n); 90 | 91 | const charset = this.charsets[settings.version]; 92 | const charAmount = charset.length; 93 | let output = ""; 94 | 95 | // Convert to unary in respect to the version differences 96 | if (charAmount === 1) { 97 | output = charset.at(0).repeat(n) 98 | } else if (settings.version === "all") { 99 | for (let i=0; i 4) { 106 | output = charset.at(1).repeat((n - singulars) / 5); 107 | } 108 | output += charset.at(0).repeat(singulars); 109 | } else { 110 | for (let i=0; i { 67 | 68 | // Remove "0x" if present 69 | normInput = normInput.replace(/^0x/, ""); 70 | 71 | // remove non-charset characters if integrity 72 | // check is disabled 73 | if (!settings.integrity) { 74 | normInput = normInput 75 | .toLowerCase() 76 | .replace(/[^0-9a-f]/g, ""); 77 | } 78 | 79 | // Ensure even number of characters 80 | if (normInput.length % 2) { 81 | normInput = "0".concat(normInput); 82 | } 83 | 84 | return normInput; 85 | } 86 | 87 | return super.decode(input, normalizeInput, null, false, ...args); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/converters/base-2048.js: -------------------------------------------------------------------------------- 1 | /** 2 | * [BaseEx|Base2048 Converter]{@link https://github.com/UmamiAppearance/BaseExJS/blob/main/src/converters/base-2048.js} 3 | * 4 | * @version 0.8.1 5 | * @author UmamiAppearance [mail@umamiappearance.eu] 6 | * @license MIT 7 | */ 8 | 9 | import { BaseTemplate } from "../core.js"; 10 | import { DecodingError } from "../utils.js"; 11 | 12 | /** 13 | * BaseEx Base 2048 Converter. 14 | * ------------------------ 15 | * This is a base2048/converter. Various input can be 16 | * converted to a hex string or a hex string can be 17 | * decoded into various formats. It is possible to 18 | * convert in both signed and unsigned mode. 19 | * 20 | * @see https://github.com/qntm/base2048 21 | */ 22 | export default class Base2048 extends BaseTemplate { 23 | 24 | /** 25 | * BaseEx Base2048 Constructor. 26 | * @param {...string} [args] - Converter settings. 27 | */ 28 | constructor(...args) { 29 | super(); 30 | 31 | // converter (properties only) 32 | this.converter = { 33 | radix: 2048, 34 | bsEnc: 11, 35 | bsEncPad: 3, 36 | bsDec: 8 37 | } 38 | 39 | // default settings 40 | this.charsets.default = [..."89ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzÆÐØÞßæðøþĐđĦħıĸŁłŊŋŒœŦŧƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƢƣƤƥƦƧƨƩƪƫƬƭƮƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿǀǁǂǃǝǤǥǶǷȜȝȠȡȢȣȤȥȴȵȶȷȸȹȺȻȼȽȾȿɀɁɂɃɄɅɆɇɈɉɊɋɌɍɎɏɐɑɒɓɔɕɖɗɘəɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯͰͱͲͳͶͷͻͼͽͿΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩαβγδεζηθικλμνξοπρςστυφχψωϏϗϘϙϚϛϜϝϞϟϠϡϢϣϤϥϦϧϨϩϪϫϬϭϮϯϳϷϸϺϻϼϽϾϿЂЄЅІЈЉЊЋЏАБВГДЕЖЗИКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзиклмнопрстуфхцчшщъыьэюяђєѕіјљњћџѠѡѢѣѤѥѦѧѨѩѪѫѬѭѮѯѰѱѲѳѴѵѸѹѺѻѼѽѾѿҀҁҊҋҌҍҎҏҐґҒғҔҕҖҗҘҙҚқҜҝҞҟҠҡҢңҤҥҦҧҨҩҪҫҬҭҮүҰұҲҳҴҵҶҷҸҹҺһҼҽҾҿӀӃӄӅӆӇӈӉӊӋӌӍӎӏӔӕӘәӠӡӨөӶӷӺӻӼӽӾӿԀԁԂԃԄԅԆԇԈԉԊԋԌԍԎԏԐԑԒԓԔԕԖԗԘԙԚԛԜԝԞԟԠԡԢԣԤԥԦԧԨԩԪԫԬԭԮԯԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿՀՁՂՃՄՅՆՇՈՉՊՋՌՍՎՏՐՑՒՓՔՕՖաբգդեզէըթժիլխծկհձղճմյնշոչպջռսվտրցւփքօֆאבגדהוזחטיךכלםמןנסעףפץצקרשתװױײؠءابةتثجحخدذرزسشصضطظعغػؼؽؾؿفقكلمنهوىي٠١٢٣٤٥٦٧٨٩ٮٯٱٲٳٴٹٺٻټٽپٿڀځڂڃڄڅچڇڈډڊڋڌڍڎڏڐڑڒړڔڕږڗژڙښڛڜڝڞڟڠڡڢڣڤڥڦڧڨکڪګڬڭڮگڰڱڲڳڴڵڶڷڸڹںڻڼڽھڿہۃۄۅۆۇۈۉۊۋیۍێۏېۑےەۮۯ۰۱۲۳۴۵۶۷۸۹ۺۻۼۿܐܒܓܔܕܖܗܘܙܚܛܜܝܞܟܠܡܢܣܤܥܦܧܨܩܪܫܬܭܮܯݍݎݏݐݑݒݓݔݕݖݗݘݙݚݛݜݝݞݟݠݡݢݣݤݥݦݧݨݩݪݫݬݭݮݯݰݱݲݳݴݵݶݷݸݹݺݻݼݽݾݿހށނރބޅކއވމފދތލގޏސޑޒޓޔޕޖޗޘޙޚޛޜޝޞޟޠޡޢޣޤޥޱ߀߁߂߃߄߅߆߇߈߉ߊߋߌߍߎߏߐߑߒߓߔߕߖߗߘߙߚߛߜߝߞߟߠߡߢߣߤߥߦߧߨߩߪࠀࠁࠂࠃࠄࠅࠆࠇࠈࠉࠊࠋࠌࠍࠎࠏࠐࠑࠒࠓࠔࠕࡀࡁࡂࡃࡄࡅࡆࡇࡈࡉࡊࡋࡌࡍࡎࡏࡐࡑࡒࡓࡔࡕࡖࡗࡘࡠࡡࡢࡣࡤࡥࡦࡧࡨࡩࡪࢠࢡࢢࢣࢤࢥࢦࢧࢨࢩࢪࢫࢬࢭࢮࢯࢰࢱࢲࢳࢴࢶࢷࢸࢹࢺࢻࢼࢽऄअआइईउऊऋऌऍऎएऐऑऒओऔकखगघङचछजझञटठडढणतथदधनपफबभमयरलळवशषसहऽॐॠॡ०१२३४५६७८९ॲॳॴॵॶॷॸॹॺॻॼॽॾॿঀঅআইঈউঊঋঌএঐওঔকখগঘঙচছজঝঞটঠডঢণতথদধনপফবভমযরলশষসহঽৎৠৡ০১২৩৪৫৬৭৮৯ৰৱ৴৵৶৷৸৹ৼਅਆਇਈਉਊਏਐਓਔਕਖਗਘਙਚਛਜਝਞਟਠਡਢਣਤਥਦਧਨਪਫਬਭਮਯਰਲਵਸਹੜ੦੧੨੩੪੫੬੭੮੯ੲੳੴઅઆઇઈઉઊઋઌઍએઐઑઓઔકખગઘઙચછજઝઞટઠડઢણતથદધનપફબભમયરલળવશષસહઽૐૠૡ૦૧૨૩૪૫૬૭૮૯ૹଅଆଇଈଉଊଋଌଏଐଓଔକଖଗଘଙଚଛଜଝଞଟଠଡଢଣତଥଦଧନପଫବଭମଯରଲଳଵଶଷସହଽୟୠୡ୦୧୨୩୪୫୬୭୮୯ୱ୲୳୴୵୶୷ஃஅஆஇஈஉஊஎஏஐஒஓகஙசஜஞடணதநனபமயரறலளழவஶஷஸஹௐ௦௧௨௩௪௫௬௭௮௯௰௱௲అఆఇఈఉఊఋఌఎఏఐఒఓఔకఖగఘఙచఛజఝఞటఠడఢణతథదధనపఫబభమయరఱలళఴవశషసహఽౘౙౚౠౡ౦౧౨౩౪౫౬౭౮౯౸౹౺౻౼౽౾ಀಅಆಇಈಉಊಋಌಎಏಐಒಓಔಕಖಗಘಙಚಛಜಝಞಟಠಡಢಣತಥದಧನಪಫಬಭಮಯರಱಲಳವಶಷಸಹಽೞೠೡ೦೧೨೩೪೫೬೭೮೯ೱೲഅആഇഈഉഊഋഌഎഏഐഒഓഔകഖഗഘങചഛജഝഞടഠഡഢണതഥദധനഩപഫബഭമയരറലളഴവശഷസഹഺഽൎൔൕൖ൘൙൚൛൜൝൞ൟൠൡ൦൧൨൩൪൫൬൭൮൯൰൱൲൳൴൵൶൷൸ൺൻർൽൾൿඅආඇඈඉඊඋඌඍඎඏඐඑඒඓඔඕඖකඛගඝඞඟචඡජඣඤඥඦටඨඩඪණඬතථදධනඳපඵබභමඹයරලවශෂසහළෆ෦෧෨෩෪෫෬෭෮෯กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะาเแโใไๅ๐๑๒๓๔๕๖๗๘๙ກຂຄງຈຊຍດຕຖທນບປຜຝພຟມຢຣລວສຫອຮຯະາຽເແໂໃໄ໐໑໒໓໔໕໖໗໘໙ໞໟༀ༠༡༢༣༤༥༦༧༨༩༪༫༬༭༮༯༰༱༲༳ཀཁགངཅཆཇཉཊཋཌཎཏཐདནཔཕབམཙཚཛཝཞཟའཡརལཤཥསཧཨཪཫཬྈྉྊྋྌကခဂဃငစဆဇဈဉညဋဌဍဎဏတထဒဓနပဖဗဘမယရလဝသဟဠအဢဣဤဥဧဨဩဪဿ၀၁၂၃၄၅၆၇၈၉ၐၑၒၓၔၕ"]; 41 | this.padChars.default = [..."01234567"]; 42 | 43 | this.padCharAmount = 8; 44 | this.hasSignedMode = true; 45 | this.littleEndian = false; 46 | this.nonASCII = true; 47 | 48 | // apply user settings 49 | this.utils.validateArgs(args, true); 50 | } 51 | 52 | 53 | /** 54 | * BaseEx Base2048 Encoder. 55 | * @param {*} input - Input according to the used byte converter. 56 | * @param {...str} [args] - Converter settings. 57 | * @returns {string} - Base2048 encoded string. 58 | */ 59 | encode(input, ...args) { 60 | 61 | const settings = this.utils.validateArgs(args); 62 | let inputBytes = this.utils.inputHandler.toBytes(input, settings).at(0); 63 | 64 | const charset = this.charsets[settings.version]; 65 | const padChars = this.padChars[settings.version]; 66 | 67 | let output = ""; 68 | let z = 0; 69 | let numZBits = 0; 70 | 71 | inputBytes.forEach(uint8 => { 72 | 73 | for (let i=this.converter.bsDec-1; i>=0; i--) { 74 | 75 | z = (z << 1) + ((uint8 >> i) & 1); 76 | numZBits++; 77 | 78 | if (numZBits === this.converter.bsEnc) { 79 | output += charset.at(z); 80 | z = 0 81 | numZBits = 0 82 | } 83 | } 84 | }); 85 | 86 | if (numZBits !== 0) { 87 | 88 | let bitCount; 89 | let isPadding; 90 | 91 | if (numZBits <= this.converter.bsEncPad) { 92 | bitCount = this.converter.bsEncPad; 93 | isPadding = true; 94 | } else { 95 | bitCount = this.converter.bsEnc 96 | isPadding = false; 97 | } 98 | 99 | while (numZBits !== bitCount) { 100 | z = (z << 1) + 1 101 | numZBits++ 102 | if (numZBits > this.converter.bsEnc) { 103 | throw new Error("Cannot process input. This is a bug!"); 104 | } 105 | } 106 | 107 | if (isPadding) { 108 | output += padChars.at(z); 109 | } else { 110 | output += charset.at(z); 111 | } 112 | } 113 | 114 | return this.utils.wrapOutput(output, settings.options.lineWrap); 115 | } 116 | 117 | 118 | /** 119 | * BaseEx Base2048 Decoder. 120 | * @param {string} input - Base2048/Hex String. 121 | * @param {...any} [args] - Converter settings. 122 | * @returns {*} - Output according to converter settings. 123 | */ 124 | decode(input, ...args) { 125 | 126 | // apply settings 127 | const settings = this.utils.validateArgs(args); 128 | 129 | // ensure a string input 130 | input = this.utils.normalizeInput(input); 131 | const inArray = [...input]; 132 | 133 | const charset = this.charsets[settings.version]; 134 | const padChars = this.padChars[settings.version]; 135 | 136 | const byteArray = new Array(); 137 | let uint8 = 0; 138 | let numUint8Bits = 0; 139 | 140 | inArray.forEach((c, i) => { 141 | 142 | let numZBits; 143 | let z = charset.indexOf(c); 144 | if (z > -1) { 145 | numZBits = this.converter.bsEnc; 146 | } else { 147 | z = padChars.indexOf(c); 148 | 149 | if (z > -1) { 150 | if (i+1 !== inArray.length) { 151 | throw new DecodingError(null, `Secondary character found before end of input, index: ${i}`); 152 | } 153 | 154 | numZBits = this.converter.bsEncPad; 155 | } 156 | 157 | else if (settings.integrity) { 158 | throw new DecodingError(c); 159 | } 160 | } 161 | 162 | // Take most significant bit first 163 | for (let j=numZBits-1; j>=0; j--) { 164 | 165 | uint8 = (uint8 << 1) + ((z >> j) & 1); 166 | numUint8Bits++ 167 | 168 | if (numUint8Bits === this.converter.bsDec) { 169 | byteArray.push(uint8); 170 | uint8 = 0; 171 | numUint8Bits = 0; 172 | } 173 | } 174 | }); 175 | 176 | return this.utils.outputHandler.compile( 177 | Uint8Array.from(byteArray), 178 | settings.outputType 179 | ); 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /src/converters/base-32.js: -------------------------------------------------------------------------------- 1 | /** 2 | * [BaseEx|Base32 Converter]{@link https://github.com/UmamiAppearance/BaseExJS/blob/main/src/converters/base-32.js} 3 | * 4 | * @version 0.8.1 5 | * @author UmamiAppearance [mail@umamiappearance.eu] 6 | * @license MIT 7 | */ 8 | 9 | import { BaseConverter, BaseTemplate } from "../core.js"; 10 | 11 | /** 12 | * BaseEx Base 32 Converter. 13 | * ------------------------ 14 | * 15 | * This is a base32 converter. Various input can be 16 | * converted to a base32 string or a base32 string 17 | * can be decoded into various formats. It is possible 18 | * to convert in both signed and unsigned mode in little 19 | * and big endian byte order. 20 | * 21 | * Available charsets are: 22 | * - RFC 3548 23 | * - RFC 4648 24 | * - crockford 25 | * - zbase32 26 | */ 27 | export default class Base32 extends BaseTemplate { 28 | 29 | /** 30 | * BaseEx Base32 Constructor. 31 | * @param {...string} [args] - Converter settings. 32 | */ 33 | constructor(...args) { 34 | super(); 35 | this.converter = new BaseConverter(32, 5, 8); 36 | 37 | // charsets 38 | this.charsets.crockford = [ ..."0123456789abcdefghjkmnpqrstvwxyz" ]; 39 | this.padChars.crockford = ["="], 40 | 41 | this.charsets.rfc3548 = [..."abcdefghijklmnopqrstuvwxyz234567"]; 42 | this.padChars.rfc3548 = ["="]; 43 | 44 | this.charsets.rfc4648 = [..."0123456789abcdefghijklmnopqrstuv"]; 45 | this.padChars.rfc4648 = ["="]; 46 | 47 | this.charsets.zbase32 = [..."ybndrfg8ejkmcpqxot1uwisza345h769"]; 48 | this.padChars.zbase32 = ["="]; 49 | 50 | // predefined settings 51 | this.padCharAmount = 1; 52 | this.hasSignedMode = true; 53 | this.version = "rfc4648"; 54 | 55 | // mutable extra args 56 | this.isMutable.littleEndian = true; 57 | this.isMutable.padding = true; 58 | this.isMutable.signed = true; 59 | this.isMutable.upper = true; 60 | 61 | // apply user settings 62 | this.utils.validateArgs(args, true); 63 | this.padding = (/rfc3548|rfc4648/).test(this.version); 64 | this.upper = this.version === "crockford"; 65 | } 66 | 67 | 68 | /** 69 | * BaseEx Base32 Encoder. 70 | * @param {*} input - Input according to the used byte converter. 71 | * @param {...str} [args] - Converter settings. 72 | * @returns {string} - Base32 encoded string. 73 | */ 74 | encode(input, ...args) { 75 | 76 | const applyPadding = ({ output, settings, zeroPadding }) => { 77 | 78 | if (!settings.littleEndian) { 79 | // Cut of redundant chars and append padding if set 80 | if (zeroPadding) { 81 | const padValue = this.converter.padBytes(zeroPadding); 82 | const padChar = this.padChars[settings.version].at(0); 83 | output = output.slice(0, -padValue); 84 | if (settings.padding) { 85 | output = output.concat(padChar.repeat(padValue)); 86 | } 87 | } 88 | } 89 | 90 | return output; 91 | } 92 | 93 | return super.encode(input, null, applyPadding, ...args); 94 | } 95 | 96 | 97 | /** 98 | * BaseEx Base32 Decoder. 99 | * @param {string} input - Base32 String. 100 | * @param {...any} [args] - Converter settings. 101 | * @returns {*} - Output according to converter settings. 102 | */ 103 | decode(input, ...args) { 104 | return super.decode(input, null, null, false, ...args); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/converters/base-58.js: -------------------------------------------------------------------------------- 1 | /** 2 | * [BaseEx|Base58 Converter]{@link https://github.com/UmamiAppearance/BaseExJS/blob/main/src/converters/base-58.js} 3 | * 4 | * @version 0.8.1 5 | * @author UmamiAppearance [mail@umamiappearance.eu] 6 | * @license MIT 7 | */ 8 | 9 | import { BaseConverter, BaseTemplate } from "../core.js"; 10 | 11 | /** 12 | * BaseEx Base 58 Converter. 13 | * ------------------------ 14 | * 15 | * This is a base58 converter. Various input can be 16 | * converted to a base58 string or a base58 string 17 | * can be decoded into various formats. 18 | * 19 | * Available charsets are: 20 | * - default 21 | * - bitcoin 22 | * - flickr 23 | */ 24 | export default class Base58 extends BaseTemplate{ 25 | 26 | /** 27 | * BaseEx Base58 Constructor. 28 | * @param {...string} [args] - Converter settings. 29 | */ 30 | constructor(...args) { 31 | super(); 32 | this.converter = new BaseConverter(58, 0, 0); 33 | 34 | // charsets 35 | this.charsets.default = [..."123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"]; 36 | Object.defineProperty(this.padChars, "default", { 37 | get: () => [ this.charsets.default.at(0) ] 38 | }); 39 | 40 | this.charsets.bitcoin = [..."123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"]; 41 | Object.defineProperty(this.padChars, "bitcoin", { 42 | get: () => [ this.charsets.bitcoin.at(0) ] 43 | }); 44 | 45 | this.charsets.flickr = [..."123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"]; 46 | Object.defineProperty(this.padChars, "flickr", { 47 | get: () => [ this.charsets.flickr.at(0) ] 48 | }); 49 | 50 | 51 | // predefined settings 52 | this.padding = true; 53 | this.version = "bitcoin"; 54 | 55 | // mutable extra args 56 | this.isMutable.padding = true; 57 | this.isMutable.signed = true; 58 | 59 | // apply user settings 60 | this.utils.validateArgs(args, true); 61 | } 62 | 63 | 64 | /** 65 | * BaseEx Base58 Encoder. 66 | * @param {*} input - Input according to the used byte converter. 67 | * @param {...str} [args] - Converter settings. 68 | * @returns {string} - Base58 encoded string. 69 | */ 70 | encode(input, ...args) { 71 | 72 | const applyPadding = ({ inputBytes, output, settings, type }) => { 73 | 74 | if (settings.padding && type !== "int") { 75 | 76 | // Count all null bytes at the start of the array 77 | // stop if a byte with a value is reached. If it goes 78 | // all the way through it, reset index and stop. 79 | let i = 0; 80 | const end = inputBytes.length; 81 | 82 | // pad char is always! the first char in the set 83 | const padChar = this.charsets[settings.version].at(0); 84 | 85 | // only proceed if input has a length at all 86 | if (end) { 87 | while (!inputBytes[i]) { 88 | i++; 89 | if (i === end) { 90 | i = 0; 91 | break; 92 | } 93 | } 94 | 95 | // The value for zero padding is the index of the 96 | // first byte with a value plus one. 97 | const zeroPadding = i; 98 | 99 | // Set a one for every leading null byte 100 | if (zeroPadding) { 101 | output = (padChar.repeat(zeroPadding)).concat(output); 102 | } 103 | } 104 | } 105 | 106 | return output; 107 | } 108 | 109 | return super.encode(input, null, applyPadding, ...args); 110 | } 111 | 112 | 113 | /** 114 | * BaseEx Base58 Decoder. 115 | * @param {string} input - Base58 String. 116 | * @param {...any} [args] - Converter settings. 117 | * @returns {*} - Output according to converter settings. 118 | */ 119 | decode(input, ...args) { 120 | 121 | // post decoding function 122 | const applyPadding = ({ input, output, settings }) => { 123 | 124 | // pad char is always! the first char in the set 125 | const padChar = this.charsets[settings.version].at(0); 126 | 127 | if (settings.padding && input.length > 1) { 128 | 129 | // Count leading padding (char should be 1) 130 | let i = 0; 131 | while (input[i] === padChar) { 132 | i++; 133 | } 134 | 135 | // The counter becomes the zero padding value 136 | const zeroPadding = i; 137 | 138 | // Create a new Uint8Array with leading null bytes 139 | // with the amount of zeroPadding 140 | if (zeroPadding) { 141 | output = Uint8Array.from([...new Array(zeroPadding).fill(0), ...output]); 142 | } 143 | 144 | } 145 | 146 | return output; 147 | } 148 | 149 | return super.decode(input, null, applyPadding, false, ...args); 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /src/converters/base-64.js: -------------------------------------------------------------------------------- 1 | /** 2 | * [BaseEx|Base64 Converter]{@link https://github.com/UmamiAppearance/BaseExJS/blob/main/src/converters/base-64.js} 3 | * 4 | * @version 0.8.1 5 | * @author UmamiAppearance [mail@umamiappearance.eu] 6 | * @license MIT 7 | */ 8 | 9 | import { BaseConverter, BaseTemplate } from "../core.js"; 10 | 11 | /** 12 | * BaseEx Base 64 Converter. 13 | * ------------------------ 14 | * 15 | * This is a base64 converter. Various input can be 16 | * converted to a base64 string or a base64 string 17 | * can be decoded into various formats. 18 | * 19 | * Available charsets are: 20 | * - default 21 | * - urlsafe 22 | */ 23 | export default class Base64 extends BaseTemplate { 24 | 25 | /**this.padChars. 26 | * BaseEx Base64 Constructor. 27 | * @param {...string} [args] - Converter settings. 28 | */ 29 | constructor(...args) { 30 | super(); 31 | this.converter = new BaseConverter(64, 3, 4); 32 | 33 | // charsets 34 | this.charsets.default = [..."ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"]; 35 | this.padChars.default = ["="]; 36 | 37 | this.charsets.urlsafe = this.charsets.default.slice(0, -2).concat(["-", "_"]); 38 | this.padChars.urlsafe = ["="]; 39 | 40 | 41 | // predefined settings 42 | this.padCharAmount = 1; 43 | this.padding = true; 44 | 45 | // mutable extra args 46 | this.isMutable.padding = true; 47 | 48 | // apply user settings 49 | this.utils.validateArgs(args, true); 50 | } 51 | 52 | 53 | /** 54 | * BaseEx Base64 Encoder. 55 | * @param {*} input - Input according to the used byte converter. 56 | * @param {...str} [args] - Converter settings. 57 | * @returns {string} - Base64 encoded string. 58 | */ 59 | encode(input, ...args) { 60 | 61 | const applyPadding = ({ output, settings, zeroPadding }) => { 62 | 63 | // Cut of redundant chars and append padding if set 64 | if (zeroPadding) { 65 | const padValue = this.converter.padBytes(zeroPadding); 66 | const padChar = this.padChars[settings.version].at(0); 67 | output = output.slice(0, -padValue); 68 | if (settings.padding) { 69 | output = output.concat(padChar.repeat(padValue)); 70 | } 71 | } 72 | 73 | return output; 74 | } 75 | 76 | return super.encode(input, null, applyPadding, ...args); 77 | } 78 | 79 | 80 | /** 81 | * BaseEx Base64 Decoder. 82 | * @param {string} input - Base64 String. 83 | * @param {...any} [args] - Converter settings. 84 | * @returns {*} - Output according to converter settings. 85 | */ 86 | decode(input, ...args) { 87 | return super.decode(input, null, null, false, ...args); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/converters/base-85.js: -------------------------------------------------------------------------------- 1 | /** 2 | * [BaseEx|Base85 Converter]{@link https://github.com/UmamiAppearance/BaseExJS/blob/main/src/converters/base-85.js} 3 | * 4 | * @version 0.8.1 5 | * @author UmamiAppearance [mail@umamiappearance.eu] 6 | * @license MIT 7 | */ 8 | 9 | import { BaseConverter, BaseTemplate } from "../core.js"; 10 | 11 | /** 12 | * BaseEx Base 85 Converter. 13 | * ------------------------ 14 | * 15 | * This is a base85 converter. Various input can be 16 | * converted to a base85 string or a base85 string 17 | * can be decoded into various formats. 18 | * 19 | * Available charsets are: 20 | * - adobe 21 | * - ascii85 22 | * - rfc1924 23 | * - z85 24 | * 25 | * Adobe and ascii85 are the basically the same. 26 | * Adobe will produce the same output, apart from 27 | * the <~wrapping~>. 28 | * 29 | * Z85 is an important variant, because of the 30 | * more interpreter-friendly character set. 31 | * 32 | * The RFC 1924 version is a hybrid. It is not using 33 | * the mandatory 128 bit calculation. Instead only 34 | * the charset is getting used. 35 | */ 36 | export default class Base85 extends BaseTemplate { 37 | 38 | /** 39 | * BaseEx Base85 Constructor. 40 | * @param {...string} [args] - Converter settings. 41 | */ 42 | constructor(...args) { 43 | super(); 44 | this.converter = new BaseConverter(85, 4, 5, 84); 45 | 46 | // charsets 47 | this.charsets.adobe = [..."!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstu"]; 48 | this.charsets.ascii85 = this.charsets.adobe.slice(); 49 | this.charsets.rfc1924 = [..."0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~"]; 50 | this.charsets.z85 = [..."0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-:+=^!/*?&<>()[]{}@%$#"]; 51 | 52 | // predefined settings 53 | this.version = "ascii85"; 54 | 55 | // apply user settings 56 | this.utils.validateArgs(args, true); 57 | } 58 | 59 | 60 | /** 61 | * BaseEx Base85 Encoder. 62 | * @param {*} input - Input according to the used byte converter. 63 | * @param {...str} [args] - Converter settings. 64 | * @returns {string} - Base85 encoded string. 65 | */ 66 | encode(input, ...args) { 67 | 68 | // Replace five consecutive "!" with a "z" 69 | // for adobe and ascii85 70 | const replacerFN = (settings) => { 71 | let replacer; 72 | if (settings.version.match(/adobe|ascii85/)) { 73 | replacer = (frame, zPad) => (!zPad && frame === "!!!!!") ? "z" : frame; 74 | } 75 | return replacer; 76 | } 77 | 78 | // Remove padded values and add a frame for the 79 | // adobe variant 80 | const framesAndPadding = ({ output, settings, zeroPadding }) => { 81 | 82 | // Cut of redundant chars 83 | if (zeroPadding) { 84 | const padValue = this.converter.padBytes(zeroPadding); 85 | output = output.slice(0, -padValue); 86 | } 87 | 88 | // Adobes variant gets its <~framing~> 89 | if (settings.version === "adobe") { 90 | output = `<~${output}~>`; 91 | } 92 | 93 | return output; 94 | } 95 | 96 | return super.encode(input, replacerFN, framesAndPadding, ...args); 97 | } 98 | 99 | 100 | /** 101 | * BaseEx Base85 Decoder. 102 | * @param {string} input - Base85 String. 103 | * @param {...any} [args] - Converter settings. 104 | * @returns {*} - Output according to converter settings. 105 | */ 106 | decode(input, ...args) { 107 | 108 | const prepareInput = ({ input, settings }) => { 109 | 110 | // For default ascii85 convert "z" back to "!!!!!" 111 | // Remove the adobe <~frame~> 112 | if (settings.version.match(/adobe|ascii85/)) { 113 | input = input.replace(/z/g, "!!!!!"); 114 | if (settings.version === "adobe") { 115 | input = input.replace(/^<~|~>$/g, ""); 116 | } 117 | } 118 | 119 | return input 120 | } 121 | 122 | return super.decode(input, prepareInput, null, false, ...args); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/converters/base-91.js: -------------------------------------------------------------------------------- 1 | /** 2 | * [BaseEx|Base91 Converter]{@link https://github.com/UmamiAppearance/BaseExJS/blob/main/src/converters/base-91.js} 3 | * 4 | * @version 0.8.1 5 | * @author UmamiAppearance [mail@umamiappearance.eu] 6 | * @license MIT AND BSD-3-Clause (Base91, Copyright (c) 2000-2006 Joachim Henke) 7 | */ 8 | 9 | import { BaseTemplate } from "../core.js"; 10 | import { DecodingError } from "../utils.js"; 11 | 12 | /** 13 | * BaseEx Base 91 Converter. 14 | * ------------------------ 15 | * 16 | * This is a base91 converter. Various input can be 17 | * converted to a base91 string or a base91 string 18 | * can be decoded into various formats. 19 | * 20 | * It is an implementation of Joachim Henkes method 21 | * to encode binary data as ASCII characters -> basE91 22 | * http://base91.sourceforge.net/ 23 | * 24 | * As this method requires to split the bytes, the 25 | * default conversion class "BaseConverter" is not 26 | * getting used in this case. 27 | */ 28 | export default class Base91 extends BaseTemplate { 29 | 30 | /** 31 | * BaseEx basE91 Constructor. 32 | * @param {...string} [args] - Converter settings. 33 | */ 34 | constructor(...args) { 35 | super(); 36 | 37 | // converter (properties only) 38 | this.converter = { 39 | radix: 91, 40 | bsEnc: 0, 41 | bsDec: 0 42 | } 43 | 44 | // charsets 45 | this.charsets.default = [..."ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!#$%&()*+,./:;<=>?@[]^_`{|}~\""]; 46 | this.version = "default"; 47 | 48 | // apply user settings 49 | this.utils.validateArgs(args, true); 50 | } 51 | 52 | 53 | /** 54 | * BaseEx basE91 Encoder. 55 | * @param {*} input - Input according to the used byte converter. 56 | * @param {...str} [args] - Converter settings. 57 | * @returns {string} - basE91 encoded string. 58 | */ 59 | encode(input, ...args) { 60 | 61 | // argument validation and input settings 62 | const settings = this.utils.validateArgs(args); 63 | const inputBytes = this.utils.inputHandler.toBytes(input, settings)[0]; 64 | 65 | // As this base representation splits the bytes 66 | // the read bits need to be stores somewhere. 67 | // This is done in "bitCount". "n", similar to 68 | // other solutions here, holds the integer which 69 | // is converted to the desired base. 70 | 71 | let bitCount = 0; 72 | let n = 0; 73 | let output = ""; 74 | 75 | const charset = this.charsets[settings.version]; 76 | 77 | inputBytes.forEach(byte => { 78 | //n = n + byte * 2^bitcount; 79 | n += (byte << bitCount); 80 | 81 | // Add 8 bits forEach byte 82 | bitCount += 8; 83 | 84 | // If the count exceeds 13 bits, base convert the 85 | // current frame. 86 | 87 | if (bitCount > 13) { 88 | 89 | // Set bit amount "count" to 13, check the 90 | // remainder of n % 2^13. If it is 88 or 91 | // lower. Take one more bit from the stream 92 | // and calculate the remainder for n % 2^14. 93 | 94 | let count = 13; 95 | let rN = n % 8192; 96 | 97 | if (rN < 89) { 98 | count = 14; 99 | rN = n % 16384; 100 | } 101 | 102 | // Remove 13 or 14 bits from the integer, 103 | // decrease the bitCount by the same amount. 104 | n >>= count; 105 | bitCount -= count; 106 | 107 | // Calculate quotient and remainder from 108 | // the before calculated remainder of n 109 | // -> "rN" 110 | let q, r; 111 | [q, r] = this.#divmod(rN, 91); 112 | 113 | // Lookup the corresponding characters for 114 | // "r" and "q" in the set, append it to the 115 | // output string. 116 | output = `${output}${charset[r]}${charset[q]}`; 117 | } 118 | }); 119 | 120 | // If the bitCount is not zero at the end, 121 | // calculate quotient and remainder of 91 122 | // once more. 123 | if (bitCount) { 124 | let q, r; 125 | [q, r] = this.#divmod(n, 91); 126 | 127 | // The remainder is concatenated in any case 128 | output = output.concat(charset[r]); 129 | 130 | // The quotient is also appended, but only 131 | // if the bitCount still has the size of a byte 132 | // or n can still represent 91 conditions. 133 | if (bitCount > 7 || n > 90) { 134 | output = output.concat(charset[q]); 135 | } 136 | } 137 | 138 | return this.utils.wrapOutput(output, settings.options.lineWrap); 139 | } 140 | 141 | 142 | /** 143 | * BaseEx basE91 Decoder. 144 | * @param {string} input - basE91 String. 145 | * @param {...any} [args] - Converter settings. 146 | * @returns {*} - Output according to converter settings. 147 | */ 148 | decode(input, ...args) { 149 | 150 | // Argument validation and output settings 151 | const settings = this.utils.validateArgs(args); 152 | const charset = this.charsets[settings.version]; 153 | 154 | // Make it a string, whatever goes in 155 | input = this.utils.normalizeInput(input); 156 | let inArray = [...input]; 157 | 158 | // remove unwanted characters if integrity is false 159 | if (!settings.integrity) { 160 | inArray = inArray.filter(c => charset.includes(c)); 161 | } 162 | 163 | 164 | let l = inArray.length; 165 | 166 | // For starters leave the last char behind 167 | // if the length of the input string is odd. 168 | 169 | let odd = false; 170 | if (l % 2) { 171 | odd = true; 172 | l--; 173 | } 174 | 175 | // Set again integer n for base conversion. 176 | // Also initialize a bitCount(er) 177 | 178 | let n = 0; 179 | let bitCount = 0; 180 | 181 | // Initialize an ordinary array 182 | const b256Array = new Array(); 183 | 184 | // Walk through the string in steps of two 185 | // (aka collect remainder- and quotient-pairs) 186 | for (let i=0; i 88) ? 13 : 14; 202 | 203 | // calculate back the individual bytes (base256) 204 | do { 205 | b256Array.push(n % 256); 206 | n >>= 8; 207 | bitCount -= 8; 208 | } while (bitCount > 7); 209 | } 210 | 211 | // Calculate the last byte if the input is odd 212 | // and add it 213 | if (odd) { 214 | const lastChar = inArray.at(l); 215 | const rN = charset.indexOf(lastChar); 216 | b256Array.push(((rN << bitCount) + n) % 256); 217 | } 218 | 219 | const output = Uint8Array.from(b256Array); 220 | 221 | // Return the output 222 | return this.utils.outputHandler.compile(output, settings.outputType); 223 | } 224 | 225 | 226 | /** 227 | * Divmod Function. 228 | * @param {*} x - number 1 229 | * @param {*} y - number 2 230 | * @returns {number} Modulo y of x 231 | */ 232 | #divmod (x, y) { 233 | return [Math.floor(x/y), x%y]; 234 | } 235 | } 236 | -------------------------------------------------------------------------------- /src/converters/base-phi.js: -------------------------------------------------------------------------------- 1 | /** 2 | * [BaseEx|BasePhi Converter]{@link https://github.com/UmamiAppearance/BaseExJS/blob/main/src/converters/base-phi.js} 3 | * 4 | * @version 0.8.1 5 | * @author UmamiAppearance [mail@umamiappearance.eu] 6 | * @license MIT 7 | */ 8 | 9 | import { BaseConverter, BaseTemplate } from "../core.js"; 10 | import Big from "../../lib/big.js/big.min.js"; 11 | import { DecodingError } from "../utils.js"; 12 | 13 | /** 14 | * BaseEx Base Phi Converter. 15 | * ------------------------ 16 | * 17 | * This is a base phi converter. Various input can be 18 | * converted to a base phi string or a base phi string 19 | * can be decoded into various formats. 20 | * 21 | */ 22 | export default class BasePhi extends BaseTemplate { 23 | 24 | #Phi = Big("1.618033988749894848204586834365638117720309179805762862135448622705260462818902449707207204189391137484754088075386891752"); 25 | 26 | /** 27 | * BaseEx basE91 Constructor. 28 | * @param {...string} [args] - Converter settings. 29 | */ 30 | constructor(...args) { 31 | super(); 32 | 33 | // converter (properties only) 34 | this.converter = { 35 | radix: 2, // radix is Phi, but the normalized representation allows two chars 36 | bsEnc: 0, 37 | bsDec: 0 38 | } 39 | 40 | // base10 converter to have always have a numerical input 41 | this.b10 = new BaseConverter(10, 0, 0); 42 | 43 | // charsets 44 | this.charsets.default = ["0", "1"]; 45 | 46 | this.version = "default"; 47 | this.signed = true; 48 | this.hasDecimalMode = true; 49 | 50 | // apply user settings 51 | this.utils.validateArgs(args, true); 52 | } 53 | 54 | 55 | /** 56 | * BaseEx BasePhi Encoder. 57 | * @param {*} input - Input according to the used byte converter. 58 | * @param {...string} [args] - Converter settings. 59 | * @returns {string} - BasePhi encoded string. 60 | */ 61 | encode(input, ...args) { 62 | 63 | // argument validation and input settings 64 | const settings = this.utils.validateArgs(args); 65 | const charset = this.charsets[settings.version]; 66 | 67 | let inputBytes; 68 | let negative; 69 | let n; 70 | let output = ""; 71 | 72 | // Base Phi allows direct encoding of rational 73 | // and irrational numbers, which can be enabled 74 | // by using the special type "decimal". Input 75 | // type must be "Number" for this mode. 76 | if (settings.decimalMode) { 77 | if (Number.isFinite(input)) { 78 | if (input < 0) { 79 | negative = true; 80 | n = Big(-input); 81 | } else { 82 | negative = false; 83 | n = Big(input); 84 | } 85 | } 86 | 87 | else { 88 | throw new TypeError("When running the converter in decimal-mode, only input of type 'Number' is allowed.") 89 | } 90 | } 91 | 92 | // Every other type first converts the byte representation 93 | // of the input to base 10. 94 | else { 95 | [ inputBytes, negative, ] = this.utils.inputHandler.toBytes(input, settings); 96 | n = Big( 97 | this.b10.encode(inputBytes, null, settings.littleEndian)[0] 98 | ); 99 | } 100 | 101 | // if "n" if 0 or 1 stop here and return 0 or 1 (according to the charset) 102 | if (n.eq(0) || n.eq(1)) { 103 | output = charset[n.toNumber()]; 104 | if (negative) { 105 | output = `-${output}`; 106 | } 107 | return output; 108 | } 109 | 110 | // create two arrays to store all exponents 111 | const exponents = []; 112 | const decExponents = []; 113 | 114 | 115 | // The very first step is to find the highest exponent 116 | // of Phi which fits into "n" (the rounded highest exponent 117 | // is also the highest Lucas number which fits into "n") 118 | // To find the highest fitting exponent start with 119 | // Phi^0 (1) and Phi^1 (Phi). 120 | 121 | let last = Big(1); 122 | let cur = this.#Phi; 123 | let exp = 0; 124 | 125 | // Now add the result with the last higher value "cur", 126 | // util "cur" is bigger than "n" 127 | while (cur.lt(n)) { 128 | [ last, cur ] = this.#nextPhiExp(last, cur); 129 | exp++; 130 | } 131 | 132 | /** 133 | * Recursive reduction function for "n". Finds the largest 134 | * fitting exponent of Phi (Lucas index), stores that index 135 | * in the exponent arrays and reduces "n" by the current exponents 136 | * power. 137 | * Once started, it calls itself until "n" is zero. 138 | * @param {Object} cur - Current result of Phi^exp as a Big.js object. 139 | * @param {Object} prev - Previous result of Phi^exp as a Big.js object. 140 | * @param {number} exp - Exponent of Phi/Lucas index. 141 | */ 142 | const reduceN = (cur, prev, exp) => { 143 | 144 | // Due to the high floating point precision "n" should 145 | // be exactly zero, but if not, an approximation is 146 | // sufficient. 147 | if (this.#approxNull(n)) return; 148 | 149 | // Reduce the exponents of Phi until it power fits into "n" 150 | while (cur.gt(n)) { 151 | [ cur, prev ] = this.#prevPhiExp(cur, prev); 152 | 153 | // if "cur" gets negative return immediately 154 | // prevent an infinite loop 155 | if (cur.lte(0)) { 156 | console.warn("Could not find an exact base-phi representation. Value is approximated."); 157 | return; 158 | } 159 | exp--; 160 | } 161 | 162 | // Store the exponents 163 | if (exp > -1) { 164 | exponents.unshift(exp); 165 | } else { 166 | decExponents.push(exp); 167 | } 168 | 169 | // Reduce "n" 170 | n = n.minus(cur); 171 | 172 | reduceN(cur, prev, exp); 173 | } 174 | 175 | // Initial call of the reduction function 176 | reduceN(last, cur, exp); 177 | 178 | 179 | // Create a BasePhi string by setting a "1" at every 180 | // index stored in the "exponent" array. for every 181 | // number between two indices a zero is added. 182 | exp = 0; 183 | exponents.forEach(nExp => { 184 | while (exp < nExp) { 185 | output = `${charset[0]}${output}`; 186 | exp++; 187 | } 188 | output = `${charset[1]}${output}`; 189 | exp++; 190 | }); 191 | 192 | // Add a decimal point 193 | if (!output) { 194 | output = "0."; 195 | } else { 196 | output += "."; 197 | } 198 | 199 | // Proceed with the decimal exponents 200 | exp = -1; 201 | decExponents.forEach(nExp => { 202 | while (exp > nExp) { 203 | output += charset[0]; 204 | exp--; 205 | } 206 | output += charset[1]; 207 | exp--; 208 | }); 209 | 210 | // Add a "-" if the input is negative. 211 | if (negative) { 212 | output = `-${output}`; 213 | } 214 | 215 | return output; 216 | } 217 | 218 | 219 | /** 220 | * BaseEx Base Phi Decoder. 221 | * @param {string} input - Base Phi String. 222 | * @param {...any} [args] - Converter settings. 223 | * @returns {*} - Output according to converter settings. 224 | */ 225 | decode(input, ...args) { 226 | 227 | // Argument validation and output settings 228 | const settings = this.utils.validateArgs(args); 229 | const charset = this.charsets[settings.version]; 230 | 231 | let negative; 232 | [ input, negative ] = this.utils.extractSign( 233 | this.utils.normalizeInput(input) 234 | ); 235 | 236 | // remove unwanted characters if integrity is false 237 | if (!settings.integrity) { 238 | const testChars = [...charset, "."]; 239 | input = [...input].filter(c => testChars.includes(c)).join(""); 240 | } 241 | 242 | // Split the input String at the decimal sign 243 | // and initialize a big.js-object with value 0 244 | const inputSplit = input.split("."); 245 | if (settings.integrity && inputSplit.length > 2) { 246 | throw new DecodingError(null, "There are multiple decimal points in the input."); 247 | } 248 | 249 | const [ posExpStr, decExpStr ] = inputSplit; 250 | let n = Big(0); 251 | 252 | // Initialize two variables "last" and "cur" 253 | // for Phi^exp-1 and Phi^exp 254 | let last = this.#Phi.minus(1); 255 | let cur = Big(1); 256 | 257 | // Convert the left side of the input string 258 | // to an array of chars and reverse it. Raise 259 | // the exponent of Phi and its values until a 260 | // one is found in the array, if a "1" was found 261 | // add the value "cur" to number "n" (one can 262 | // also be another corresponding char of the set 263 | // which represents 1). 264 | [...posExpStr].reverse().forEach((char) => { 265 | const charIndex = charset.indexOf(char); 266 | if (charIndex === 1) { 267 | n = n.plus(cur); 268 | } else if (charIndex !== 0) { 269 | throw new DecodingError(char); 270 | } 271 | [ last, cur ] = this.#nextPhiExp(last, cur); 272 | }); 273 | 274 | // Now also add the values for the decimal places. 275 | if (decExpStr) { 276 | let prev = Big(1); 277 | cur = this.#Phi.minus(prev); 278 | 279 | [...decExpStr].forEach((char) => { 280 | const charIndex = charset.indexOf(char); 281 | if (charIndex === 1) { 282 | n = n.plus(cur); 283 | } else if (charIndex !== 0) { 284 | throw new DecodingError(char); 285 | } 286 | [ cur, prev ] = this.#prevPhiExp(cur, prev); 287 | }); 288 | } 289 | 290 | // If running in decimal mode return n as a Number 291 | if (settings.decimalMode) { 292 | return n.toNumber(); 293 | } 294 | 295 | // For every other case round "n" and turn it 296 | // into a string of an integer. 297 | n = n.round().toFixed(); 298 | 299 | // Use the base 10 decoder to get the byte 300 | // representation of "n". 301 | const output = this.b10.decode(n, [..."0123456789"], [], settings.integrity, settings.littleEndian); 302 | 303 | // Return the output according to the settings. 304 | return this.utils.outputHandler.compile(output, settings.outputType, settings.littleEndian, negative); 305 | } 306 | 307 | /** 308 | * Test if n is approximately zero. 309 | * @param {Object} n - Big.js Object. 310 | * @returns {Boolean} 311 | */ 312 | #approxNull(n) { 313 | return !(n.round(50) 314 | .abs() 315 | .toNumber() 316 | ); 317 | } 318 | 319 | /** 320 | * Get the results of of the following exponents of Phi 321 | * from the predecessors. 322 | * @param {Object} last - Phi^exp-1 as a big.js-object 323 | * @param {Object} cur - Phi^exp as a big.js-object 324 | * @returns {Object[]} - Array with Phi^exp and Phi^exp+1 325 | */ 326 | #nextPhiExp(last, cur) { 327 | return [ cur, last.plus(cur) ]; 328 | } 329 | 330 | /** 331 | * Get the results of of the previous exponents of Phi 332 | * from the predecessors. 333 | * @param {Object} cur - Phi^exp as a big.js-object 334 | * @param {Object} prev - Phi^exp-1 as a big.js-object 335 | * @returns {Object[]} - Array with Phi^exp-1 and Phi^exp 336 | */ 337 | #prevPhiExp(cur, prev) { 338 | return [ prev.minus(cur), cur ]; 339 | } 340 | } 341 | -------------------------------------------------------------------------------- /src/converters/byte-converter.js: -------------------------------------------------------------------------------- 1 | /** 2 | * [BaseEx|Byte Converter]{@link https://github.com/UmamiAppearance/BaseExJS/blob/main/src/converters/byte-converter.js} 3 | * 4 | * @version 0.8.1 5 | * @author UmamiAppearance [mail@umamiappearance.eu] 6 | * @license MIT 7 | */ 8 | 9 | import { SmartInput, SmartOutput } from "../io-handlers.js"; 10 | 11 | // Endianness of the system 12 | const LITTLE_ENDIAN = (() => { 13 | const testInt = new Uint16Array([1]); 14 | const byteRepresentation = new Uint8Array(testInt.buffer); 15 | return Boolean(byteRepresentation.at(0)); 16 | })(); 17 | 18 | 19 | /** 20 | * BaseEx Byte Converter. 21 | * --------------------- 22 | * 23 | * This is a byte converter. Various input can be 24 | * converted to a bytes or bytes can be decoded into 25 | * various formats. 26 | * 27 | * As en- and decoder were already available, for the 28 | * use of converting in- and output for the base 29 | * converters, this is just a little extra tool, which 30 | * was fast and easy to create. 31 | */ 32 | export default class ByteConverter { 33 | 34 | /** 35 | * BaseEx ByteConverter Constructor. 36 | * @param {...string} [args] - Converter settings. 37 | */ 38 | constructor(...args) { 39 | 40 | // predefined settings 41 | this.littleEndian = LITTLE_ENDIAN; 42 | this.numberMode = false; 43 | this.outputType = "buffer"; 44 | 45 | // simplified utils 46 | this.utils = { 47 | validateArgs: (args, initial=false) => { 48 | 49 | const parameters = { 50 | littleEndian: this.littleEndian, 51 | numberMode: this.numberMode, 52 | outputType: this.outputType, 53 | signed: false, 54 | } 55 | 56 | if (!args.length) { 57 | return parameters; 58 | } 59 | 60 | if (args.includes("number")) { 61 | args.splice(args.indexOf("number"), 1); 62 | parameters.numberMode = true; 63 | parameters.outputType = "float_n"; 64 | } 65 | 66 | const outTypes = SmartOutput.typeList.map(s => `'${s}'`).join(", "); 67 | 68 | args.forEach((arg) => { 69 | arg = String(arg).toLowerCase(); 70 | 71 | if (arg === "le") { 72 | parameters.littleEndian = true; 73 | } else if (arg === "be") { 74 | parameters.littleEndian = false; 75 | } else if (SmartOutput.typeList.includes(arg)) { 76 | parameters.outputType = arg; 77 | } else { 78 | throw new TypeError(`Invalid argument: '${arg}.\nValid arguments are:\n'le', 'be', ${outTypes}`); 79 | } 80 | }); 81 | 82 | if (initial) { 83 | for (const param in parameters) { 84 | this[param] = parameters[param]; 85 | } 86 | } 87 | 88 | return parameters; 89 | } 90 | } 91 | 92 | // apply user settings 93 | this.utils.validateArgs(args, true); 94 | } 95 | 96 | 97 | /** 98 | * BaseEx Byte Encoder. 99 | * @param {*} input - Almost any input. 100 | * @param {...str} [args] - Converter settings. 101 | * @returns {{ buffer: ArrayBufferLike; }} - Bytes of Input. 102 | */ 103 | encode(input, ...args) { 104 | const settings = this.utils.validateArgs(args); 105 | return SmartInput.toBytes(input, settings)[0]; 106 | } 107 | 108 | 109 | /** 110 | * BaseEx Byte Decoder. 111 | * @param {{ buffer: ArrayBufferLike; }} input - Bytes/Buffer/View 112 | * @param {...any} [args] - Converter settings. 113 | * @returns {*} - Output of requested type. 114 | */ 115 | decode(input, ...args) { 116 | const settings = this.utils.validateArgs(args); 117 | return SmartOutput.compile(input, settings.outputType, settings.littleEndian); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/converters/leb-128.js: -------------------------------------------------------------------------------- 1 | /** 2 | * [BaseEx|LEB128 Converter]{@link https://github.com/UmamiAppearance/BaseExJS/blob/main/src/converters/leb-128.js} 3 | * 4 | * @version 0.8.1 5 | * @author UmamiAppearance [mail@umamiappearance.eu] 6 | * @license MIT 7 | */ 8 | 9 | import { BaseConverter, BaseTemplate } from "../core.js"; 10 | import { BytesInput } from "../io-handlers.js"; 11 | 12 | /** 13 | * BaseEx Little Endian Base 128 Converter. 14 | * --------------------------------------- 15 | * 16 | * This is a leb128 converter. Various input can be 17 | * converted to a leb128 string or a leb128 string 18 | * can be decoded into various formats. 19 | * 20 | * There is no real charset available as the input is 21 | * getting converted to bytes. For having the chance 22 | * to store these bytes, there is a hexadecimal output 23 | * available. 24 | */ 25 | export default class LEB128 extends BaseTemplate { 26 | 27 | /** 28 | * BaseEx LEB128 Constructor. 29 | * @param {...string} [args] - Converter settings. 30 | */ 31 | constructor(...args) { 32 | // initialize base template without utils 33 | super(); 34 | 35 | // converters 36 | this.converter = new BaseConverter(10, 0, 0); 37 | this.hexlify = new BaseConverter(16, 1, 2); 38 | 39 | // charsets 40 | this.charsets.default = ""; 41 | this.charsets.hex = "" 42 | 43 | // predefined settings 44 | this.version = "default"; 45 | this.frozenCharsets = true; 46 | 47 | // predefined settings 48 | this.littleEndian = true; 49 | this.hasSignedMode = true; 50 | this.isMutable.signed = true; 51 | 52 | // apply user settings 53 | this.utils.validateArgs(args, true); 54 | } 55 | 56 | 57 | /** 58 | * BaseEx LEB128 Encoder. 59 | * @param {*} input - Input according to the used byte converter. 60 | * @param {...str} [args] - Converter settings. 61 | * @returns {{ buffer: ArrayBufferLike; }} - LEB128 encoded Unit8Array (or hex string of it). 62 | */ 63 | encode(input, ...args) { 64 | 65 | // argument validation and input settings 66 | const settings = this.utils.validateArgs(args); 67 | 68 | const signed = settings.signed; 69 | settings.signed = true; 70 | const [ inputBytes, negative, ] = this.utils.inputHandler.toBytes(input, settings); 71 | 72 | // Convert to BaseRadix string 73 | let base10 = this.converter.encode(inputBytes, null, settings.littleEndian)[0]; 74 | 75 | let n = BigInt(base10); 76 | let output = new Array(); 77 | 78 | if (negative) { 79 | if (!signed) { 80 | throw new TypeError("Negative values in unsigned mode are invalid."); 81 | } 82 | n = -n; 83 | } 84 | 85 | if (signed) { 86 | 87 | for (;;) { 88 | const byte = Number(n & 127n); 89 | n >>= 7n; 90 | if ((n == 0 && (byte & 64) == 0) || (n == -1 && (byte & 64) != 0)) { 91 | output.push(byte); 92 | break; 93 | } 94 | output.push(byte | 128); 95 | } 96 | } 97 | 98 | else { 99 | for (;;) { 100 | const byte = Number(n & 127n); 101 | n >>= 7n; 102 | if (n == 0) { 103 | output.push(byte) 104 | break; 105 | } 106 | output.push(byte | 128); 107 | } 108 | } 109 | 110 | const Uint8Output = Uint8Array.from(output); 111 | 112 | if (settings.version === "hex") { 113 | return this.hexlify.encode(Uint8Output, [..."0123456789abcdef"], false)[0]; 114 | } 115 | 116 | return Uint8Output; 117 | } 118 | 119 | 120 | /** 121 | * BaseEx LEB128 Decoder. 122 | * @param {{ buffer: ArrayBufferLike; }|string} input - LEB128-Bytes or String of Hex-Version. 123 | * @param {...any} [args] - Converter settings. 124 | * @returns {*} - Output according to converter settings. 125 | */ 126 | decode(input, ...args) { 127 | 128 | // Argument validation and output settings 129 | const settings = this.utils.validateArgs(args); 130 | 131 | if (settings.version === "hex") { 132 | input = this.hexlify.decode(this.utils.normalizeInput(input).toLowerCase(), [..."0123456789abcdef"], [], settings.integrity, false); 133 | } else if (typeof input.byteLength !== "undefined") { 134 | input = BytesInput.toBytes(input)[0]; 135 | } else { 136 | throw new TypeError("Input must be a bytes like object."); 137 | } 138 | 139 | if (input.length === 1 && !input[0]) { 140 | return this.utils.outputHandler.compile(new Uint8Array(1), settings.outputType, true); 141 | } 142 | 143 | input = Array.from(input); 144 | 145 | let n = 0n; 146 | let shiftVal = -7n; 147 | let byte; 148 | 149 | for (byte of input) { 150 | shiftVal += 7n; 151 | n += (BigInt(byte & 127) << shiftVal); 152 | } 153 | 154 | if (settings.signed && ((byte & 64) !== 0)) { 155 | n |= -(1n << shiftVal + 7n); 156 | } 157 | 158 | // Test for a negative sign 159 | let decimalNum, negative; 160 | [decimalNum, negative] = this.utils.extractSign(n.toString()); 161 | 162 | const output = this.converter.decode(decimalNum, [..."0123456789"], [], settings.integrity, true); 163 | 164 | // Return the output 165 | return this.utils.outputHandler.compile(output, settings.outputType, true, negative); 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /src/converters/simple-base.js: -------------------------------------------------------------------------------- 1 | /** 2 | * [BaseEx|SimpleBase Converter]{@link https://github.com/UmamiAppearance/BaseExJS/blob/main/src/converters/simple-base.js} 3 | * 4 | * @version 0.8.1 5 | * @author UmamiAppearance [mail@umamiappearance.eu] 6 | * @license MIT 7 | */ 8 | 9 | import { BaseConverter, BaseTemplate } from "../core.js"; 10 | 11 | 12 | /** 13 | * BaseEx SimpleBase Converter. 14 | * --------------------------- 15 | * SimpleBase provides the simple mathematical base 16 | * conversion as known from (n).toString(radix) and 17 | * parseInt(n, radix). 18 | * 19 | * The constructor needs a radix between 2-62 as the 20 | * first argument. In other regards it behaves pretty 21 | * much as any other converter. 22 | */ 23 | export default class SimpleBase extends BaseTemplate { 24 | 25 | /** 26 | * SimpleBase Constructor. 27 | * @param {number} radix - Radix between 2 and 62 28 | * @param {...any} args - Converter settings. 29 | */ 30 | constructor(radix, ...args) { 31 | super(); 32 | 33 | if (!radix || !Number.isInteger(radix) || radix < 2 || radix > 62) { 34 | throw new RangeError("Radix argument must be provided and has to be an integer between 2 and 62.") 35 | } 36 | this.converter = new BaseConverter(radix, 0, 0); 37 | 38 | 39 | // charsets 40 | this.charsets.default = [..."0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"].slice(0, radix); 41 | 42 | 43 | // predefined settings 44 | this.frozenCharsets = true; 45 | this.hasSignedMode = true; 46 | this.littleEndian = !(radix === 2 || radix === 16); 47 | this.signed = true; 48 | this.version = "default"; 49 | 50 | // list of allowed/disallowed args to change 51 | this.isMutable.littleEndian = true, 52 | this.isMutable.upper = radix <= 36; 53 | 54 | // apply user settings 55 | this.utils.validateArgs(args, true); 56 | } 57 | 58 | 59 | /** 60 | * BaseEx SimpleBase Encoder. 61 | * @param {*} input - Input according to the used byte converter. 62 | * @param {...any} [args] - Converter settings. 63 | * @returns {string} - Base 2-62 encoded string. 64 | */ 65 | encode(input, ...args) { 66 | return super.encode(input, null, null, ...args); 67 | } 68 | 69 | 70 | /** 71 | * BaseEx SimpleBase Decoder. 72 | * @param {string} input - Base 2-62 String. 73 | * @param {...any} [args] - Converter settings. 74 | * @returns {*} - Output according to converter settings. 75 | */ 76 | decode(rawInput, ...args) { 77 | 78 | // pre decoding function 79 | const normalizeInput = ({ input }) => { 80 | 81 | // normalize input (add leading zeros) for base 2 and 16 82 | if (this.converter.radix === 2) { 83 | const leadingZeros = (8 - (input.length % 8)) % 8; 84 | input = `${"0".repeat(leadingZeros)}${input}`; 85 | } else if (this.converter.radix === 16) { 86 | const leadingZeros = input.length % 2; 87 | input = `${"0".repeat(leadingZeros)}${input}`; 88 | } 89 | 90 | return input; 91 | } 92 | 93 | return super.decode(rawInput, normalizeInput, null, false, ...args); 94 | 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/converters/uuencode.js: -------------------------------------------------------------------------------- 1 | /** 2 | * [BaseEx|UUencode Converter]{@link https://github.com/UmamiAppearance/BaseExJS/blob/main/src/converters/uuencode.js} 3 | * 4 | * @version 0.8.1 5 | * @author UmamiAppearance [mail@umamiappearance.eu] 6 | * @license MIT 7 | */ 8 | 9 | import { BaseConverter, BaseTemplate } from "../core.js"; 10 | 11 | /** 12 | * BaseEx UUencode Converter. 13 | * ------------------------ 14 | * 15 | * This is a UUencoder/UUdecoder. Various input can be 16 | * converted to a UUencoded string or a UUencoded string 17 | * can be decoded into various formats. 18 | * 19 | * Available charsets are: 20 | * - default 21 | * - original 22 | * - xx 23 | */ 24 | export default class UUencode extends BaseTemplate { 25 | 26 | /** 27 | * BaseEx UUencode Constructor. 28 | * @param {...string} [args] - Converter settings. 29 | */ 30 | constructor(...args) { 31 | super(); 32 | this.converter = new BaseConverter(64, 3, 4); 33 | 34 | // charsets 35 | this.charsets.default = [..."`!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"]; 36 | Object.defineProperty(this.padChars, "default", { 37 | get: () => [ this.charsets.default.at(0) ] 38 | }); 39 | 40 | this.charsets.original = [" ", ...this.charsets.default.slice(1)]; 41 | Object.defineProperty(this.padChars, "original", { 42 | get: () => [ this.charsets.original.at(0) ] 43 | }); 44 | 45 | this.charsets.xx = [..."+-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"]; 46 | Object.defineProperty(this.padChars, "xx", { 47 | get: () => [ this.charsets.xx.at(0) ] 48 | }); 49 | 50 | 51 | // predefined settings 52 | this.padding = true; 53 | this.buffering = false; 54 | this.utils.converterArgs.buffering = ["nobuffering", "buffering"]; 55 | this.isMutable.buffering = true; 56 | this.header = false; 57 | this.utils.converterArgs.header = ["noheader", "header"]; 58 | this.isMutable.header = true; 59 | this.isMutable.integrity = false; 60 | 61 | // apply user settings 62 | this.utils.validateArgs(args, true); 63 | } 64 | 65 | 66 | /** 67 | * BaseEx UUencoder. 68 | * @param {*} input - Input according to the used byte converter. 69 | * @param {...str} [args] - Converter settings. 70 | * @returns {string} - UUencode string. 71 | */ 72 | encode(input, ...args) { 73 | 74 | const format = ({ output, settings, zeroPadding }) => { 75 | 76 | const charset = this.charsets[settings.version]; 77 | const outArray = [...output]; 78 | const outLen = outArray.length; 79 | settings.options.lineWrap = 0; 80 | 81 | 82 | if (settings.header && !settings.buffering) { 83 | const permissions = settings.options.permissions || een(); 84 | const fileName = settings.options.file || ees(); 85 | output = `begin ${permissions} ${fileName}\n`; 86 | } else { 87 | output = ""; 88 | } 89 | 90 | // repeatedly take 60 chars from the output 91 | for (let start=0; start= outLen) { 97 | const byteCount = this.converter.padChars(lArray.length) - zeroPadding; 98 | 99 | // add the the current chars plus the leading 100 | // count char 101 | output += `${charset.at(byteCount)}${lArray.join("")}\n`; 102 | } 103 | 104 | // add the the current chars plus the leading 105 | // count char ("M" for default charsets) 106 | else { 107 | output += `${charset.at(45)}${lArray.join("")}\n`; 108 | } 109 | } 110 | 111 | if (!settings.buffering) { 112 | output += `${charset.at(0)}\n`; 113 | 114 | if (settings.header) { 115 | output += "end\n"; 116 | } 117 | } 118 | 119 | return output; 120 | } 121 | 122 | return super.encode(input, null, format, ...args); 123 | } 124 | 125 | 126 | /** 127 | * BaseEx UUdecoder. 128 | * @param {string} input - UUencode String. 129 | * @param {...any} [args] - Converter settings. 130 | * @returns {*} - Output according to converter settings. 131 | */ 132 | decode(input, ...args) { 133 | 134 | let padChars = 0; 135 | 136 | const format = ({ input, settings }) => { 137 | 138 | const charset = this.charsets[settings.version]; 139 | const lines = input.trim().split(/\r?\n/); 140 | const inArray = []; 141 | 142 | if ((/^begin/i).test(lines.at(0))) { 143 | lines.shift(); 144 | } 145 | 146 | for (const line of lines) { 147 | const lArray = [...line]; 148 | const byteCount = charset.indexOf(lArray.shift()); 149 | 150 | if (!(byteCount > 0)) { 151 | break; 152 | } 153 | 154 | inArray.push(...lArray); 155 | 156 | if (byteCount !== 45) { 157 | let len = lArray.length 158 | 159 | // fix probably missing spaces for original charset 160 | if (settings.version === "original") { 161 | const expectedLen = calcUUStrLen(byteCount); 162 | while (len < expectedLen) { 163 | len++; 164 | inArray.push(" "); 165 | } 166 | } 167 | 168 | padChars = this.converter.padChars(len) - byteCount; 169 | break; 170 | } 171 | 172 | // fix probably missing spaces for original charset 173 | else if (lArray.length !== 60 && settings.version === "original") { 174 | while (inArray.length % 60) { 175 | inArray.push(" "); 176 | } 177 | } 178 | } 179 | 180 | return inArray.join(""); 181 | 182 | } 183 | 184 | const removePadChars = ({ output }) => { 185 | if (padChars) { 186 | output = new Uint8Array(output.slice(0, -padChars)); 187 | } 188 | return output; 189 | } 190 | 191 | return super.decode(input, format, removePadChars, true, ...args); 192 | } 193 | } 194 | 195 | 196 | const een = () => { 197 | const o = () => Math.floor(Math.random() * 8); 198 | return `${o()}${o()}${o()}`; 199 | } 200 | 201 | const ees = () => { 202 | const name = [ 203 | "unchronological", 204 | "unconditionally", 205 | "underemphasized", 206 | "underprivileged", 207 | "undistinguished", 208 | "unsophisticated", 209 | "untitled", 210 | "untitled-1", 211 | "untitled-3", 212 | "uuencode" 213 | ]; 214 | 215 | const ext = [ 216 | "applescript", 217 | "bat", 218 | "beam", 219 | "bin", 220 | "exe", 221 | "js", 222 | "mam", 223 | "py", 224 | "sh", 225 | "vdo", 226 | "wiz" 227 | ]; 228 | 229 | const pick = (arr) => arr.at(Math.floor(Math.random() * arr.length)); 230 | 231 | return `${pick(name)}.${pick(ext)}`; 232 | }; 233 | 234 | const calcUUStrLen = byteCount => { 235 | const len = byteCount / 3 * 4; 236 | if (len % 4) { 237 | return Math.floor(len/4) * 4 + 4; 238 | } 239 | return len; 240 | } 241 | -------------------------------------------------------------------------------- /test/base-1.test.js: -------------------------------------------------------------------------------- 1 | import { Base1, SimpleBase } from "base-ex"; 2 | import { randInt } from "./fixtures/helpers.js"; 3 | import test from "ava"; 4 | 5 | 6 | const b1Test = test.macro(async (t, input, expectedLen, base, ...args) => { 7 | const output = base.encode(input, ...args); 8 | t.is(output.length, expectedLen); 9 | t.is(base.decode(output, ...args), input); 10 | }); 11 | 12 | const bFn = new Base1(); 13 | const base10 = new SimpleBase(10); 14 | 15 | // string 16 | let input = "str"; 17 | let expectedLen = base10.encode(input)|0; 18 | const title = `En- and decode Base1 for type String with input 'str'`; 19 | 20 | test(title, b1Test, input, expectedLen, bFn, "str"); 21 | 22 | 23 | // integers 24 | for (let i=0; i<2; i++) { 25 | 26 | const int = ["Uint", "Int"].at(i); 27 | const signMulti = [1, -1].at(i); 28 | const arg = `${int.toLowerCase()}_n`; 29 | 30 | input = randInt(256, 2**24); 31 | 32 | // raise by one if negative sign is present 33 | expectedLen = input + i; 34 | input *= signMulti; 35 | 36 | const title = `En- and decode Base1 for type Integer with input '${input}'`; 37 | 38 | test(title, b1Test, input, expectedLen, bFn, arg); 39 | } 40 | -------------------------------------------------------------------------------- /test/ecoji-orig.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * JavaScript/AVA implementation 3 | * @see https://github.com/keith-turner/ecoji/blob/main/test_scripts/ecoji_test.sh 4 | */ 5 | 6 | 7 | import { readFile, readdir } from "fs/promises"; 8 | import { Ecoji } from "base-ex"; 9 | import test from "ava"; 10 | 11 | // macros 12 | const enDecodeTest = test.macro((t, input, expected, ecoji) => { 13 | const output = ecoji.encode(input); 14 | t.is(output, expected); 15 | t.deepEqual(ecoji.decode(output), input); 16 | }); 17 | 18 | const decodeTest = test.macro((t, input, expected, ecoji, ...args) => { 19 | t.is(ecoji.decode(input, ...args), expected); 20 | }); 21 | 22 | const errorTest = test.macro((t, input, ecoji) => { 23 | t.throws(() => ecoji.decode(input)); 24 | }); 25 | 26 | 27 | // declarations 28 | const path = "./test/fixtures/ecoji/"; 29 | const files = await (readdir(path)); 30 | const ecojiV1 = new Ecoji("emojis_v1", "uint8"); 31 | const ecojiV2 = new Ecoji("emojis_v2", "uint8"); 32 | 33 | 34 | // test group file lists 35 | const plainFilesA = files.filter(f => (/\.plain$/).test(f)); 36 | const aLen = plainFilesA.length; 37 | 38 | const plainFilesB = files.filter(f => (/\.plaind$/).test(f)); 39 | const bLen = plainFilesB.length; 40 | 41 | const garbage = files.filter(f => (/\.garbage$/).test(f)); 42 | const gLen = garbage.length; 43 | 44 | 45 | // test data generation 46 | const dataA = await Promise.all( 47 | plainFilesA.map(async plainFile => { 48 | const bareName = plainFile.slice(0, -6); 49 | 50 | const input = new Uint8Array(await readFile(`${path}${plainFile}`)); 51 | 52 | const expectedV1 = await readFile(`${path}${bareName}.ev1`, "utf-8"); 53 | const expectedV2 = await readFile(`${path}${bareName}.ev2`, "utf-8"); 54 | 55 | return { 56 | input, 57 | expectedV1, 58 | expectedV2 59 | } 60 | }) 61 | ); 62 | 63 | const dataB = await Promise.all( 64 | plainFilesB.map(async plainFile => { 65 | const bareName = plainFile.slice(0, -7); 66 | 67 | const input = await readFile(`${path}${bareName}.enc`, "utf-8"); 68 | const expected = await readFile(`${path}${plainFile}`, "utf-8"); 69 | 70 | return { 71 | input, 72 | expected 73 | } 74 | }) 75 | ); 76 | 77 | const dataC = await Promise.all( 78 | garbage.map( 79 | async plainFile => readFile(`${path}${plainFile}`) 80 | ) 81 | ); 82 | 83 | 84 | // tests 85 | dataA.forEach((data, i) => { 86 | test(`En- and decoding for Ecoji Version 1, Test: [${i+1}|${aLen}]`, enDecodeTest, data.input, data.expectedV1, ecojiV1); 87 | test(`En- and decoding for Ecoji Version 2, Test: [${i+1}|${aLen}]`, enDecodeTest, data.input, data.expectedV2, ecojiV2); 88 | }); 89 | 90 | dataB.forEach((data, i) => { 91 | test(`Decode sample data for both versions, Test: [${i+1}|${bLen}]`, decodeTest, data.input, data.expected, ecojiV2, "str"); 92 | }); 93 | 94 | dataC.forEach((data, i) => { 95 | test(`Garbage input > throw Error, Test: [${i+1}|${gLen}]`, errorTest, data, ecojiV2); 96 | }); 97 | -------------------------------------------------------------------------------- /test/fixtures/ecoji/ascii.garbage: -------------------------------------------------------------------------------- 1 | not emojisV2 -------------------------------------------------------------------------------- /test/fixtures/ecoji/concat_v1_1.enc: -------------------------------------------------------------------------------- 1 | 👖📸🎈☕🎥🤠📠🏍🐲👡🕟☕ -------------------------------------------------------------------------------- /test/fixtures/ecoji/concat_v1_1.plaind: -------------------------------------------------------------------------------- 1 | abc6789XY 2 | -------------------------------------------------------------------------------- /test/fixtures/ecoji/concat_v1_2.enc: -------------------------------------------------------------------------------- 1 | 🏒☕☕☕🏗🈳☕☕🏟🌚👑☕🏫🍌🔥📑🏾🎌🛡🔢🐒🏣🍜🛢🐥☕☕☕🐪👆📨🐫🎈🚌☕☕🎐🚯🏛🐇🎩🤰🔓☕👖📸🎦🌭👪🕕📬🏍👺😁🚗🐿💎🚃🌤🕒 -------------------------------------------------------------------------------- /test/fixtures/ecoji/concat_v1_2.plaind: -------------------------------------------------------------------------------- 1 | ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrs -------------------------------------------------------------------------------- /test/fixtures/ecoji/concat_v2_1.enc: -------------------------------------------------------------------------------- 1 | 👖📸🧈🌭👩☕💲🥇🪚☕ -------------------------------------------------------------------------------- /test/fixtures/ecoji/concat_v2_1.plaind: -------------------------------------------------------------------------------- 1 | abcdefxyz -------------------------------------------------------------------------------- /test/fixtures/ecoji/concat_v2_2.enc: -------------------------------------------------------------------------------- 1 | 🏒☕🧏🥱☕🧝🌚👑☕🏫🍌🔥📑🧦🎌🫣🧽🐒🏣🍜🫤🐥☕🐪👆📨🐫🎈🚌☕🎐🚯🧙🐇🎩🤰🔓☕👖📸🧈🌭👪🪐📬🛼👺😁🚗🧨💎🚃🦩🪄 -------------------------------------------------------------------------------- /test/fixtures/ecoji/concat_v2_2.plaind: -------------------------------------------------------------------------------- 1 | ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrs -------------------------------------------------------------------------------- /test/fixtures/ecoji/eight_byte.ev1: -------------------------------------------------------------------------------- 1 | 🅱🎙👁🔼🕰🦰🎈☕ -------------------------------------------------------------------------------- /test/fixtures/ecoji/eight_byte.ev2: -------------------------------------------------------------------------------- 1 | ⏳🧃🧩🩻🪤🫳🎈☕ -------------------------------------------------------------------------------- /test/fixtures/ecoji/eight_byte.plain: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UmamiAppearance/BaseExJS/d32c2969546bebad272325d937f0d9daabe3aed3/test/fixtures/ecoji/eight_byte.plain -------------------------------------------------------------------------------- /test/fixtures/ecoji/exhaustive.ev1: -------------------------------------------------------------------------------- 1 | 💜🥪🌫🚏🛬🇦🥖🕷🐓🍮🕋🏪🥠🦶👺📺👭🔽👊🦵🥈🈸🚅🎠🎲😌🕴🍰🚾🕗🏖🌙🚒🍄🛶🌒🤤🎺🍣🦀🈁🖖🔒👖🗳🍠🤛📋👤🥯🆖🏝💋🚬🇧💃🎚🦊👶🌩🛑🗡📅😅🖕🍱🇬🈺😷🌖🖼🛡😪😿👁🀄👌💲🌭👷🚶🏙🏯🏾🚍🥘👈🍸🏆🇩🚌🛰🇸🇷🤸📕🕎🛳😥😒🦞🥼📬🔎🌇🎰🐂📭🍭💻🔱🤲😚📷🕳💒🔈🌾📌🍗😀🕸🚐🦋🆗🙆🔌🏒🎖🏁🏹🦹🚖🏫🦇📽🥒🍦🤺😮🚳🦲🍹🚠👵🚀📖🎹🥇👿🤾🌜💇🏜💯🖱😤🕤👕🗻🗂🎥🤷🖥🦑🤐🕑🏴🦉🦐🏩📍🚔🕶💰🐁🏈🏽🍪🆙🌵💨🎆🍁👪👝🔧🔥🎼🗄🛣🦴🚤🥕🎡🛢🏐🌷😴🎃🚩🍨🎋🔄🐹🥌😣📆🦠🤞🔀🏻🐻🤖🦢📙😵🥙🚎🔞🇮🏃🔝🌈🦙🙄🎏🎢😐💹🗼🐩💡📊📥🤗🛐😊🌅💿👓📀🌪🐨🕦🍷📰📚🏤💢🌯🤱🗿🍌🚁🥝👐🍲🍉🗝🥤🗞🌞🔩🈚😨🚻🔃🐘😑🍋🎧🌶😔🍻🍟👋💫🍖🤶🚄🔙🤘👦🐯🐟🏺🇳🌬🙌🏂💶🛴🆎🐅🔜🐇🌹📶🍢🦍🕓🌡🐮🔅🔭🌂💏👢📣📯📘👙🦸🌘🗨💈📁🆕🇨🕖🛤👟🐎👰🉑🍓😉🔐🦃🌉🤡🐣🍐🍽🔻💆🌝🎾💵👨🐌🐶👡🐪🔑👞🏓🙃🐍😱👸🗯📟🍛🔴🐊🎌🕢🐤👂🛀🦎🤚🤢🖌🕕🦅💎🥮🇹💤📦😂💷🧁🥗🛂🎛🚛😛🥭🚢🎦🙁🛒🔕💟📱💗🌱🎁🤫🚗🕠🙇🛌😡🦰🙅🦟🔯🛠😇📢🚭🗽🌳🍺🗣📵🏦🌑🤪🏣🔖🌄🎐👀🛹🇪🕍🦷🌍🔫📨🎙😢🎑🧐😲🥿🛩🏀🕹😏🚇🚣🚺🎎🎂🕰🈯🗃🤜🦡📮🍍🔺🌮🍂🐳🔦🥡🆔🎬💩🏸🥦🐺🏛🎓🏏🍚🎳🔳🎱🧓👏🥐🏷🧒🕛🐔💀📴🅰🕥🥳🏕👫🏄🕡🚨🚕🌲🌰🎞📩🐜📝🎣😜👻🖲🛵📓🍇🍡📼💕🏡🎸🈳🗓📸🤳🕞🏥😎🛅🌴👒🛋📿🎭🗑🚱📒📧🖍🛎🔬🎵👯🦔🐷🕺🏼🕣👗🥞🕟😽🥓🏔💖🌔😬🐥🇼😞🤹🕜🚑🚙🥧🇽🔹🥟🏧🖤🏨🛍👘🤑🎍🏞🎄🥫🈂💊🔘👬🚆💛🤩🇲💽🔂🖋🐲📛💉🍵💧🍈🇫🔟🐭🌛🥴🙂📤🌁🚹🔏🏰🇱🕌😟🎟🚧🏅🕧🥏🔨🧔💄🏚🔉🚫🐿😹🏮🤰🍊🐐🌟🙎💐📪🐕🖨👾📃🚞🍤🎗🐠🎪📜😺🚜🍙💍🍅🈹👇👧🇵🍑🌎🌼🐄🇯💞🛏🔸👱🆓🧀🛄🎶🗾💱🦕💥🔛🌆🌕💓🕵💅🔇🏳👃📔😻🍎🚚🎤🥛👄🈲🙏🤧🕯🔚🕚👔🐗🇴🚸🛁📂🌽🍴💳👹🏎😙🦗🇰👜🚘🤽🥉🤟👍🎊😦🦁🙊🐡🦛🔢📫🐒👣🥥🧂🚟🕔🈷🦖📳📻🚼🔰😫🚰💁🎇🐝🌊🍀🕉🔤🚥🔼🖐🐵🌓👛🍫📇🛸🕐🛃🚯🐖🥁🎿🧑🍿📏💚🚊🔡🥣🎯🇺🧕🔊🏵🥽🦘💮📞🏉🔮🥚👼😍🚋🔠👳💪🍃👅🤒🏋💦😘👠😩🚃🐾👥🥔🍆🥰📉😳😓🔪😶🎀🤯🚓😈🥋🆚💸🤔🎫🥬🐼🌗🤵🤦🆘🏢📹🥊🎻🍯🕊🚵🙈🐸🚉💺📗🐴🦜🐱😾👚😰🔍🕒🍜👑🍒🆑🏗📲🌿🦳🇿😸🍏🍔😠🦒🍳🏿🔋🔓🚈🥵🚦🆒🥺🦱😯🦝📄🖊🔶🥾🔵🥄😧🌠🐰💾🕝🌺🏬🐀🤭🐞🌻🤕🐽😖🐙🎷👉🌤🖇🤼🔷🦓🐢🙉🚂🅾🐦😼🍾🇻🗺🤥🥂🈵💘🎅🐑😄🥑🍶🤣🎽🗜👴🚲🇭🌸🤙🚽🍬🔆🏠📎🍞🥃🦏🌐📡🐧😁🦆🛥🐃👩🅱🎉📠🤝🦚🌥😆🌃🔣🤨🥩🌨💭🐫🔲🍼🎈💠🥨🕘🐛🥍📈🥢🏭🐉💣🤮🎒🍕🌋🅿🤠💔💴🌀📐🕙🎩😃🌌💼🥶🤬🐏🥜🇶🌦🔗🥅😝🙀🈶🤴😗💝😕💂🔁🍥🈴🥎🍧🛷🛫🉐🏌🚮💬🚷🚡🏘🐚🌏😋👲🍝🐈💙🏊🙍🚴😭💌🌚🏟🎴🗒👎🐋👆👽👮🥀🎨🤓🦂🐬🦌🚝🚿🐆💑🏑🇾🔔🍩🍘🦄🌧🏇🃏🦈🚪🎮 -------------------------------------------------------------------------------- /test/fixtures/ecoji/exhaustive.ev2: -------------------------------------------------------------------------------- 1 | 💜🥪🦺🚏🛬♿🥖🪩🐓🍮🕋🏪🥠🦶👺📺👭🩼👊🦵🥈🦣🚅🎠🎲😌🪦🍰🚾🪒🧎🌙🚒🍄🛶🌒🤤🎺🍣🦀🈁🖖🔒👖🫖🍠🤛📋👤🥯♏🧛💋🚬⚓💃🧄🦊👶🦮🛑🫒🧬😅🖕🍱⛅🦥😷🌖🪹🫣😪😿🧩🀄👌💲🌭👷🚶🧗🏯🧦🚍🥘👈🍸🏆⚽🚌🫱⭐✨🤸📕🕎🫲😥😒🦞🥼📬🔎🌇🎰🐂📭🍭💻🔱🤲😚📷🪥💒🔈🌾📌🍗😀🪪🚐🦋♐🙆🔌🏒🦾🏁🏹🦹🚖🏫🦇🧮🥒🍦🤺😮🚳🫵🍹🚠👵🚀📖🎹🥇👿🤾🌜💇🧚💯🪷😤🪟👕🗻🪺🎥🤷🪵🦑🤐🪃🏴🦉🦐🏩📍🚔🪨💰🐁🏈🧥🍪♒🌵💨🎆🍁👪👝🔧🔥🎼🫁🫥🦴🚤🥕🎡🫤🏐🌷😴🎃🚩🍨🎋🧳🐹🥌😣📆🦠🤞🧯🧣🐻🤖🦢📙😵🥙🚎🧹⛔🏃🧸🌈🦙🙄🎏🎢😐🧪🗼🐩💡📊📥🤗🛐😊🌅💿👓📀🦯🐨🪡🍷📰📚🏤💢🌯🤱🗿🍌🚁🥝👐🍲🍉🫐🥤🫑🌞🔩🤌😨🚻🧲🐘😑🍋🎧🦼😔🍻🍟👋💫🍖🤶🚄🧴🤘👦🐯🐟🏺⛺🦻🙌🏂💶🛴♉🐅🧷🐇🌹📶🍢🦍🪅🦨🐮🔅🔭🌂💏👢📣📯📘👙🦸🌘🫔💈🧫♎⚡🪑🫦👟🐎👰🦧🍓😉🔐🦃🌉🤡🐣🍐🦽🩺💆🌝🎾💵👨🐌🐶👡🐪🔑👞🏓🙃🐍😱👸🫕📟🍛🩰🐊🎌🪝🐤👂🛀🦎🤚🤢🪲🪐🦅💎🥮🛕💤📦😂💷🧁🥗🛂🧅🚛😛🥭🚢🧈🙁🛒🔕💟📱💗🌱🎁🤫🚗🪛🙇🛌😡🫳🙅🦟🔯🫢😇📢🚭🗽🌳🍺🫓📵🏦🌑🤪🏣🔖🌄🎐👀🛹⚾🕍🦷🌍🔫📨🧃😢🎑🧐😲🥿🫰🏀🪫😏🚇🚣🚺🎎🎂🪤🤏🫀🤜🦡📮🍍🩹🌮🍂🐳🔦🥡♍🎬💩🏸🥦🐺🧙🎓🏏🍚🎳🔳🎱🧓👏🥐🧢🧒🪖🐔💀🧭⏰🪠🥳🧍👫🏄🪜🚨🚕🌲🌰🧆📩🐜📝🎣😜👻🪸🛵📓🍇🍡📼💕🏡🎸🥱🫄📸🤳🪙🏥😎🛅🌴👒🫘📿🎭🫂🚱📒📧🪳🫠🔬🎵👯🦔🐷🕺🧤🪞👗🥞🪚😽🥓🧌💖🌔😬🐥🛝😞🤹🪗🚑🚙🥧🛞🩸🥟🧞🖤🏨🫙👘🤑🎍🧜🎄🥫🛻💊🔘👬🚆💛🤩⛵💽🧱🪱🐲📛💉🍵💧🍈⛄🧺🐭🌛🥴🙂📤🌁🚹🔏🏰⛳🕌😟🧇🚧🏅🪢🥏🔨🧔💄🧘🔉🚫🧨😹🏮🤰🍊🐐🌟🙎💐📪🐕🪶👾📃🚞🍤🦿🐠🎪📜😺🚜🍙💍🍅🦤👇👧✊🍑🌎🌼🐄⛪💞🫡🩴👱♌🧀🛄🎶🗾💱🦕💥🧶🌆🌕💓🪧💅🔇🧟👃📔😻🍎🚚🎤🥛👄🤿🙏🤧🪣🧵🪕👔🐗⛽🚸🛁📂🌽🍴💳👹🧋😙🦗⛲👜🚘🤽🥉🤟👍🎊😦🦁🙊🐡🦛🧽📫🐒👣🥥🧂🚟🪆🥻🦖📳📻🚼🔰😫🚰💁🎇🐝🌊🍀🪀🧿🚥🩻🪴🐵🌓👛🍫📇🛸🪂🛃🚯🐖🥁🎿🧑🍿📏💚🚊🧼🥣🎯🛖🧕🔊🧠🥽🦘💮📞🏉🔮🥚👼😍🚋🧻👳💪🍃👅🤒🧉💦😘👠😩🚃🐾👥🥔🍆🥰📉😳😓🔪😶🎀🤯🚓😈🥋♓💸🤔🎫🥬🐼🌗🤵🤦♑🏢📹🥊🎻🍯🪁🚵🙈🐸🚉💺📗🐴🦜🐱😾👚😰🔍🪄🍜👑🍒♊🧏📲🌿🫶🛺😸🍏🍔😠🦒🍳🧧🔋🔓🚈🥵🚦♋🥺🫴😯🦝📄🪰🩲🥾🩱🥄😧🌠🐰💾🪘🌺🏬🐀🤭🐞🌻🤕🐽😖🐙🎷👉🦩🪬🤼🩳🦓🐢🙉🚂☔🐦😼🍾🛗🫗🤥🥂🥸💘🎅🐑😄🥑🍶🤣🎽🫅👴🚲⛎🌸🤙🚽🍬🔆🏠📎🍞🥃🦏🌐📡🐧😁🦆🫧🐃👩⏳🎉📠🤝🦚🦪😆🌃🧾🤨🥩🦭💭🐫🔲🍼🎈💠🥨🪓🐛🥍📈🥢🏭🐉💣🤮🎒🍕🌋♈🤠💔💴🌀📐🪔🎩😃🌌💼🥶🤬🐏🥜✋🦫🔗🥅😝🙀🥹🤴😗💝😕💂🧰🍥🥲🥎🍧🛷🛫🦦🧊🚮💬🚷🚡🧖🐚🌏😋👲🍝🐈💙🏊🙍🚴😭💌🌚🧝🎴🫃👎🐋👆👽👮🥀🎨🤓🦂🐬🦌🚝🚿🐆💑🏑🛟🔔🍩🍘🦄🦬🏇🃏🦈🚪🎮 -------------------------------------------------------------------------------- /test/fixtures/ecoji/exhaustive.plain: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UmamiAppearance/BaseExJS/d32c2969546bebad272325d937f0d9daabe3aed3/test/fixtures/ecoji/exhaustive.plain -------------------------------------------------------------------------------- /test/fixtures/ecoji/five_byte.ev1: -------------------------------------------------------------------------------- 1 | 🗺🎫🥰🏳 -------------------------------------------------------------------------------- /test/fixtures/ecoji/five_byte.ev2: -------------------------------------------------------------------------------- 1 | 🫗🎫🥰🧟 -------------------------------------------------------------------------------- /test/fixtures/ecoji/five_byte.plain: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UmamiAppearance/BaseExJS/d32c2969546bebad272325d937f0d9daabe3aed3/test/fixtures/ecoji/five_byte.plain -------------------------------------------------------------------------------- /test/fixtures/ecoji/four_byte_1.ev1: -------------------------------------------------------------------------------- 1 | 🀄🆚🍈⚜ -------------------------------------------------------------------------------- /test/fixtures/ecoji/four_byte_1.ev2: -------------------------------------------------------------------------------- 1 | 🀄♓🍈🥷 -------------------------------------------------------------------------------- /test/fixtures/ecoji/four_byte_1.plain: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /test/fixtures/ecoji/four_byte_2.ev1: -------------------------------------------------------------------------------- 1 | 🀄🆚🍈🏍 -------------------------------------------------------------------------------- /test/fixtures/ecoji/four_byte_2.ev2: -------------------------------------------------------------------------------- 1 | 🀄♓🍈🛼 -------------------------------------------------------------------------------- /test/fixtures/ecoji/four_byte_2.plain: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /test/fixtures/ecoji/four_byte_3.ev1: -------------------------------------------------------------------------------- 1 | 🀄🆚🍈📑 -------------------------------------------------------------------------------- /test/fixtures/ecoji/four_byte_3.ev2: -------------------------------------------------------------------------------- 1 | 🀄♓🍈📑 -------------------------------------------------------------------------------- /test/fixtures/ecoji/four_byte_3.plain: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /test/fixtures/ecoji/four_byte_4.ev1: -------------------------------------------------------------------------------- 1 | 🀄🆚🍈🙋 -------------------------------------------------------------------------------- /test/fixtures/ecoji/four_byte_4.ev2: -------------------------------------------------------------------------------- 1 | 🀄♓🍈🙋 -------------------------------------------------------------------------------- /test/fixtures/ecoji/four_byte_4.plain: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /test/fixtures/ecoji/incorrect_v1_padding.garbage: -------------------------------------------------------------------------------- 1 | 🌶🌶🌶🌶🌶 -------------------------------------------------------------------------------- /test/fixtures/ecoji/misplaced_padding_1.garbage: -------------------------------------------------------------------------------- 1 | ⚜🃏🅰🅱 -------------------------------------------------------------------------------- /test/fixtures/ecoji/misplaced_padding_2.garbage: -------------------------------------------------------------------------------- 1 | 🥷🃏⏰⏳ -------------------------------------------------------------------------------- /test/fixtures/ecoji/misplaced_padding_3.garbage: -------------------------------------------------------------------------------- 1 | 🃏🏍🅰🅱 -------------------------------------------------------------------------------- /test/fixtures/ecoji/misplaced_padding_4.garbage: -------------------------------------------------------------------------------- 1 | 🃏⏰🙋⏳ -------------------------------------------------------------------------------- /test/fixtures/ecoji/misplaced_padding_5.garbage: -------------------------------------------------------------------------------- 1 | 🀄🅰☕🤾 -------------------------------------------------------------------------------- /test/fixtures/ecoji/misplaced_padding_6.garbage: -------------------------------------------------------------------------------- 1 | ☕🃏⏰⏳ -------------------------------------------------------------------------------- /test/fixtures/ecoji/misplaced_padding_7.garbage: -------------------------------------------------------------------------------- 1 | 🃏⏰⏳☔☕☕☕☕ -------------------------------------------------------------------------------- /test/fixtures/ecoji/missing_padding_1.garbage: -------------------------------------------------------------------------------- 1 | 🃏⏰⏳ -------------------------------------------------------------------------------- /test/fixtures/ecoji/missing_padding_2.garbage: -------------------------------------------------------------------------------- 1 | 🃏⏰⏳☔♈ -------------------------------------------------------------------------------- /test/fixtures/ecoji/mixed_1.garbage: -------------------------------------------------------------------------------- 1 | 🀄🅰🤿🤾 -------------------------------------------------------------------------------- /test/fixtures/ecoji/mixed_2.garbage: -------------------------------------------------------------------------------- 1 | 🀄🤿🅰🤾 -------------------------------------------------------------------------------- /test/fixtures/ecoji/mixed_3.garbage: -------------------------------------------------------------------------------- 1 | 🀄🅰🅰🤾🀄🅰🅰🤾🀄🅰🤿🤾 -------------------------------------------------------------------------------- /test/fixtures/ecoji/mixed_4.garbage: -------------------------------------------------------------------------------- 1 | 🀄🅰🀄🥷 -------------------------------------------------------------------------------- /test/fixtures/ecoji/mixed_5.garbage: -------------------------------------------------------------------------------- 1 | 🀄🅰🀄🛼 -------------------------------------------------------------------------------- /test/fixtures/ecoji/mixed_6.garbage: -------------------------------------------------------------------------------- 1 | 🀄🀄🤿⚜ -------------------------------------------------------------------------------- /test/fixtures/ecoji/mixed_7.garbage: -------------------------------------------------------------------------------- 1 | 🀄🀄🤿🏍 -------------------------------------------------------------------------------- /test/fixtures/ecoji/nine_byte_0.ev1: -------------------------------------------------------------------------------- 1 | 🛥🏻🦲🌩🔶🏳🛩⚜ -------------------------------------------------------------------------------- /test/fixtures/ecoji/nine_byte_0.ev2: -------------------------------------------------------------------------------- 1 | 🫧🧣🫵🦮🩲🧟🫰🥷 -------------------------------------------------------------------------------- /test/fixtures/ecoji/nine_byte_0.plain: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UmamiAppearance/BaseExJS/d32c2969546bebad272325d937f0d9daabe3aed3/test/fixtures/ecoji/nine_byte_0.plain -------------------------------------------------------------------------------- /test/fixtures/ecoji/nine_byte_1.ev1: -------------------------------------------------------------------------------- 1 | 🛥🏻🦲🌩🔶🏳🛩🏍 -------------------------------------------------------------------------------- /test/fixtures/ecoji/nine_byte_1.ev2: -------------------------------------------------------------------------------- 1 | 🫧🧣🫵🦮🩲🧟🫰🛼 -------------------------------------------------------------------------------- /test/fixtures/ecoji/nine_byte_1.plain: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UmamiAppearance/BaseExJS/d32c2969546bebad272325d937f0d9daabe3aed3/test/fixtures/ecoji/nine_byte_1.plain -------------------------------------------------------------------------------- /test/fixtures/ecoji/nine_byte_2.ev1: -------------------------------------------------------------------------------- 1 | 🛥🏻🦲🌩🔶🏳🛩📑 -------------------------------------------------------------------------------- /test/fixtures/ecoji/nine_byte_2.ev2: -------------------------------------------------------------------------------- 1 | 🫧🧣🫵🦮🩲🧟🫰📑 -------------------------------------------------------------------------------- /test/fixtures/ecoji/nine_byte_2.plain: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UmamiAppearance/BaseExJS/d32c2969546bebad272325d937f0d9daabe3aed3/test/fixtures/ecoji/nine_byte_2.plain -------------------------------------------------------------------------------- /test/fixtures/ecoji/nine_byte_3.ev1: -------------------------------------------------------------------------------- 1 | 🛥🏻🦲🌩🔶🏳🛩🙋 -------------------------------------------------------------------------------- /test/fixtures/ecoji/nine_byte_3.ev2: -------------------------------------------------------------------------------- 1 | 🫧🧣🫵🦮🩲🧟🫰🙋 -------------------------------------------------------------------------------- /test/fixtures/ecoji/nine_byte_3.plain: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UmamiAppearance/BaseExJS/d32c2969546bebad272325d937f0d9daabe3aed3/test/fixtures/ecoji/nine_byte_3.plain -------------------------------------------------------------------------------- /test/fixtures/ecoji/non_ecoji_emoji.garbage: -------------------------------------------------------------------------------- 1 | 🟠🟡🤍🟩 -------------------------------------------------------------------------------- /test/fixtures/ecoji/one_byte.ev1: -------------------------------------------------------------------------------- 1 | 👽☕☕☕ -------------------------------------------------------------------------------- /test/fixtures/ecoji/one_byte.ev2: -------------------------------------------------------------------------------- 1 | 👽☕ -------------------------------------------------------------------------------- /test/fixtures/ecoji/one_byte.plain: -------------------------------------------------------------------------------- 1 | k -------------------------------------------------------------------------------- /test/fixtures/ecoji/phrase.ev1: -------------------------------------------------------------------------------- 1 | 🏗📩🎦🐇🎛📘🔯🚜💞😽🆖🐊🎱🥁🚄🌱💞😭💮🇵💢🕥🐭🔸🍉🚲🦑🐶💢🕥🔮🔺🍉📸🐮🌼👦🚟🥴📑 -------------------------------------------------------------------------------- /test/fixtures/ecoji/phrase.ev2: -------------------------------------------------------------------------------- 1 | 🧏📩🧈🐇🧅📘🔯🚜💞😽♏🐊🎱🥁🚄🌱💞😭💮✊💢🪠🐭🩴🍉🚲🦑🐶💢🪠🔮🩹🍉📸🐮🌼👦🚟🥴📑 -------------------------------------------------------------------------------- /test/fixtures/ecoji/phrase.plain: -------------------------------------------------------------------------------- 1 | Base64 is so 1999, isn't there something better? 2 | -------------------------------------------------------------------------------- /test/fixtures/ecoji/seven_byte.ev1: -------------------------------------------------------------------------------- 1 | 🎺🌓🏏📓🚥🌸☕☕ -------------------------------------------------------------------------------- /test/fixtures/ecoji/seven_byte.ev2: -------------------------------------------------------------------------------- 1 | 🎺🌓🏏📓🚥🌸☕ -------------------------------------------------------------------------------- /test/fixtures/ecoji/seven_byte.plain: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UmamiAppearance/BaseExJS/d32c2969546bebad272325d937f0d9daabe3aed3/test/fixtures/ecoji/seven_byte.plain -------------------------------------------------------------------------------- /test/fixtures/ecoji/six_byte.ev1: -------------------------------------------------------------------------------- 1 | 🍃💙🚑🤺🎩☕☕☕ -------------------------------------------------------------------------------- /test/fixtures/ecoji/six_byte.ev2: -------------------------------------------------------------------------------- 1 | 🍃💙🚑🤺🎩☕ -------------------------------------------------------------------------------- /test/fixtures/ecoji/six_byte.plain: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UmamiAppearance/BaseExJS/d32c2969546bebad272325d937f0d9daabe3aed3/test/fixtures/ecoji/six_byte.plain -------------------------------------------------------------------------------- /test/fixtures/ecoji/three_byte.ev1: -------------------------------------------------------------------------------- 1 | 🀄🆚🍈☕ -------------------------------------------------------------------------------- /test/fixtures/ecoji/three_byte.ev2: -------------------------------------------------------------------------------- 1 | 🀄♓🍈☕ -------------------------------------------------------------------------------- /test/fixtures/ecoji/three_byte.plain: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /test/fixtures/ecoji/two_byte.ev1: -------------------------------------------------------------------------------- 1 | 🀄🆚☕☕ -------------------------------------------------------------------------------- /test/fixtures/ecoji/two_byte.ev2: -------------------------------------------------------------------------------- 1 | 🀄♓☕ -------------------------------------------------------------------------------- /test/fixtures/ecoji/two_byte.plain: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /test/fixtures/ecoji/windows_newline_v2_1.enc: -------------------------------------------------------------------------------- 1 | 🎌 2 | 🚟 3 | 🦿🦣🎥🤠 4 | 📠🐁👖📸🎈☕ -------------------------------------------------------------------------------- /test/fixtures/ecoji/windows_newline_v2_1.plaind: -------------------------------------------------------------------------------- 1 | 1234567890abc -------------------------------------------------------------------------------- /test/fixtures/ecoji/windows_newline_v2_2.enc: -------------------------------------------------------------------------------- 1 | 🎌🚟🎗🈸🎥🤠📠🐁👖📸🎈☕ 2 | -------------------------------------------------------------------------------- /test/fixtures/ecoji/windows_newline_v2_2.plaind: -------------------------------------------------------------------------------- 1 | 1234567890abc -------------------------------------------------------------------------------- /test/fixtures/ecoji/zero_byte.ev1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UmamiAppearance/BaseExJS/d32c2969546bebad272325d937f0d9daabe3aed3/test/fixtures/ecoji/zero_byte.ev1 -------------------------------------------------------------------------------- /test/fixtures/ecoji/zero_byte.ev2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UmamiAppearance/BaseExJS/d32c2969546bebad272325d937f0d9daabe3aed3/test/fixtures/ecoji/zero_byte.ev2 -------------------------------------------------------------------------------- /test/fixtures/ecoji/zero_byte.plain: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UmamiAppearance/BaseExJS/d32c2969546bebad272325d937f0d9daabe3aed3/test/fixtures/ecoji/zero_byte.plain -------------------------------------------------------------------------------- /test/fixtures/helpers.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | 3 | const baseTest = test.macro(async (t, input, expected, base, ...args) => { 4 | const output = base.encode(input, ...args); 5 | if (expected !== null) { 6 | t.is(output, expected); 7 | } 8 | t.is(base.decode(output, ...args), input); 9 | }); 10 | 11 | 12 | // Random integer 13 | const randInt = (min, max) => Math.floor(Math.random() * (max - min) + min); 14 | 15 | // Random byte value 16 | const randByte = (start=0) => randInt(start, 256); 17 | 18 | // Random array with a length (between 8 and 24 by default) 19 | const randArray = (nullBytes, options={}) => { 20 | 21 | if (!("start" in options)) options.start = 8; 22 | if (!("end" in options)) options.end = 24; 23 | 24 | const array = new Array(); 25 | const generator = (nullBytes === null) ? () => 0 : () => randByte(); 26 | let i = randInt(options.start, options.end); 27 | while (i--) { 28 | array.push(generator()); 29 | } 30 | if (options.noNullStart && array.at(0) === 0) { 31 | array[0] = randByte(1); 32 | } else if (options.noNullEnd && array.at(-1) === 0) { 33 | array[array.length-1] = randByte(1); 34 | } 35 | return array 36 | } 37 | 38 | // Random string of printable ascii-chars including space 39 | const randStr = (len) => { 40 | const array = new Uint8Array(len); 41 | array.forEach((b, i) => array[i] = randInt(32, 127)); 42 | return new TextDecoder("ascii").decode(array); 43 | }; 44 | 45 | 46 | export { baseTest, randInt, randByte, randArray, randStr }; 47 | -------------------------------------------------------------------------------- /test/fixtures/load-json.js: -------------------------------------------------------------------------------- 1 | import { readFile } from "fs/promises"; 2 | 3 | const loadEncodingMap = async () => { 4 | 5 | const absPath = import.meta.url. 6 | replace("file://", ""). 7 | split("/"). 8 | slice(0, -1). 9 | concat("encoding-map.json"). 10 | join("/"); 11 | 12 | const encodingMap = JSON.parse(await readFile(absPath)); 13 | 14 | return encodingMap; 15 | }; 16 | 17 | export { loadEncodingMap }; 18 | -------------------------------------------------------------------------------- /test/map.test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-underscore-dangle */ 2 | 3 | import * as BaseEx from "base-ex"; 4 | import { baseTest } from "./fixtures/helpers.js"; 5 | import { loadEncodingMap } from "./fixtures/load-json.js"; 6 | import test from "ava"; 7 | 8 | 9 | const encodingMap = await loadEncodingMap(); 10 | for (const base in encodingMap) { 11 | 12 | const bFn = base === "LEB128" 13 | ? new BaseEx[base]("hex", "signed") 14 | : new BaseEx[base](); 15 | 16 | for (const _type in encodingMap[base]) { 17 | 18 | for (let input in encodingMap[base][_type]) { 19 | const title = `En- and decode ${base} for type ${_type} with input '${input}'`; 20 | const expected = encodingMap[base][_type][input]; 21 | 22 | let type = _type; 23 | if (type === "int") { 24 | input = (input.length > 12) ? BigInt(input) : Number(input); 25 | type = (input < 0) ? "int_n" : "uint_n"; 26 | } else if (type === "float") { 27 | input = Number(input); 28 | type = "float_n"; 29 | } else if (type === "decimal") { 30 | input = Number(input); 31 | } 32 | 33 | test(title, baseTest, input, expected, bFn, type); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /test/number-mode.test.js: -------------------------------------------------------------------------------- 1 | import * as BaseEx from "base-ex"; 2 | import { baseTest } from "./fixtures/helpers.js"; 3 | import test from 'ava'; 4 | 5 | 6 | const numbers = [ 7 | -Number.MAX_VALUE, 8 | -(2**256), 9 | -(2**128), 10 | -(2**64), 11 | -(2**32), 12 | -(2**16), 13 | -(2**8), 14 | -2, 15 | -1.23456789, 16 | -Number.MIN_VALUE, 17 | 0, 18 | Number.MIN_VALUE, 19 | 1.23456789, 20 | 2**16, 21 | 2**32, 22 | 2**64, 23 | 2**128, 24 | 2**256, 25 | Number.MAX_VALUE 26 | ]; 27 | 28 | const numbersNoMIN = [ 29 | ...numbers.slice(0, 9), 30 | 0, 31 | ...numbers.slice(12) 32 | ]; 33 | 34 | 35 | for (const base in BaseEx) { 36 | 37 | if (base !== "Base1" && base !== "BaseEx" && base !== "SimpleBase") { 38 | 39 | let bFn, num; 40 | 41 | if (base === "LEB128") { 42 | bFn = new BaseEx[base]("number", "signed"); 43 | num = numbersNoMIN; 44 | } 45 | 46 | else if (base === "BasePhi") { 47 | bFn = new BaseEx.BasePhi("number"); 48 | num = numbersNoMIN; 49 | } 50 | 51 | else { 52 | bFn = new BaseEx[base]("number"); 53 | num = numbers; 54 | } 55 | 56 | for (const n of num) { 57 | test( 58 | `Encode and decode back for ${base} with input '${n}'`, 59 | baseTest, 60 | n, 61 | null, 62 | bFn 63 | ); 64 | } 65 | } 66 | } 67 | 68 | 69 | for (let radix=2; radix<=62; radix++) { 70 | const bFn = new BaseEx.SimpleBase(radix, "number"); 71 | 72 | for (const n of numbersNoMIN) { 73 | test( 74 | `Encode and decode back for SimpleBase${radix} with input '${n}'`, 75 | baseTest, 76 | n, 77 | null, 78 | bFn 79 | ); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /test/random-io.test.js: -------------------------------------------------------------------------------- 1 | import * as BaseEx from "base-ex"; 2 | import { baseTest, randArray, randInt, randStr } from "./fixtures/helpers.js"; 3 | import test from 'ava'; 4 | 5 | let ITERATIONS = 4; 6 | process.argv.forEach(arg => { 7 | if ((/^iter=/).test(arg)) { 8 | ITERATIONS = arg.split("=").at(1)|0 9 | } 10 | }); 11 | 12 | const randBytesTest = test.macro(async (t, input, baseObj) => { 13 | const output = baseObj.encode(input); 14 | const backDecoded = baseObj.decode(output, "bytes").toString(); 15 | t.is(backDecoded, input.toString()); 16 | }); 17 | 18 | 19 | const randomInputs = (ignoreNullEnd, ignoreNullStart=false) => { 20 | 21 | const noNullStart = !ignoreNullEnd; 22 | const noNullEnd = !ignoreNullStart; 23 | 24 | const randBytesX = new Uint8Array(randArray(false, { 25 | start: 1, 26 | end: randInt(1, 512), 27 | noNullStart, 28 | noNullEnd 29 | })); 30 | 31 | const randStr16 = randStr(16); 32 | const randStr32 = randStr(32); 33 | const randStrX = randStr(randInt(1, 512)); 34 | 35 | const inputs = { 36 | bytes: { 37 | randBytesX 38 | }, 39 | str: { 40 | randStr16, 41 | randStr32, 42 | randStrX 43 | } 44 | }; 45 | 46 | if (!ignoreNullEnd) { 47 | inputs.bytes.randBytesNullEnd = new Uint8Array([ 48 | ...randArray(false, {noNullStart}), 49 | ...randArray(null), 50 | ...randArray(), 51 | ...randArray(null) 52 | ]); 53 | } 54 | 55 | if (!ignoreNullStart) { 56 | inputs.bytes.randBytesNullStart= new Uint8Array([ 57 | ...randArray(null), 58 | ...randArray(), 59 | ...randArray(null), 60 | ...randArray(false, {noNullEnd}) 61 | ]); 62 | } 63 | return inputs; 64 | }; 65 | 66 | 67 | [...Array(ITERATIONS).keys()].forEach(async i => { 68 | 69 | Object.keys(BaseEx).forEach(async base => { 70 | 71 | if (base !== "Base1" && base !== "BaseEx" && base !== "SimpleBase") { 72 | 73 | const bFn = new BaseEx[base](); 74 | const inputs = randomInputs( 75 | bFn.littleEndian || base === "ByteConverter", 76 | base === "BasePhi" 77 | ); 78 | 79 | for (const input in inputs.bytes) { 80 | test( 81 | `Iteration ${i} - Encode and decode back for ${base} (type bytes) with input <${input}>`, 82 | randBytesTest, 83 | inputs.bytes[input], 84 | bFn 85 | ); 86 | } 87 | 88 | for (const input in inputs.str) { 89 | test( 90 | `Iteration ${i} - Encode and decode back for ${base} (type string) with input <${input}>`, 91 | baseTest, 92 | inputs.str[input], 93 | null, 94 | bFn, 95 | "str" 96 | ); 97 | } 98 | } 99 | }); 100 | 101 | 102 | for (let radix=2; radix<=62; radix++) { 103 | 104 | const bFn = new BaseEx.SimpleBase(radix); 105 | const inputs = randomInputs(bFn.littleEndian, (radix === 2 || radix === 16)); 106 | 107 | for (const input in inputs.bytes) { 108 | test( 109 | `Iteration ${i} - Encode and decode back for SimpleBase${radix} (type bytes) with input <${input}>`, 110 | randBytesTest, 111 | inputs.bytes[input], 112 | bFn 113 | ); 114 | } 115 | 116 | for (const input in inputs.str) { 117 | test( 118 | `Iteration ${i} - Encode and decode back for SimpleBase${radix} (type string) with input <${input}>`, 119 | baseTest, 120 | inputs.str[input], 121 | null, 122 | bFn, 123 | "str" 124 | ); 125 | } 126 | } 127 | }); 128 | 129 | -------------------------------------------------------------------------------- /test/simple-base.test.js: -------------------------------------------------------------------------------- 1 | import { SimpleBase } from "base-ex"; 2 | import { baseTest } from "./fixtures/helpers.js"; 3 | import test from "ava"; 4 | 5 | /** 6 | * Transpiled python code from an online tutorial 7 | * to have the change to compare bases gt 36 8 | * 9 | * @see: https://www.tutorialexample.com/python-convert-decimal-to-62-base-a-completed-guide-python-tutorial/ 10 | */ 11 | const b62 = { 12 | 13 | charset: [..."0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"], 14 | 15 | divmod: (x, y) => [ BigInt(x) / BigInt(y), BigInt(x) % BigInt(y) ], 16 | 17 | encode: (n, radix) => { 18 | let negative = false; 19 | 20 | if (n < 0) { 21 | n = -n; 22 | negative = true; 23 | } 24 | if (n == 0) { 25 | return 0; 26 | } 27 | const arr = []; 28 | let r; 29 | while (n > 0) { 30 | [n, r] = b62.divmod(n, radix); 31 | arr.unshift(b62.charset[r]); 32 | } 33 | let output = arr.join(""); 34 | if (negative) { 35 | output = `-${output}`; 36 | } 37 | return output; 38 | } 39 | } 40 | 41 | 42 | const Base10 = new SimpleBase(10); 43 | const randInt = (max, min=0) => BigInt(Math.floor(Math.random() * (max - min) + min)); 44 | 45 | const strToBase = (input, encoder) => { 46 | const endianness = (encoder.littleEndian) ? "LE" : "BE"; 47 | const b10Integer = BigInt(Base10.encode(input, endianness)); 48 | const radix = encoder.converter.radix; 49 | 50 | const output = radix > 36 51 | ? b62.encode(b10Integer, radix) 52 | : b10Integer.toString(radix); 53 | 54 | return output; 55 | }; 56 | 57 | for (let radix=2; radix<=62; radix++) { 58 | 59 | const bFn = new SimpleBase(radix); 60 | const base = `Base${radix}`; 61 | 62 | // integers 63 | for (let i=8; i<=1024; i*=2) { 64 | 65 | const n = 2n**BigInt(i); 66 | 67 | for (const signMulti of [1n, -1n]) { 68 | 69 | for (const add of [-randInt(128, 2), -1n, 0n, 1n, randInt(128, 2)]) { 70 | 71 | let input = (n + add) * signMulti; 72 | 73 | if (input <= Number.MAX_SAFE_INTEGER && input >= Number.MIN_SAFE_INTEGER) { 74 | input = Number(input); 75 | } 76 | 77 | const expected = radix > 36 78 | ? b62.encode(input, radix) 79 | : input.toString(radix); 80 | 81 | const numVal = (input < 0) ? "int_n" : "uint_n"; 82 | const title = `En- and decode Simple${base} for type Number/BigInt with input '${input}'`; 83 | 84 | test(title, baseTest, input, expected, bFn, numVal); 85 | } 86 | } 87 | } 88 | 89 | // string 90 | let helloInput = ""; 91 | "Hello World!!!".split("").forEach(c => { 92 | helloInput += c; 93 | const expected = strToBase(helloInput, bFn); 94 | const title = `En- and decode Simple${base} for type String with input '${helloInput}'`; 95 | test(title, baseTest, helloInput, expected, bFn, "str"); 96 | }); 97 | } 98 | -------------------------------------------------------------------------------- /third-party-licenses/BASE2048-LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 qntm 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 | -------------------------------------------------------------------------------- /third-party-licenses/BASE91-LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2000-2006 Joachim Henke 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | - Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | - Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | - Neither the name of Joachim Henke nor the names of his contributors may be 13 | used to endorse or promote products derived from this software without 14 | specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 23 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /third-party-licenses/BIG.JS-LICENCE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | ===================== 3 | 4 | Copyright © `<2022>` `Michael Mclaughlin` 5 | 6 | Permission is hereby granted, free of charge, to any person 7 | obtaining a copy of this software and associated documentation 8 | files (the “Software”), to deal in the Software without 9 | restriction, including without limitation the rights to use, 10 | copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following 13 | conditions: 14 | 15 | The above copyright notice and this permission notice shall be 16 | included in all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, 19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 20 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 22 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 23 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 24 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 25 | OTHER DEALINGS IN THE SOFTWARE. 26 | 27 | -------------------------------------------------------------------------------- /third-party-licenses/ECOJI-LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | --------------------------------------------------------------------------------