{
bool keep_going;
bool short_format;
- bool base64;
+ int base_enc;
bool lower_case;
bool benchmark;
}
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);
}
/*
+ * 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)
}
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")))
{
++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;
}
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
}
/*
+ * 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)
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;
/*
* 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]]++;
/*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)
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();
+}
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*/