From c74c02027ef2cab13ba72409cbfbb5f95862f7d0 Mon Sep 17 00:00:00 2001 From: dd86k Date: Sun, 15 Jan 2023 18:01:26 -0500 Subject: [PATCH] INITIATION --- .gitignore | 20 +++++ LICENSE | 32 +++++++ README.md | 44 +++++++++ dub.sdl | 7 ++ source/binco.d | 237 +++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 340 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 dub.sdl create mode 100644 source/binco.d diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..572a22c --- /dev/null +++ b/.gitignore @@ -0,0 +1,20 @@ +.dub +docs.json +dub.selections.json +__dummy.html +docs/ +/binco +binco.so +binco.dylib +binco.dll +binco.a +binco.lib +binco.pdb +binco-test-* +*.exe +*.o +*.obj +*.lst +*.exe +*.xz +*.gz \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..ffe4c0b --- /dev/null +++ b/LICENSE @@ -0,0 +1,32 @@ +The Clear BSD License + +Copyright (c) 2023 dd86k +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted (subject to the limitations in the disclaimer +below) provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY +THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..1188111 --- /dev/null +++ b/README.md @@ -0,0 +1,44 @@ +# Binco: Binary Encoder/Decoder + +Something I made quick for myself. + +# Usage + +First, you need to specify `-e|--encode` or `-d|--decode` to select an +operation mode, then add the format to use (e.g., `-e base64`). + +By default, stdin and stdout streams are used for input and output. + +To specify a file input, use `-i|--input`. And file output, use `-o|--output`. + +Encode file and show result to stdout: +```text +$ binco -e base64 -i dub.sdl +bmFtZSAiYmluY28iCmRlc2NyaXB0aW9uICJCaW5hcnkgRW5jb2Rlci9EZWNvZGVyIgphdXRob3Jz +ICJkZDg2ayA8ZGRAZGF4Lm1vZT4iCmNvcHlyaWdodCAiQ29weXJpZ2h0IMKpIDIwMjMsIGRkODZr +IDxkZEBkYXgubW9lPiIKbGljZW5zZSAiQlNELTMtQ2xhdXNlIgoKdGFyZ2V0VHlwZSAiZXhlY3V0 +YWJsZSI= +``` + +Encode stream to base64: +```text +$ echo 123 | binco -e base64 +MTIzIA0K +``` + +Decode file to another file: +```text +$ binco -d base64 -i example.txt -o example.exe +``` + +# Limitations + +## Only Base64 (for now) + +I need to create a wrapper for encoders/decoders before adding other binary +formats. + +## Newlines + +Currently, due to a limitation to `File.byLine`, only the `\n` line terminator +is understood by the decoder. \ No newline at end of file diff --git a/dub.sdl b/dub.sdl new file mode 100644 index 0000000..489e050 --- /dev/null +++ b/dub.sdl @@ -0,0 +1,7 @@ +name "binco" +description "Binary Encoder/Decoder" +authors "dd86k " +copyright "Copyright © 2023, dd86k " +license "BSD-3-Clause-Clear" + +targetType "executable" \ No newline at end of file diff --git a/source/binco.d b/source/binco.d new file mode 100644 index 0000000..7719bf5 --- /dev/null +++ b/source/binco.d @@ -0,0 +1,237 @@ +/// Command-line interface and application. +/// +/// Authors: dd86k +/// Copyright: dd86k +/// License: BSD-3-Clause-Clear +module binco; + +import std.stdio; +import std.getopt; +import core.stdc.stdlib : exit; +import std.base64; +/*static import std.file; +import std.algorithm : chunkBy; +import std.string : lineSplitter; + +alias readAll = std.file.read; +alias readAllText = std.file.readText; +alias writeAll = std.file.write;*/ + +enum Version = "0.0.1"; +enum Desc = "binco "~Version~" (built: "~__TIMESTAMP__~")"; +enum Copyright = "Copyright (c) 2023 dd86k "; + +enum Base +{ + none, + //base16, + //base32, + //base32z, + //base36, + //base58, + base64, + //base64url, + //ascii85 + //base91 + //bson +} + +__gshared int setting_columns = 76; /// Columns before newline + +File fileOpen(string path, string mode) +{ + File file; + + try + { + file.open(path, mode); + } + catch (Exception ex) + { + stderr.writefln("error: %s", ex.message); + exit(5); + } + + return file; +} + +const(char)[] encode64(ubyte[] data) +{ + return Base64.encode(data); +} + +const(char)[] encode(Base base, ubyte[] data) +{ + return encode64(data); +} + +immutable string page_secret = q"SECRET +The year is 2032, + + And you received your DNA results. + + +- The part that enjoys ASCII art. + v + oo OO oo OO oo + ||o O||O o||o O||O o|| + |||O||||O||||O||||O||| + ||O o||o O||O o||o O|| + OO oo OO oo OO +SECRET"; + +immutable string page_version = + Desc~"\n"~ + Copyright~"\n"~ + "License: BSD-3-Clause-Clear \n"~ + "Homepage: "; + +immutable string page_license = q"LICENSE +The Clear BSD License + +LICENSE"~Copyright~q"LICENSE + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted (subject to the limitations in the disclaimer +below) provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY +THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +LICENSE"; + +int main(string[] args) +{ + import std.traits : EnumMembers; + + string pathIn, pathOut; + Base encodeBase, decodeBase; + + try + { + bool noarg = args.length == 1; + + GetoptResult res = getopt(args, config.caseSensitive, + "tmp000", "", { + writeln(page_secret); + exit(0); + }, + "cols", "Line length when encoding", &setting_columns, + "e|encode", "Select encoding mode and format", &encodeBase, + "d|decode", "Select decoding mode and format", &decodeBase, + "i|input", "File input (default: stdin)", &pathIn, + "o|output", "File output (default: stdout)", &pathOut, + "list", "List available formats", { + writeln("Formats available:"); + foreach (member; EnumMembers!Base[1..$]) + writeln(member); + exit(0); + }, + "version", "Show software version page", { + writeln(page_version); + exit(0); + }, + "ver", "Show software version", { + writeln(Version); + exit(0); + }, + "license", "Show software license", { + writeln(page_license); + exit(0); + }, + ); + + if (res.helpWanted || noarg) + { + writeln( + "Binary-Text Encoder/Decoder\n"~ + "\n"~ + "OPTIONS" + ); + res.options[$-1].help = "Show this help page and quit."; + foreach (Option opt; res.options[1..$]) + { + with (opt) + if (optShort) + writefln("%s, %-12s %s", optShort, optLong, help); + else + writefln(" %-12s %s", optLong, help); + } + writeln("\nThis program has {{todo}}."); + return 0; + } + } + catch (Exception ex) + { + stderr.writefln("error: %s", ex.message); + return 1; + } + + if (encodeBase == Base.none && decodeBase == Base.none) + { + stderr.writeln("error: Encoding or decoding base not selected"); + return 2; + } + + bool toencode = encodeBase != Base.none; + bool todecode = decodeBase != Base.none; + + if (toencode && todecode) + { + stderr.writeln("error: Cannot encode and decode at the same time"); + return 3; + } + + setting_columns = cast(int)(setting_columns / 1.33333f); + + File fileIn = pathIn ? fileOpen(pathIn, "rb") : stdin; + File fileOut = pathOut ? fileOpen(pathOut, "wb") : stdout; + + try + { + if (toencode) + { + foreach (encoded; Base64.encoder(fileIn.byChunk(setting_columns))) + { + fileOut.write(encoded); + //fileOut.write("\r\n"); + fileOut.write('\n'); + } + } + else + { + foreach (decoded; Base64.decoder(fileIn.byLine())) + { + fileOut.rawWrite(decoded); + } + } + } + catch (Exception ex) + { + stderr.writefln("error: %s", ex.message); + exit(6); + } + + return 0; +}