9#if !__has_include(<zstd.h>) 
   10#error "Missing <zstd.h> from libzstd-dev, please set CXXFLAGS and LDFLAGS" 
   13#include "external/blake3/c/blake3.h" 
   18is_aiff (
const String &input)
 
   20  return input.
substr (0, 4) == 
"FORM" && input.
substr (8, 4) == 
"AIFF";
 
   24is_wav (
const String &input)
 
   26  return input.
substr (0, 4) == 
"RIFF" && input.
substr (8, 4) == 
"WAVE";
 
   30is_midi (
const String &input)
 
   32  return input.
substr (0, 4) == 
"MThd";
 
   36is_pdf (
const String &input)
 
   38  return input.
substr (0, 5) == 
"%PDF-";
 
   41static constexpr const size_t MB = 1024 * 1024;
 
   42static struct { 
size_t level, 
size; } 
const zstd_adaptive_level[] = {
 
   52guess_zstd_level (
size_t input_size)
 
   55  while (zstd_adaptive_level[zal].size > input_size)
 
   57  return zstd_adaptive_level[zal].level;
 
   61zstd_compress (
const String &input, 
int level)
 
   63  return zstd_compress (input.
data(), input.
size(), level);
 
   67zstd_compress (
const void *src, 
size_t src_size, 
int level)
 
   69  const size_t maxosize = ZSTD_compressBound (src_size);
 
   71  data.resize (maxosize);
 
   72  const size_t osize = ZSTD_compress (&data[0], 
data.size(), src, src_size, level ? level : guess_zstd_level (src_size));
 
   73  if (ZSTD_isError (osize))
 
   75      warning (
"zstd compression failed (input=%zu): %s", src_size, ZSTD_getErrorName (osize));
 
   84zstd_target_size (
const String &input)
 
   86  const size_t maxosize = ZSTD_getFrameContentSize (&input[0], input.
size());
 
   87  if (maxosize == ZSTD_CONTENTSIZE_ERROR)
 
   89  if (maxosize == ZSTD_CONTENTSIZE_UNKNOWN)
 
   91  if (maxosize >= 2 * 1024 * 1024 * 1024ull)
 
   97zstd_uncompress (
const String &input, 
void *dst, 
size_t dst_size)
 
   99  const ssize_t target_size = zstd_target_size (input);
 
  101  assert_return (target_size >= 0 && target_size <= dst_size, -ENOMEM);
 
  102  const size_t osize = ZSTD_decompress (dst, dst_size, input.
data(), input.
size());
 
  108zstd_uncompress (
const String &input)
 
  110  const ssize_t maxosize = zstd_target_size (input);
 
  113  data.resize (maxosize);
 
  114  const size_t osize = ZSTD_decompress (&data[0], 
data.size(), &input[0], input.
size());
 
  115  if (ZSTD_isError (osize))
 
  117      warning (
"zstd decompression failed (input=%zu): %s", input.
size(), ZSTD_getErrorName (osize));
 
  127is_zstd (
const String &input)
 
  129  return (input.
size() >= 4 &&
 
  130          input[0] == 
char (0x28) &&
 
  131          input[1] == 
char (0xb5) &&
 
  132          input[2] == 
char (0x2f) &&
 
  133          input[3] == 
char (0xfd));
 
  137is_lz4 (
const String &input)
 
  139  return (input.
size() >= 4 &&
 
  140          input[0] == 
char (0x04) &&
 
  141          input[1] == 
char (0x22) &&
 
  142          input[2] == 
char (0x4d) &&
 
  143          input[3] == 
char (0x18));
 
  147is_zip (
const String &input)
 
  149  return (input.
size() >= 4 &&
 
  150          input[0] == 
'P' && input[1] == 
'K' &&
 
  151          ((input[2] == 0x03 && input[3] == 0x04) ||
 
  152           (input[2] == 0x05 && input[3] == 0x06) ||
 
  153           (input[2] == 0x07 && input[3] == 0x08)));
 
  157is_arj (
const String &input)
 
  159  return input.
size() >= 2 && input[0] == 
char (0x60) && input[1] == 
char (0xea);
 
  163is_isz (
const String &input)
 
  165  return input.
substr (0, 4) == 
"IsZ!";
 
  169is_ogg (
const String &input)
 
  171  return input.
substr (0, 4) == 
"OggS";
 
  175is_avi (
const String &input)
 
  177  return input.
substr (0, 4) == 
"RIFF" && input.
substr (8, 4) == 
"AVI ";
 
  181is_gz (
const String &input)
 
  183  return input.
size() >= 2 && input[0] == 
char (0x1f) && input[1] == 
char (0x8B);
 
  187is_xz (
const String &input)
 
  189  return (input.
size() >= 6 &&
 
  190          input[0] == 
char (0xfd) &&
 
  191          input[1] == 
char (0x37) &&
 
  192          input[2] == 
char (0x7a) &&
 
  193          input[3] == 
char (0x58) &&
 
  194          input[4] == 
char (0x5a) &&
 
  195          input[5] == 
char (0x00));
 
  199is_png (
const String &input)
 
  201  return (input.
size() >= 8 &&
 
  202          input[0] == 
char (0x89) &&
 
  203          input.
substr (1, 3) == 
"PNG" &&
 
  204          input[4] == 
char (0x0d) &&
 
  205          input[5] == 
char (0x0a) &&
 
  206          input[6] == 
char (0x1a) &&
 
  207          input[7] == 
char (0x0a));
 
  211is_jpg (
const String &input)
 
  213  return (input.
size() >= 4 &&
 
  214          input[0] == 
char (0xff) &&
 
  215          input[1] == 
char (0xd8) &&
 
  216          input[2] == 
char (0xff) &&
 
  217          (input[3] == 
char (0xdb) || input[3] == 
char (0xe0) ||
 
  218           input[3] == 
char (0xee) || input[3] == 
char (0xe1)));
 
  222is_compressed (
const String &input)
 
  224  return (is_zstd (input) ||
 
  239  StreamReaderP istream_;
 
  241  ZSTD_inBuffer zinput_ = { 
nullptr, 0, 0 };
 
  242  ZSTD_DCtx *dctx_ = 
nullptr;
 
  248    name_ = istream_->name();
 
  249    ibuffer_.resize (ZSTD_DStreamInSize());
 
  250    dctx_ = ZSTD_createDCtx();
 
  258  name()
 const override 
  263  read (
void *buffer, 
size_t len)
 override 
  268    if (zinput_.pos < zinput_.size) {
 
  269      ZSTD_outBuffer zoutput = { buffer, len, 0 };
 
  270      ret = ZSTD_decompressStream (dctx_, &zoutput, &zinput_);
 
  271      if (ZSTD_isError (ret))
 
  277    while (zinput_.pos == zinput_.size && istream_) {
 
  278      const ssize_t l = istream_->read (&ibuffer_[0], ibuffer_.size());
 
  280        zinput_ = { &ibuffer_[0], 
size_t (l), 0 };
 
  283      ZSTD_outBuffer zoutput = { buffer, len, 0 };
 
  284      ret = ZSTD_decompressStream (dctx_, &zoutput, &zinput_);
 
  285      if (ZSTD_isError (ret))
 
  291    printerr (
"%s: ZSTD_decompressStream: %s\n", 
program_alias(), ZSTD_getErrorName (ret));
 
  300    const bool closeok = istream_->close();
 
  303    ibuffer_.reserve (0);
 
  305      ZSTD_freeDCtx (dctx_);
 
 
  312stream_reader_zstd (StreamReaderP &istream)
 
  318static constexpr bool PRINT_ADAPTIVE = 
false;
 
  321  StreamWriterP ostream_;
 
  324  ZSTD_CCtx *cctx_ = 
nullptr;
 
  327  bool last_block_ = 
false;
 
  333    obuffer_.reserve (0);
 
  335      ZSTD_freeCCtx (cctx_);
 
  340    obuffer_.resize (ZSTD_CStreamOutSize());
 
  341    cctx_ = ZSTD_createCCtx();
 
  344    pret = ZSTD_CCtx_setParameter (cctx_, ZSTD_c_checksumFlag, 1);
 
  347      while (zstd_adaptive_level[zal_].size < 
std::numeric_limits<
decltype (zstd_adaptive_level[0].size)>::max())
 
  349      pret = ZSTD_CCtx_setParameter (cctx_, ZSTD_c_compressionLevel, level);
 
  350      if (PRINT_ADAPTIVE) printerr (
"ZSTD_compressStream2: fixed level=%u: %s\n", level, ZSTD_getErrorName (pret));
 
  352      pret = ZSTD_CCtx_setParameter (cctx_, ZSTD_c_compressionLevel, zstd_adaptive_level[zal_].level);
 
  353      if (PRINT_ADAPTIVE) printerr (
"ZSTD_compressStream2: size=%u level=%u: %s\n", itotal_, zstd_adaptive_level[zal_].level, ZSTD_getErrorName (pret));
 
  357    name_ = ostream_->name();
 
  360  name()
 const override 
  365  write (
const void *buffer, 
size_t len)
 override 
  369    const ZSTD_EndDirective mode = last_block_ ? ZSTD_e_end : ZSTD_e_continue;
 
  370    ZSTD_inBuffer zinput = { buffer, len, 0 };
 
  372    bool block_finished = 
false;
 
  373    while (!block_finished) {
 
  374      ZSTD_outBuffer zoutput = { &obuffer_[0], obuffer_.size(), 0 };
 
  376      const size_t current_total = itotal_ + zinput.pos;
 
  377      if (!last_block_ && current_total > zstd_adaptive_level[zal_].size)
 
  380          const size_t pret = ZSTD_CCtx_setParameter (cctx_, ZSTD_c_compressionLevel, zstd_adaptive_level[zal_].level);
 
  382          if (PRINT_ADAPTIVE) printerr (
"ZSTD_compressStream2: size=%u level=%u: %s\n", current_total, zstd_adaptive_level[zal_].level, ZSTD_getErrorName (pret));
 
  383          zinput.size = zinput.pos;
 
  384          ret = ZSTD_compressStream2 (cctx_, &zoutput, &zinput, ZSTD_e_end);
 
  388        ret = ZSTD_compressStream2 (cctx_, &zoutput, &zinput, mode);
 
  390      if (ZSTD_isError (ret))
 
  392      const char *p = (
const char*) &obuffer_[0], *
const e = p + zoutput.pos;
 
  394        const ssize_t n = ostream_->write (p, e - p);
 
  399      block_finished = last_block_ ? ret == 0 : zinput.pos == zinput.size;
 
  401    itotal_ += zinput.pos;
 
  404    printerr (
"%s: ZSTD_compressStream2: %s\n", 
program_alias(), ZSTD_getErrorName (ret));
 
  415    bool closedok = 
true;
 
  422          l = write (
nullptr, 0);
 
  425        closedok &= ostream_->close();
 
 
  433stream_writer_zstd (
const StreamWriterP &ostream, 
int level)
 
  440blake3_hash_string (
const String &input)
 
  442  blake3_hasher hasher;
 
  443  blake3_hasher_init (&hasher);
 
  444  blake3_hasher_update (&hasher, input.
data(), input.
size());
 
  445  uint8_t output[BLAKE3_OUT_LEN];
 
  446  blake3_hasher_finalize (&hasher, output, BLAKE3_OUT_LEN);
 
  447  blake3_hasher_reset (&hasher);
 
  448  return String ((
const char*) output, BLAKE3_OUT_LEN);
 
  452blake3_hash_file (
const String &filename)
 
  454  StreamReaderP stream = stream_reader_from_file (filename);
 
  456  blake3_hasher hasher;
 
  457  blake3_hasher_init (&hasher);
 
  459  ssize_t l = stream->read (buffer, 
sizeof (buffer));
 
  461    blake3_hasher_update (&hasher, buffer, l);
 
  462    l = stream->read (buffer, 
sizeof (buffer));
 
  464  uint8_t output[BLAKE3_OUT_LEN];
 
  465  blake3_hasher_finalize (&hasher, output, BLAKE3_OUT_LEN);
 
  466  blake3_hasher_reset (&hasher);
 
  467  return String ((
const char*) output, BLAKE3_OUT_LEN);
 
  480  TCMP (h, ==, 
"af1349b9f5f9a1a6a0404dea36dcc9499bcb25c9adc112b7cc9a93cae41f3262");
 
  482  TASSERT (h == 
"6201e8ededb2f1f2b6362119b46b404e822efbd58d7922202408025c5f527c56");
 
#define assert_return(expr,...)
Return from the current function if expr is unmet and issue an assertion warning.
 
#define return_unless(cond,...)
Return silently if cond does not evaluate to true with return value ...
 
#define TEST_INTEGRITY(FUNC)
Register func as an integrity test.
 
The Anklang C++ API namespace.
 
String string_to_hex(const String &input)
Convert bytes in string input to hexadecimal numbers.
 
String program_alias()
Retrieve the program name as used for logging or debug messages.
 
std::string String
Convenience alias for std::string.
 
uint32_t uint
Provide 'uint' as convenience type.
 
#define TASSERT(cond)
Unconditional test assertion, enters breakpoint if not fullfilled.
 
#define TCMP(a, cmp, b)
Compare a and b according to operator cmp, verbose on failiure.