{"id":13536734,"url":"https://github.com/05nelsonm/encoding","last_synced_at":"2025-09-05T16:32:49.612Z","repository":{"id":39415855,"uuid":"422489504","full_name":"05nelsonm/encoding","owner":"05nelsonm","description":"A Kotlin Multiplatform library for configurable, streamable, efficient and extensible Encoding/Decoding with support for base16/32/64.","archived":false,"fork":false,"pushed_at":"2025-02-14T14:22:18.000Z","size":1373,"stargazers_count":40,"open_issues_count":1,"forks_count":5,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-28T19:02:37.866Z","etag":null,"topics":["base16","base32","base32hex","base64","crockford","crockford-base32","decoding","decoding-library","encoding","encoding-library","kotlin-multiplatform","kotlin-multiplatform-library"],"latest_commit_sha":null,"homepage":"https://encoding.matthewnelson.io/","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/05nelsonm.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-10-29T07:58:49.000Z","updated_at":"2025-04-10T01:11:32.000Z","dependencies_parsed_at":"2024-07-06T07:54:20.628Z","dependency_job_id":"0888ccec-84f7-4cac-a463-4ad77f7e323c","html_url":"https://github.com/05nelsonm/encoding","commit_stats":{"total_commits":136,"total_committers":2,"mean_commits":68.0,"dds":0.007352941176470562,"last_synced_commit":"04062dabb25e2530e2560ffc44992b1984069d69"},"previous_names":["05nelsonm/component-encoding"],"tags_count":19,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/05nelsonm%2Fencoding","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/05nelsonm%2Fencoding/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/05nelsonm%2Fencoding/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/05nelsonm%2Fencoding/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/05nelsonm","download_url":"https://codeload.github.com/05nelsonm/encoding/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253164285,"owners_count":21864227,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["base16","base32","base32hex","base64","crockford","crockford-base32","decoding","decoding-library","encoding","encoding-library","kotlin-multiplatform","kotlin-multiplatform-library"],"created_at":"2024-08-01T09:00:48.280Z","updated_at":"2025-05-08T23:33:58.483Z","avatar_url":"https://github.com/05nelsonm.png","language":"Kotlin","readme":"# encoding\n[![badge-license]][url-license]\n[![badge-latest]][url-latest]\n\n[![badge-kotlin]][url-kotlin]\n\n![badge-platform-android]\n![badge-platform-jvm]\n![badge-platform-js]\n![badge-platform-js-node]\n![badge-platform-wasm]\n![badge-platform-linux]\n![badge-platform-macos]\n![badge-platform-ios]\n![badge-platform-tvos]\n![badge-platform-watchos]\n![badge-platform-windows]\n![badge-support-android-native]\n![badge-support-apple-silicon]\n![badge-support-js-ir]\n![badge-support-linux-arm]\n\nConfigurable, streamable, efficient and extensible Encoding/Decoding for Kotlin Multiplatform.\n\nAPI docs available at [https://encoding.matthewnelson.io][url-docs]\n\n**Base16 (a.k.a. \"hex\")**\n - [RFC 4648 section 8][url-rfc-s8]\n\n**Base32**\n - [Crockford][url-crockford]\n - Default [RFC 4648 section 6][url-rfc-s6]\n - Hex [RFC 4648 section 7][url-rfc-s7]\n\n**Base64**\n - Default [RFC 4648 section 4][url-rfc-s4]\n - UrlSafe [RFC 4648 section 5][url-rfc-s5]\n\n### Usage\n\n**Configure `EncoderDecoder`(s) to your needs**\n\n```kotlin\nval base16 = Base16 {\n    // Ignore whitespace and new lines when decoding\n    isLenient = true\n\n    // Insert line breaks every X characters of encoded output\n    lineBreakInterval = 10\n\n    // Use lowercase instead of uppercase characters when encoding\n    encodeToLowercase = true\n}\n\n// Shortcuts\nval base16StrictSettings = Base16(strict = true)\nval base16DefaultSettings = Base16()\n\n// Alternatively, use the static instance with its default settings\nBase16\n```\n\n```kotlin\nval base32Crockford = Base32Crockford {\n    isLenient = true\n    encodeToLowercase = false\n\n    // Insert hyphens every X characters of encoded output\n    hyphenInterval = 5\n\n    // Optional data integrity check unique to the Crockford spec\n    checkSymbol('*')\n\n    // Only apply the checkSymbol \u0026 reset hyphen interval counter\n    // when Encoder.Feed.doFinal is called (see builder docs for\n    // more info) \n    finalizeWhenFlushed = false\n}\n\n// Alternatively, use the static instance with its default settings\nBase32.Crockford\n\nval base32Default = Base32Default {\n    isLenient = true\n    lineBreakInterval = 64\n    encodeToLowercase = true\n    \n    // Skip padding of the encoded output\n    padEncoded = false\n}\n\n// Alternatively, use the static instance with its default settings\nBase32.Default\n\nval base32Hex = Base32Hex {\n    isLenient = true\n    lineBreakInterval = 64\n    encodeToLowercase = false\n    padEncoded = true\n}\n\n// Alternatively, use the static instance with its default settings\nBase32.Hex\n```\n\n```kotlin\n// NOTE: Base64 can _decode_ both Default and UrlSafe, no matter what\n// encodeToUrlSafe is set to.\nval base64 = Base64 {\n    isLenient = true\n    lineBreakInterval = 64\n    encodeToUrlSafe = false\n    padEncoded = true\n}\n\n// Alternatively, use the static instance with its default settings\nBase64.Default\n\n// Inherit settings from another EncoderDecoder's Config\nval base64UrlSafe = Base64(base64.config) {\n    encodeToUrlSafe = true\n    padEncoded = false\n}\n\n// Alternatively, use the static instance with its default settings\nBase64.UrlSafe\n```\n\n**Encoding/Decoding Extension Functions**\n\n```kotlin\nval text = \"Hello World!\"\nval bytes = text.encodeToByteArray()\n\n// Choose the output type that suits your needs\n// without having to perform unnecessary intermediate\n// transformations (can be useful for security \n// purposes, too, as you are able to clear Arrays\n// before they are de-referenced).\nval encodedString = bytes.encodeToString(Base64.Default)\nval encodedChars = bytes.encodeToCharArray(Base32.Default)\n\nval decodedString = try {\n    encodedString.decodeToByteArray(Base64.Default)\n} catch (e: EncodingException) {\n    Log.e(\"Something went terribly wrong\", e)\n    null\n}\n// Swallow `EncodingException`s by using the `*OrNull` variants\nval decodedChars = encodedChars.decodeToByteArrayOrNull(Base32.Default)\n```\n\n**Encoding/Decoding `Feed`(s) (i.e. Streaming)**\n\n`Feed`'s are a new concept which enable some pretty awesome things. They break \nthe encoding/decoding process into its individual parts, such that the medium \nfor which data is coming from or going to can be **anything**; `Feed`'s only \ncare about `Byte`(s) and `Char`(s)!\n\n```kotlin\n// e.g. Concatenate multiple encodings\nval sb = StringBuilder()\n\n// Use our own line break out feed in order to add a delimiter between\n// encodings and preserve the counter.\nval out = LineBreakOutFeed(interval = 64) { char -\u003e sb.append(char) }\n\nBase64.Default.newEncoderFeed(out).use { feed -\u003e\n    \"Hello World 1!\".encodeToByteArray().forEach { b -\u003e feed.consume(b)  }\n    feed.flush()\n    out.output('.')\n    \"Hello World 2!\".encodeToByteArray().forEach { b -\u003e feed.consume(b)  }\n}\n\nprintln(sb.toString())\n// SGVsbG8gV29ybGQgMSE=.SGVsbG8gV29ybGQgMiE=\n```\n\n```kotlin\n// e.g. Writing encoded data to a File in Java.\n// NOTE: try/catch omitted for this example.\n\nfile.outputStream().use { oStream -\u003e\n    Base64.Default.newEncoderFeed { encodedChar -\u003e\n        // As encoded data comes out of the feed,\n        // write it to the file.\n        oStream.write(encodedChar.code)\n    }.use { feed -\u003e\n\n        // Push data through the feed.\n        //\n        // There are NO size/length limitations with `Feed`s.\n        // You are only limited by the medium you use to store\n        // the output (e.g. the maximum size of a ByteArray is\n        // Int.MAX_VALUE).\n        //\n        // The `Feed.use` extension function calls `doFinal`\n        // automatically, which closes the `Encoder.Feed`\n        // and performs finalization of the operation (such as\n        // adding padding).\n        \"Hello World!\".encodeToByteArray().forEach { b -\u003e\n            feed.consume(b)\n        }\n    }\n}\n```\n\nAs `Feed`(s) is a new concept, they can be \"bulky\" to use (as you will see in \nthe example below). This is due to a lack of extension functions for them, but \nit's something I hope can be built out over time with your help (PRs and \nFeatureRequests are **always** welcome)!\n\n```kotlin\n// e.g. Reading encoded data from a File in Java.\n// NOTE: try/catch omitted for this example.\n\n// Pre-calculate the output size for the given encoding\n// spec; in this case, Base64.\nval size = Base64.Default.config.decodeOutMaxSize(file.length())\n\n// Since we will be storing the data in a StringBuilder,\n// we need to check if the output size would exceed\n// StringBuilder's maximum capacity.\nif (size \u003e Int.MAX_VALUE.toLong()) {\n    // Alternatively, one could fall back to chunking, but that\n    // is beyond the scope of this example.\n    throw EncodingSizeException(\n        \"File contents would be too large after decoding to store in a StringBuilder\"\n    )\n}\n\nval sb = StringBuilder(size.toInt())\n\nfile.inputStream().reader().use { iStreamReader -\u003e\n    Base64.Default.newDecoderFeed { decodedByte -\u003e\n        // As decoded data comes out of the feed,\n        // update the StringBuilder.\n        sb.append(decodedByte.toInt().toChar())\n    }.use { feed -\u003e\n\n        val buffer = CharArray(4096)\n        while (true) {\n            val read = iStreamReader.read(buffer)\n            if (read == -1) break\n            \n            // Push encoded data from the file through the feed.\n            //\n            // The `Feed.use` extension function calls `doFinal`\n            // automatically, which closes the `Decoder.Feed`\n            // and performs finalization of the operation.\n            for (i in 0 until read) {\n                feed.consume(buffer[i])\n            }\n        }\n    }\n}\n\nprintln(sb.toString())\n```\n\n**Alternatively, create your own `EncoderDecoder`(s) using the abstractions provided by `encoding-core`**\n\n### Sample\n\nSee [sample project](sample/README.md)\n\n### Get Started\n\n\u003c!-- TAG_VERSION --\u003e\n\n```kotlin\n// build.gradle.kts\ndependencies {\n    val encoding = \"2.4.0\"\n    implementation(\"io.matthewnelson.encoding:base16:$encoding\")\n    implementation(\"io.matthewnelson.encoding:base32:$encoding\")\n    implementation(\"io.matthewnelson.encoding:base64:$encoding\")\n\n    // Only necessary if you just want the abstractions to create your own EncoderDecoder(s)\n    implementation(\"io.matthewnelson.encoding:core:$encoding\")\n}\n```\n\n\u003c!-- TAG_VERSION --\u003e\nAlternatively, you can use the BOM.\n\n```kotlin\n// build.gradle.kts\ndependencies {\n    // define the BOM and its version\n    implementation(platform(\"io.matthewnelson.encoding:bom:2.4.0\"))\n\n    // define artifacts without version\n    implementation(\"io.matthewnelson.encoding:base16\")\n    implementation(\"io.matthewnelson.encoding:base32\")\n    implementation(\"io.matthewnelson.encoding:base64\")\n\n    // Only necessary if you just want the abstractions to create your own EncoderDecoder(s)\n    implementation(\"io.matthewnelson.encoding:core\")\n}\n```\n\n\u003c!-- TAG_VERSION --\u003e\n[badge-latest]: https://img.shields.io/badge/latest--release-2.4.0-blue.svg?style=flat\n[badge-license]: https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg?style=flat\n\n\u003c!-- TAG_DEPENDENCIES --\u003e\n[badge-kotlin]: https://img.shields.io/badge/kotlin-2.1.10-blue.svg?logo=kotlin\n\n\u003c!-- TAG_PLATFORMS --\u003e\n[badge-platform-android]: http://img.shields.io/badge/-android-6EDB8D.svg?style=flat\n[badge-platform-jvm]: http://img.shields.io/badge/-jvm-DB413D.svg?style=flat\n[badge-platform-js]: http://img.shields.io/badge/-js-F8DB5D.svg?style=flat\n[badge-platform-js-node]: https://img.shields.io/badge/-nodejs-68a063.svg?style=flat\n[badge-platform-linux]: http://img.shields.io/badge/-linux-2D3F6C.svg?style=flat\n[badge-platform-macos]: http://img.shields.io/badge/-macos-111111.svg?style=flat\n[badge-platform-ios]: http://img.shields.io/badge/-ios-CDCDCD.svg?style=flat\n[badge-platform-tvos]: http://img.shields.io/badge/-tvos-808080.svg?style=flat\n[badge-platform-watchos]: http://img.shields.io/badge/-watchos-C0C0C0.svg?style=flat\n[badge-platform-wasm]: https://img.shields.io/badge/-wasm-624FE8.svg?style=flat\n[badge-platform-windows]: http://img.shields.io/badge/-windows-4D76CD.svg?style=flat\n[badge-support-android-native]: http://img.shields.io/badge/support-[AndroidNative]-6EDB8D.svg?style=flat\n[badge-support-apple-silicon]: http://img.shields.io/badge/support-[AppleSilicon]-43BBFF.svg?style=flat\n[badge-support-js-ir]: https://img.shields.io/badge/support-[js--IR]-AAC4E0.svg?style=flat\n[badge-support-linux-arm]: http://img.shields.io/badge/support-[LinuxArm]-2D3F6C.svg?style=flat\n\n[url-crockford]: https://www.crockford.com/base32.html\n[url-docs]: https://encoding.matthewnelson.io\n[url-kotlin]: https://kotlinlang.org\n[url-latest]: https://github.com/05nelsonm/encoding/releases/latest\n[url-license]: https://www.apache.org/licenses/LICENSE-2.0.txt\n[url-rfc-s4]: https://www.ietf.org/rfc/rfc4648.html#section-4\n[url-rfc-s5]: https://www.ietf.org/rfc/rfc4648.html#section-5\n[url-rfc-s6]: https://www.ietf.org/rfc/rfc4648.html#section-6\n[url-rfc-s7]: https://www.ietf.org/rfc/rfc4648.html#section-7\n[url-rfc-s8]: https://www.ietf.org/rfc/rfc4648.html#section-8\n","funding_links":[],"categories":["Libraries"],"sub_categories":["Serializer"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F05nelsonm%2Fencoding","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F05nelsonm%2Fencoding","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F05nelsonm%2Fencoding/lists"}