OSDN Git Service

Added support for Base85 (Ascii85) encoding.
authorLoRd_MuldeR <mulder2@gmx.de>
Sat, 15 Feb 2020 15:40:59 +0000 (16:40 +0100)
committerLoRd_MuldeR <mulder2@gmx.de>
Sun, 16 Feb 2020 20:39:30 +0000 (21:39 +0100)
frontend/src/common.h
frontend/src/main.cpp
frontend/src/self_test.cpp
frontend/src/utils.cpp
frontend/src/utils.h

index df3eef3..4bed96b 100644 (file)
@@ -71,7 +71,7 @@ typedef struct
 {
        bool keep_going;
        bool short_format;
-       bool base64;
+       int  base_enc;
        bool lower_case;
        bool benchmark;
 }
index f6a288d..122ce8e 100644 (file)
@@ -97,6 +97,7 @@ static void print_manpage(const CHAR_T *const argv0)
        FPUTS(STR("   --short       Print the digest in short format (no file names)\n"), stderr);
        FPUTS(STR("   --lower-case  Print the digest in lower-case letters (default: upper-case)\n"), stderr);
        FPUTS(STR("   --base64      Print the digest in Base64 format (default: Hex format)\n"), stderr);
+       FPUTS(STR("   --base85      Print the digest in Base85 format (default: Hex format)\n"), stderr);
        FPUTS(STR("   --help        Print help screen and exit\n"), stderr);
        FPUTS(STR("   --version     Print program version and exit\n"), stderr);
        FPUTS(STR("   --self-test   Run self-test and exit\n"), stderr);
@@ -106,6 +107,21 @@ static void print_manpage(const CHAR_T *const argv0)
 }
 
 /*
+ * Encode digest string
+ */
+static std::string encode_digest(const uint8_t *const digest, const options_t &options)
+{
+       if (options.base_enc)
+       {
+               return ((options.base_enc > 1U) ? bytes_to_base85(digest, MHASH384_SIZE) : bytes_to_base64(digest, MHASH384_SIZE));
+       }
+       else
+       {
+               return bytes_to_hex(digest, MHASH384_SIZE, options.lower_case);
+       }
+}
+
+/*
  * Parse command-line options
  */
 static opmode_t parse_options(int &arg_offset, options_t &options, const int argc, const CHAR_T *const *const argv)
@@ -131,7 +147,11 @@ static opmode_t parse_options(int &arg_offset, options_t &options, const int arg
                }
                else if (!STRICMP(argstr, STR("base64")))
                {
-                       options.base64 = true;
+                       options.base_enc = (options.base_enc != 1) ? (options.base_enc + 1) : options.base_enc;
+               }
+               else if (!STRICMP(argstr, STR("base85")))
+               {
+                       options.base_enc = (options.base_enc != 2) ? (options.base_enc + 2) : options.base_enc;
                }
                else if(!STRICMP(argstr, STR("lower-case")))
                {
@@ -168,10 +188,17 @@ static opmode_t parse_options(int &arg_offset, options_t &options, const int arg
                ++arg_offset;
        }
 
-       if (options.base64 && options.lower_case)
+       if (options.base_enc > 2)
+       {
+               print_logo();
+               FPUTS(STR("Error: Options \"--base64\" and \"--base85\" are mutually exclusive!\n"), stderr);
+               fflush(stderr);
+               return MODE_UNKNOWN;
+       }
+       else if (options.base_enc && options.lower_case)
        {
                print_logo();
-               FPUTS(STR("Error: Options \"--base64\" and \"--lower-case\" are mutually exclusive!\n"), stderr);
+               FPRINTF(stderr, STR("Error: Options \"--%") PRI_CHAR STR("\" and \"--lower-case\" are mutually exclusive!\n"), (options.base_enc > 1U) ? STR("base85") : STR("base64"));
                fflush(stderr);
                return MODE_UNKNOWN;
        }
@@ -230,10 +257,9 @@ static bool process_file(const CHAR_T *const file_name, const options_t options)
        if(!ferror(input))
        {
                const uint8_t *const digest = mhash384.finish();
-               const std::string string = options.base64 ? bytes_to_base64(digest, MHASH384_SIZE) : bytes_to_hex(digest, MHASH384_SIZE, options.lower_case);
                const CHAR_T *const source_name = file_name ? file_name : STR("-");
                const CHAR_T *const format = options.short_format ? STR("%") PRI_char STR("\n") : STR("%") PRI_char STR("  %") PRI_CHAR STR("\n");
-               FPRINTF(stdout, format, string.c_str(), source_name);
+               FPRINTF(stdout, format, encode_digest(digest, options).c_str(), source_name);
                fflush(stdout);
        }
        else
index 4c384e8..bc3a1ee 100644 (file)
@@ -154,6 +154,21 @@ static bool read_line(FILE *const input, char *const line, const int max_count,
 }
 
 /*
+ * Encode digest string
+ */
+static std::string encode_digest(const uint8_t *const digest, const options_t &options)
+{
+       if (options.base_enc)
+       {
+               return ((options.base_enc > 1U) ? bytes_to_base85(digest, MHASH384_SIZE) : bytes_to_base64(digest, MHASH384_SIZE));
+       }
+       else
+       {
+               return bytes_to_hex(digest, MHASH384_SIZE, options.lower_case);
+       }
+}
+
+/*
  * Compute hash and compare against reference
  */
 static bool test_string(const uint32_t count, const char *const text, const uint8_t *const expected, const options_t &options)
@@ -167,9 +182,7 @@ static bool test_string(const uint32_t count, const char *const text, const uint
        const uint8_t *const digest = mhash384.finish();
        const bool success = (!memcmp(digest, expected, MHASH384_SIZE));
 
-       const std::string string = options.base64 ? bytes_to_base64(digest, MHASH384_SIZE) : bytes_to_hex(digest, MHASH384_SIZE, options.lower_case);
-       const CHAR_T *const result = success ? STR("OK") : STR("Error!");
-       FPRINTF(stderr, STR("%") PRI_char STR(" - %") PRI_CHAR STR("\n"), string.c_str(), result);
+       FPRINTF(stderr, STR("%") PRI_char STR(" - %") PRI_CHAR STR("\n"), encode_digest(digest, options).c_str(), success ? STR("OK") : STR("Error!"));
        
        fflush(stderr);
        return success;
@@ -178,14 +191,12 @@ static bool test_string(const uint32_t count, const char *const text, const uint
 /*
  * Compute hash and append to hashset
  */
-static bool append_string(UnorderedHashSet &hash_set, std::vector<std::array<uint64_t,256U>> &stats, const char *const text, const bool base64, const bool lower_case)
+static bool append_string(UnorderedHashSet &hash_set, std::vector<std::array<uint64_t,256U>> &stats, const char *const text, const options_t &options)
 {
        std::array<uint8_t, MHASH384_SIZE> digest;
        mhash384_compute(digest.data(), reinterpret_cast<const uint8_t*>(text), strlen(text));
 
-       const std::string string = base64 ? bytes_to_base64(digest.data(), MHASH384_SIZE) : bytes_to_hex(digest.data(), MHASH384_SIZE, lower_case);
-       FPRINTF(stderr, STR("%") PRI_char STR("\n"), string.c_str());
-       
+       FPRINTF(stderr, STR("%") PRI_char STR("\n"), encode_digest(digest.data(), options).c_str());
        for(size_t i = 0U; i < MHASH384_SIZE; ++i)
        {
                stats[i][digest[i]]++;
@@ -263,7 +274,7 @@ bool stress_test(const CHAR_T *const file_name, const options_t &options)
                /*FPRINTF(stderr, STR("\"%") PRI_char STR("\"\n"), line);*/
                if(line[0U])
                {
-                       if(!append_string(hash_set, stats, line, options.base64, options.lower_case))
+                       if(!append_string(hash_set, stats, line, options))
                        {
                                success = false;
                                if(!options.keep_going)
index 9a50db2..ec7cbc3 100644 (file)
@@ -96,3 +96,67 @@ std::string bytes_to_base64(const uint8_t *const data, const size_t len)
 
        return result.str();
 }
+
+/*
+ * Convert byte array to Base85-string
+ * implementation based on code created by Doug Currie <https://github.com/dcurrie/ascii85>
+ */
+std::string bytes_to_base85(const uint8_t *const data, const size_t len)
+{
+       static const char BASE_CHAR = '!';
+
+       size_t pos = 0U;
+       std::ostringstream result;
+       char temp[6U];
+       memset(temp, 0, sizeof(char) * 6U);
+
+       while (pos < len)
+       {
+               uint32_t chunk;
+               size_t n = len - pos;
+
+               if (n >= 4U)
+               {
+                       chunk  = (((uint32_t)data[pos++]) << 24U);
+                       chunk |= (((uint32_t)data[pos++]) << 16U);
+                       chunk |= (((uint32_t)data[pos++]) <<  8U);
+                       chunk |= (((uint32_t)data[pos++]));
+               }
+               else
+               {
+                       chunk = (((uint32_t)data[pos++]) << 24U);
+                       if (pos < len)
+                       {
+                               chunk |= (((uint32_t)data[pos++]) << 16U);
+                               if (pos < len)
+                               {
+                                       chunk |= (((uint32_t)data[pos++]) << 8U);
+                                       if (pos < len)
+                                       {
+                                               chunk |= (((uint32_t)data[pos++]));
+                                       }
+                               }
+                       }
+               }
+
+               if(chunk || (n < 4U))
+               {
+                       temp[4U] = ((char)(BASE_CHAR + (chunk % 85U)));
+                       chunk /= 85U;
+                       temp[3U] = ((char)(BASE_CHAR + (chunk % 85U)));
+                       chunk /= 85U;
+                       temp[2U] = ((char)(BASE_CHAR + (chunk % 85U)));
+                       chunk /= 85U;
+                       temp[1U] = ((char)(BASE_CHAR + (chunk % 85U)));
+                       chunk /= 85U;
+                       temp[0U] = ((char)(BASE_CHAR + chunk));
+                       result << temp;
+               }
+               else
+               {
+                       result << 'z'; /*encode z for zero*/
+               }
+       }
+
+       return result.str();
+}
index ae48810..dbaec7a 100644 (file)
@@ -29,5 +29,6 @@
 const CHAR_T * get_basename(const CHAR_T *const path);
 std::string bytes_to_hex(const uint8_t *const data, const size_t len, const bool lower_case);
 std::string bytes_to_base64(const uint8_t *const data, const size_t len);
+std::string bytes_to_base85(const uint8_t *const data, const size_t len);
 
 #endif /*INC_MHASH384_UTILS_H*/