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;
+}