Example #1
0
static MSCompFlush
squash_ms_comp_flush_from_operation (SquashOperation operation) {
  switch (operation) {
    case SQUASH_OPERATION_PROCESS:
      return MSCOMP_NO_FLUSH;
    case SQUASH_OPERATION_FLUSH:
      return MSCOMP_FLUSH;
    case SQUASH_OPERATION_FINISH:
      return MSCOMP_FINISH;
    case SQUASH_OPERATION_TERMINATE:
      squash_assert_unreachable ();
  }
  squash_assert_unreachable();
}
Example #2
0
static void
squash_brotli_stream_init (SquashBrotliStream* s,
                           SquashCodec* codec,
                           SquashStreamType stream_type,
                           SquashOptions* options,
                           SquashDestroyNotify destroy_notify) {
  SquashStream* stream = (SquashStream*) s;
  squash_stream_init (stream, codec, stream_type, (SquashOptions*) options, destroy_notify);

  s->finished = false;
  if (stream_type == SQUASH_STREAM_COMPRESS) {
    brotli::BrotliParams params;
    params.quality = squash_options_get_int_at (stream->options, stream->codec, SQUASH_BROTLI_OPT_LEVEL);
    params.mode = (brotli::BrotliParams::Mode) squash_options_get_int_at (stream->options, stream->codec, SQUASH_BROTLI_OPT_MODE);
    s->compressor = new brotli::BrotliCompressor (params);
    s->remaining_block_in = s->compressor->input_block_size();
    s->remaining_out = 0;
    s->next_out = NULL;
    s->should_flush = false;
    s->should_seal = false;
  } else if (stream_type == SQUASH_STREAM_DECOMPRESS) {
    s->decompressor = BrotliCreateState(squash_brotli_malloc, squash_brotli_free, squash_codec_get_context (codec));
  } else {
    squash_assert_unreachable();
  }
}
Example #3
0
/**
 * Allocate an aligned buffer
 *
 * Memory allocated with this function is assumed not to support
 * reallocation.  In reality, assuming nobody has installed thick
 * wrappers it should be possible to @ref squash_realloc the buffer,
 * but the result is not constrained to the alignment requirements
 * presented to the initial buffer.
 *
 * The value returned by this function must be freed with @ref
 * squash_aligned_free; While some implementations (such as C11's
 * aligned_alloc and the POSIX posix_memalign function) allow values
 * returned by @ref squash_aligned_alloc to be passed directly to
 * @ref squash_free, others (such as Windows' _aligned_malloc) do not.
 * Passing the result of this function to @ref squash_free is
 * considered undefined behavior.
 *
 * @note Values supported for the @a alignment parameter are
 * implementation defined, but a fair assumption is that they must be
 * a power of two and multiple of `sizeof(void*)`.
 *
 * @param ctx The context
 * @param alignment Alignment of the buffer
 * @param size Number of bytes to allocate
 */
void*
squash_aligned_alloc (size_t alignment, size_t size) {
  if (squash_memfns.aligned_alloc != NULL) {
    return squash_memfns.aligned_alloc (alignment, size);
  } else {
    /* This code is only used when people provide custom memory
     * functions but don't bother providing aligned versions.  AFAIK
     * all systems provide a way to get aligned memory, so this
     * shouldn't really be necessary unless you're writing your own
     * malloc implementations (e.g., to track memory usage), or using
     * something weird (PHP's emalloc, Python's PyMem_Malloc, etc.).
     *
     * Note that this function will call squash_malloc() with a much
     * larger buffer than is necessary.  If you have a problem with
     * that then feel free to provide your own aligned_alloc
     * implementation. */

    const size_t ms = size + alignment + sizeof(void*);
    const void* ptr = squash_memfns.malloc (ms);
    const uintptr_t addr = (uintptr_t) ptr;

    /* Figure out where to put the object.  We want a pointer to the
       real allocation to immediately precede the object (so we can
       recover it later to pass to free()/ */
    size_t padding = alignment - (addr % alignment);
    if (padding < sizeof(void*))
      padding += alignment;
    assert ((padding + size) <= ms);

    memcpy ((void*) (addr + padding - sizeof(void*)), &ptr, sizeof(void*));
    return (void*) (addr + padding);
  }

  squash_assert_unreachable ();
}
Example #4
0
static SquashBZ2Stream*
squash_bz2_stream_new (SquashCodec* codec, SquashStreamType stream_type, SquashOptions* options) {
  int bz2_e = 0;
  SquashBZ2Stream* stream;

  assert (codec != NULL);
  assert (stream_type == SQUASH_STREAM_COMPRESS || stream_type == SQUASH_STREAM_DECOMPRESS);

  stream = squash_malloc (sizeof (SquashBZ2Stream));
  squash_bz2_stream_init (stream, codec, stream_type, options, squash_bz2_stream_destroy);

  if (stream_type == SQUASH_STREAM_COMPRESS) {
    bz2_e = BZ2_bzCompressInit (&(stream->stream),
                                squash_codec_get_option_int_index (codec, options, SQUASH_BZ2_OPT_LEVEL),
                                0,
                                squash_codec_get_option_int_index (codec, options, SQUASH_BZ2_OPT_WORK_FACTOR));
  } else if (stream_type == SQUASH_STREAM_DECOMPRESS) {
    bz2_e = BZ2_bzDecompressInit (&(stream->stream),
                                  0,
                                  squash_codec_get_option_int_index (codec, options, SQUASH_BZ2_OPT_SMALL));
  } else {
    squash_assert_unreachable();
  }

  if (bz2_e != BZ_OK) {
    /* We validate the params so OOM is really the only time this
       should happen, and that really shouldn't be happening here. */
    stream = squash_object_unref (stream);
  }

  return stream;
}
Example #5
0
static SquashStatus
squash_bz2_process_stream (SquashStream* stream, SquashOperation operation) {
  switch (operation) {
    case SQUASH_OPERATION_PROCESS:
      return squash_bz2_process_stream_ex (stream, BZ_RUN);
    case SQUASH_OPERATION_FLUSH:
      return squash_bz2_process_stream_ex (stream, BZ_FLUSH);
    case SQUASH_OPERATION_FINISH:
      return squash_bz2_finish_stream (stream);
    case SQUASH_OPERATION_TERMINATE:
      squash_assert_unreachable ();
      break;
  }

  squash_assert_unreachable();
}
Example #6
0
static SquashStatus
squash_brotli_process_stream (SquashStream* stream, SquashOperation operation) {
  SquashBrotliStream* s = (SquashBrotliStream*) stream;

  if (stream->stream_type == SQUASH_STREAM_COMPRESS) {
    const int be_ret =
      BrotliEncoderCompressStream(s->ctx.encoder,
                                  squash_brotli_encoder_operation_from_squash_operation(operation),
                                  &(stream->avail_in), &(stream->next_in),
                                  &(stream->avail_out), &(stream->next_out),
                                  NULL);

    if (SQUASH_UNLIKELY(be_ret != 1))
      return squash_error (SQUASH_FAILED);
    else if (stream->avail_in != 0 || BrotliEncoderHasMoreOutput(s->ctx.encoder))
      return SQUASH_PROCESSING;
    else
      return SQUASH_OK;
  } else if (stream->stream_type == SQUASH_STREAM_DECOMPRESS) {
    const BrotliResult bd_ret =
      BrotliDecompressStream(&(stream->avail_in), &(stream->next_in),
                             &(stream->avail_out), &(stream->next_out),
                             NULL,
                             s->ctx.decoder);

    switch (bd_ret) {
      case BROTLI_RESULT_SUCCESS:
        return SQUASH_OK;
      case BROTLI_RESULT_NEEDS_MORE_INPUT:
        return SQUASH_OK;
      case BROTLI_RESULT_NEEDS_MORE_OUTPUT:
        return SQUASH_PROCESSING;
      case BROTLI_RESULT_ERROR:
        return SQUASH_FAILED;
    }

    if (SQUASH_UNLIKELY(bd_ret != BROTLI_RESULT_SUCCESS))
      return squash_error (SQUASH_FAILED);
  } else {
    squash_assert_unreachable ();
  }

  squash_assert_unreachable ();
}
Example #7
0
static SquashStatus
squash_lz4f_process_stream (SquashStream* stream, SquashOperation operation) {
  switch (stream->stream_type) {
    case SQUASH_STREAM_COMPRESS:
      return squash_lz4f_compress_stream (stream, operation);
    case SQUASH_STREAM_DECOMPRESS:
      return squash_lz4f_decompress_stream (stream, operation);
    default:
      squash_assert_unreachable();
  }
}
Example #8
0
static DENSITY_COMPRESSION_MODE
squash_density_level_to_mode (int level) {
  switch (level) {
    case 1:
      return DENSITY_COMPRESSION_MODE_CHAMELEON_ALGORITHM;
    case 7:
      return DENSITY_COMPRESSION_MODE_CHEETAH_ALGORITHM;
    case 9:
      return DENSITY_COMPRESSION_MODE_LION_ALGORITHM;
    default:
      squash_assert_unreachable ();
  }
}
Example #9
0
/**
 * @brief Get the boolean value for an option
 *
 * Note that this function will not perform a conversion—if you use it
 * to request the value of an option which is not a boolean the result
 * is undefined.
 *
 * @param codec the relevant codec
 * @param options the options instance to retrieve the value from
 * @param key the name of the option to retrieve the value of
 * @return the value of the option
 */
bool
squash_codec_get_option_bool (SquashCodec* codec,
                              SquashOptions* options,
                              const char* key) {
  SquashOptionType type;
  const SquashOptionValue* value = squash_codec_get_option_value_by_name (codec, options, key, &type);
  switch ((int) type) {
    case SQUASH_OPTION_TYPE_BOOL:
      return value->bool_value;
    default:
      squash_assert_unreachable();
  }
}
Example #10
0
static MSCompFormat
squash_ms_format_from_codec (SquashCodec* codec) {
  const char* name = squash_codec_get_name (codec);

  if (name[5] == 0)
    return MSCOMP_LZNT1;
  else if (name[6] == 0)
    return MSCOMP_XPRESS;
  else if (name[14] == 0)
    return MSCOMP_XPRESS_HUFF;
  else
    squash_assert_unreachable();
}
Example #11
0
static void
squash_brotli_stream_destroy (void* stream) {
  SquashBrotliStream* s = (SquashBrotliStream*) stream;

  if (((SquashStream*) stream)->stream_type == SQUASH_STREAM_COMPRESS) {
    delete s->compressor;
  } else if (((SquashStream*) stream)->stream_type == SQUASH_STREAM_DECOMPRESS) {
    BrotliDestroyState(s->decompressor);
  } else {
    squash_assert_unreachable();
  }

  squash_stream_destroy (stream);
}
Example #12
0
static void
squash_brotli_stream_destroy (void* stream) {
  SquashBrotliStream* s = (SquashBrotliStream*) stream;

  if (((SquashStream*) stream)->stream_type == SQUASH_STREAM_COMPRESS) {
    BrotliEncoderDestroyInstance(s->ctx.encoder);
  } else if (((SquashStream*) stream)->stream_type == SQUASH_STREAM_DECOMPRESS) {
    BrotliDestroyState(s->ctx.decoder);
  } else {
    squash_assert_unreachable();
  }

  squash_stream_destroy (stream);
}
Example #13
0
static BrotliEncoderOperation
squash_brotli_encoder_operation_from_squash_operation (const SquashOperation operation) {
  switch (operation) {
    case SQUASH_OPERATION_PROCESS:
      return BROTLI_OPERATION_PROCESS;
    case SQUASH_OPERATION_FLUSH:
      return BROTLI_OPERATION_FLUSH;
    case SQUASH_OPERATION_FINISH:
      return BROTLI_OPERATION_FINISH;
    case SQUASH_OPERATION_TERMINATE:
    default:
      squash_assert_unreachable ();
  }
}
Example #14
0
/**
 * @brief Get the integer value for an option
 *
 * Note that this function will not perform a conversion—if you use it
 * to request the value of an option which is not an integer the
 * result is undefined.
 *
 * @param codec the relevant codec
 * @param options the options instance to retrieve the value from
 * @param key the name of the option to retrieve the value of
 * @return the value of the option
 */
int
squash_codec_get_option_int (SquashCodec* codec,
                             SquashOptions* options,
                             const char* key) {
  SquashOptionType type;
  const SquashOptionValue* value = squash_codec_get_option_value_by_name (codec, options, key, &type);
  switch ((int) type) {
    case SQUASH_OPTION_TYPE_INT:
    case SQUASH_OPTION_TYPE_RANGE_INT:
    case SQUASH_OPTION_TYPE_ENUM_STRING:
      return value->int_value;
    default:
      squash_assert_unreachable();
  }
}
Example #15
0
static size_t
squash_lz4f_block_size_id_to_size (blockSizeID_t blkid) {
  switch (blkid) {
    case max64KB:
      return  64 * 1024;
    case max256KB:
      return 256 * 1024;
    case max1MB:
      return   1 * 1024 * 1024;
    case max4MB:
      return   4 * 1024 * 1024;
    default:
      squash_assert_unreachable();
      break;
  }
}
Example #16
0
static SquashStatus
squash_lz4_compress_buffer (SquashCodec* codec,
                            size_t* compressed_size,
                            uint8_t compressed[SQUASH_ARRAY_PARAM(*compressed_size)],
                            size_t uncompressed_size,
                            const uint8_t uncompressed[SQUASH_ARRAY_PARAM(uncompressed_size)],
                            SquashOptions* options) {
  int level = squash_codec_get_option_int_index (codec, options, SQUASH_LZ4_OPT_LEVEL);

#if INT_MAX < SIZE_MAX
  if (SQUASH_UNLIKELY(INT_MAX < uncompressed_size) ||
      SQUASH_UNLIKELY(INT_MAX < *compressed_size))
    return squash_error (SQUASH_RANGE);
#endif

  int lz4_r;

  if (level == 7) {
    lz4_r = LZ4_compress_limitedOutput ((char*) uncompressed,
                                        (char*) compressed,
                                        (int) uncompressed_size,
                                        (int) *compressed_size);
  } else if (level < 7) {
    lz4_r = LZ4_compress_fast ((const char*) uncompressed,
                               (char*) compressed,
                               (int) uncompressed_size,
                               (int) *compressed_size,
                               squash_lz4_level_to_fast_mode (level));
  } else if (level < 17) {
    lz4_r = LZ4_compressHC2_limitedOutput ((char*) uncompressed,
                                           (char*) compressed,
                                           (int) uncompressed_size,
                                           (int) *compressed_size,
                                           squash_lz4_level_to_hc_level (level));
  } else {
    squash_assert_unreachable();
  }

#if SIZE_MAX < INT_MAX
  if (SQUASH_UNLIKELY(SIZE_MAX < lz4_r))
    return squash_error (SQUASH_RANGE);
#endif

  *compressed_size = lz4_r;

  return SQUASH_UNLIKELY(lz4_r == 0) ? squash_error (SQUASH_BUFFER_FULL) : SQUASH_OK;
}
Example #17
0
static int
squash_lz4_level_to_fast_mode (const int level) {
    switch (level) {
      case 1:
        return 32;
      case 2:
        return 24;
      case 3:
        return 17;
      case 4:
        return 8;
      case 5:
        return 4;
      case 6:
        return 2;
      default:
        squash_assert_unreachable();
    }
}
Example #18
0
static int
squash_lz4_level_to_hc_level (const int level) {
  switch (level) {
    case 8:
      return 2;
    case 9:
      return 4;
    case 10:
      return 6;
    case 11:
      return 9;
    case 12:
      return 12;
    case 13:
      return 14;
    case 14:
      return 16;
    default:
      squash_assert_unreachable();
  }
}
Example #19
0
static void
squash_brotli_stream_init (SquashBrotliStream* s,
                           SquashCodec* codec,
                           SquashStreamType stream_type,
                           SquashOptions* options,
                           SquashDestroyNotify destroy_notify) {
  SquashStream* stream = (SquashStream*) s;
  squash_stream_init (stream, codec, stream_type, (SquashOptions*) options, destroy_notify);

  if (stream_type == SQUASH_STREAM_COMPRESS) {
    s->ctx.encoder = BrotliEncoderCreateInstance(squash_brotli_malloc, squash_brotli_free, NULL);

    BrotliEncoderSetParameter(s->ctx.encoder, BROTLI_PARAM_QUALITY, squash_options_get_int_at (options, codec, SQUASH_BROTLI_OPT_LEVEL));
    BrotliEncoderSetParameter(s->ctx.encoder, BROTLI_PARAM_LGWIN, squash_options_get_int_at (options, codec, SQUASH_BROTLI_OPT_WINDOW_SIZE));
    BrotliEncoderSetParameter(s->ctx.encoder, BROTLI_PARAM_LGBLOCK, squash_options_get_int_at (options, codec, SQUASH_BROTLI_OPT_BLOCK_SIZE));
    BrotliEncoderSetParameter(s->ctx.encoder, BROTLI_PARAM_MODE, squash_options_get_int_at (options, codec, SQUASH_BROTLI_OPT_MODE));
  } else if (stream_type == SQUASH_STREAM_DECOMPRESS) {
    s->ctx.decoder = BrotliCreateState(squash_brotli_malloc, squash_brotli_free, NULL);
  } else {
    squash_assert_unreachable();
  }
}
Example #20
0
static bool
squash_density_flush_internal_buffer (SquashStream* stream) {
  SquashDensityStream* s = (SquashDensityStream*) stream;
  const size_t buffer_remaining = s->buffer_size - s->buffer_pos;
  const size_t cp_size = (stream->avail_out < buffer_remaining) ? stream->avail_out : buffer_remaining;

  if (cp_size > 0) {
    memcpy (stream->next_out, s->buffer + s->buffer_pos, cp_size);
    stream->next_out += cp_size;
    stream->avail_out -= cp_size;
    s->buffer_pos += cp_size;

    if (s->buffer_pos == s->buffer_size) {
      s->buffer_size = 0;
      s->buffer_pos = 0;
      return true;
    } else {
      return false;
    }
  }

  squash_assert_unreachable();
}
Example #21
0
static SquashStatus
squash_lz4f_get_status (size_t res) {
  if (!LZ4F_isError (res))
    return SQUASH_OK;

  switch ((LZ4F_errorCodes) (-(int)(res))) {
    case LZ4F_OK_NoError:
      return SQUASH_OK;
    case LZ4F_ERROR_GENERIC:
      return squash_error (SQUASH_FAILED);
    case LZ4F_ERROR_maxBlockSize_invalid:
    case LZ4F_ERROR_blockMode_invalid:
    case LZ4F_ERROR_contentChecksumFlag_invalid:
    case LZ4F_ERROR_headerVersion_wrong:
    case LZ4F_ERROR_blockChecksum_unsupported:
    case LZ4F_ERROR_reservedFlag_set:
    case LZ4F_ERROR_frameHeader_incomplete:
    case LZ4F_ERROR_frameType_unknown:
    case LZ4F_ERROR_frameSize_wrong:
    case LZ4F_ERROR_headerChecksum_invalid:
    case LZ4F_ERROR_contentChecksum_invalid:
      return squash_error (SQUASH_INVALID_BUFFER);
    case LZ4F_ERROR_compressionLevel_invalid:
      return squash_error (SQUASH_BAD_VALUE);
    case LZ4F_ERROR_allocation_failed:
      return squash_error (SQUASH_MEMORY);
    case LZ4F_ERROR_srcSize_tooLarge:
    case LZ4F_ERROR_dstMaxSize_tooSmall:
      return squash_error (SQUASH_BUFFER_FULL);
    case LZ4F_ERROR_decompressionFailed:
    case LZ4F_ERROR_srcPtr_wrong:
    case LZ4F_ERROR_maxCode:
      return squash_error (SQUASH_FAILED);
    default:
      squash_assert_unreachable ();
  }
}
Example #22
0
File: file.c Project: jibsen/squash
static SquashStatus
squash_file_write_internal (SquashFile* file,
                            size_t uncompressed_size,
                            const uint8_t uncompressed[SQUASH_ARRAY_PARAM(uncompressed_size)],
                            SquashOperation operation) {
  SquashStatus res;

  assert (file != NULL);

  if (SQUASH_UNLIKELY(file->last_status < 0))
    return file->last_status;

  if (file->stream == NULL) {
    file->stream = squash_codec_create_stream_with_options (file->codec, SQUASH_STREAM_COMPRESS, file->options);
    if (SQUASH_UNLIKELY(file->stream == NULL)) {
      res = squash_error (SQUASH_FAILED);
      goto cleanup;
    }
  }

  assert (file->stream->next_in == NULL);
  assert (file->stream->avail_in == 0);
  assert (file->stream->next_out == NULL);
  assert (file->stream->avail_out == 0);

  file->stream->next_in = uncompressed;
  file->stream->avail_in = uncompressed_size;

  file->stream->next_in = uncompressed;
  file->stream->avail_in = uncompressed_size;

  do {
    file->stream->next_out = file->buf;
    file->stream->avail_out = SQUASH_FILE_BUF_SIZE;

    switch (operation) {
      case SQUASH_OPERATION_PROCESS:
        res = squash_stream_process (file->stream);
        break;
      case SQUASH_OPERATION_FLUSH:
        res = squash_stream_flush (file->stream);
        break;
      case SQUASH_OPERATION_FINISH:
        res = squash_stream_finish (file->stream);
        break;
      case SQUASH_OPERATION_TERMINATE:
        squash_assert_unreachable ();
        break;
    }

    if (res > 0 && file->stream->avail_out != SQUASH_FILE_BUF_SIZE) {
      size_t bytes_written = SQUASH_FWRITE_UNLOCKED(file->buf, 1, SQUASH_FILE_BUF_SIZE - file->stream->avail_out, file->fp);
      if (bytes_written != SQUASH_FILE_BUF_SIZE - file->stream->avail_out) {
        res = SQUASH_IO;
        goto cleanup;
      }
    }
  } while (res == SQUASH_PROCESSING);

 cleanup:

  if (file->stream != NULL) {
    file->stream->next_in = NULL;
    file->stream->avail_in = 0;
    file->stream->next_out = NULL;
    file->stream->avail_out = 0;
  }

  return file->last_status = res;
}
Example #23
0
static SquashStatus
squash_ms_process_stream (SquashStream* stream, SquashOperation operation) {
  SquashStatus status = SQUASH_FAILED;
  MSCompStatus res;
  SquashMSCompStream* s = (SquashMSCompStream*) stream;
  uint8_t nul_buf;

  s->mscomp.in = stream->next_in;
  s->mscomp.in_avail = stream->avail_in;
  s->mscomp.out = stream->next_out;
  s->mscomp.out_avail = stream->avail_out;

  if (s->mscomp.in == NULL) {
    s->mscomp.in = &nul_buf;
  }

  if (stream->stream_type == SQUASH_STREAM_COMPRESS) {
    res = ms_deflate(&(s->mscomp), squash_ms_comp_flush_from_operation (operation));
  } else {
    res = ms_inflate(&(s->mscomp));
  }

  stream->next_in = s->mscomp.in;
  stream->avail_in = s->mscomp.in_avail;
  stream->next_out = s->mscomp.out;
  stream->avail_out = s->mscomp.out_avail;

  switch (stream->stream_type) {
    case SQUASH_STREAM_COMPRESS:
      switch (operation) {
        case SQUASH_OPERATION_PROCESS:
          switch ((int) res) {
            case MSCOMP_OK:
              status = (stream->avail_in == 0) ? SQUASH_OK : SQUASH_PROCESSING;
              break;
            default:
              status = squash_ms_status_to_squash_status (res);
              break;
          }
          break;
        case SQUASH_OPERATION_FLUSH:
          switch ((int) res) {
            case MSCOMP_OK:
              status = SQUASH_OK;
              break;
            default:
              status = squash_ms_status_to_squash_status (res);
              break;
          }
          break;
        case SQUASH_OPERATION_FINISH:
          switch ((int) res) {
            case MSCOMP_OK:
              status = SQUASH_PROCESSING;
              break;
            case MSCOMP_STREAM_END:
              status = SQUASH_OK;
              break;
            default:
              status = squash_ms_status_to_squash_status (res);
              break;
          }
          break;
        case SQUASH_OPERATION_TERMINATE:
          squash_assert_unreachable ();
          break;
      }
      break;
    case SQUASH_STREAM_DECOMPRESS:
      switch (operation) {
        case SQUASH_OPERATION_PROCESS:
        case SQUASH_OPERATION_FLUSH:
        case SQUASH_OPERATION_FINISH:
          switch ((int) res) {
            case MSCOMP_OK:
            case MSCOMP_POSSIBLE_STREAM_END:
              status = (stream->avail_in == 0 && stream->avail_out > 0) ? SQUASH_OK : SQUASH_PROCESSING;
              break;
            default:
              status = squash_ms_status_to_squash_status (res);
              break;
          }
          break;
        case SQUASH_OPERATION_TERMINATE:
          squash_assert_unreachable ();
      }
      break;
  }

  return status;
}
Example #24
0
static SquashStatus
squash_density_process_stream (SquashStream* stream, SquashOperation operation) {
  SquashDensityStream* s = (SquashDensityStream*) stream;

  if (s->buffer_size > 0) {
    squash_density_flush_internal_buffer (stream);
    return SQUASH_PROCESSING;
  }

  if (s->next == SQUASH_DENSITY_ACTION_INIT) {
    s->active_input_size = (stream->stream_type == SQUASH_STREAM_COMPRESS) ? ((stream->avail_in / SQUASH_DENSITY_INPUT_MULTIPLE) * SQUASH_DENSITY_INPUT_MULTIPLE) : stream->avail_in;
    if (stream->avail_out < DENSITY_MINIMUM_OUTPUT_BUFFER_SIZE) {
      s->buffer_active = true;
      s->state = density_stream_prepare (s->stream, (uint8_t*) stream->next_in, s->active_input_size, s->buffer, DENSITY_MINIMUM_OUTPUT_BUFFER_SIZE);
    } else {
      s->buffer_active = false;
      s->state = density_stream_prepare (s->stream, (uint8_t*) stream->next_in, s->active_input_size, stream->next_out, stream->avail_out);
    }
    if (SQUASH_UNLIKELY(s->state != DENSITY_STREAM_STATE_READY))
      return squash_error (SQUASH_FAILED);
  }

  switch (s->state) {
    case DENSITY_STREAM_STATE_STALL_ON_INPUT:
      if (s->input_buffer_size != 0 ||
          (stream->avail_in < SQUASH_DENSITY_INPUT_MULTIPLE && stream->stream_type == SQUASH_STREAM_COMPRESS && operation == SQUASH_OPERATION_PROCESS)) {
        const size_t remaining = SQUASH_DENSITY_INPUT_MULTIPLE - s->input_buffer_size;
        const size_t cp_size = remaining < stream->avail_in ? remaining : stream->avail_in;
        if (cp_size != 0) {
          memcpy (s->input_buffer + s->input_buffer_size, stream->next_in, cp_size);
          s->input_buffer_size += cp_size;
          stream->next_in += cp_size;
          stream->avail_in -= cp_size;
          assert (cp_size != 0);
        }
      }

      if (s->input_buffer_size != 0) {
        if (s->input_buffer_size == SQUASH_DENSITY_INPUT_MULTIPLE || operation != SQUASH_OPERATION_PROCESS) {
          s->active_input_size = s->input_buffer_size;
          s->input_buffer_active = true;
          density_stream_update_input (s->stream, s->input_buffer, s->input_buffer_size);
          s->state = DENSITY_STREAM_STATE_READY;
        } else {
          assert (stream->avail_in == 0);
          return SQUASH_OK;
        }
      } else {
        s->active_input_size = (stream->stream_type == SQUASH_STREAM_COMPRESS) ? ((stream->avail_in / SQUASH_DENSITY_INPUT_MULTIPLE) * SQUASH_DENSITY_INPUT_MULTIPLE) : stream->avail_in;
        density_stream_update_input (s->stream, stream->next_in, s->active_input_size);
        s->state = DENSITY_STREAM_STATE_READY;
      }
      break;
    case DENSITY_STREAM_STATE_STALL_ON_OUTPUT:
      {
        if (!s->output_invalid) {
          const size_t written = density_stream_output_available_for_use (s->stream);
          total_bytes_written += written;

          if (s->buffer_active) {
            s->buffer_size = written;
            s->buffer_pos = 0;

            const size_t cp_size = s->buffer_size < stream->avail_out ? s->buffer_size : stream->avail_out;
            memcpy (stream->next_out, s->buffer, cp_size);
            stream->next_out += cp_size;
            stream->avail_out -= cp_size;
            s->buffer_pos += cp_size;
            if (s->buffer_pos == s->buffer_size) {
              s->buffer_pos = 0;
              s->buffer_size = 0;
            }
          } else {
            assert (written <= stream->avail_out);
            stream->next_out += written;
            stream->avail_out -= written;
          }

          s->output_invalid = true;
          return SQUASH_PROCESSING;
        } else {
          if (stream->avail_out < DENSITY_MINIMUM_OUTPUT_BUFFER_SIZE) {
            s->buffer_active = true;
            density_stream_update_output (s->stream, s->buffer, DENSITY_MINIMUM_OUTPUT_BUFFER_SIZE);
          } else {
            s->buffer_active = false;
            density_stream_update_output (s->stream, stream->next_out, stream->avail_out);
          }
          s->output_invalid = false;
          s->state = DENSITY_STREAM_STATE_READY;
        }
      }
      break;
    case DENSITY_STREAM_STATE_READY:
      break;
    case DENSITY_STREAM_STATE_ERROR_OUTPUT_BUFFER_TOO_SMALL:
    case DENSITY_STREAM_STATE_ERROR_INVALID_INTERNAL_STATE:
    case DENSITY_STREAM_STATE_ERROR_INTEGRITY_CHECK_FAIL:
      return squash_error (SQUASH_FAILED);
  }

  assert (s->output_invalid == false);

  while (s->state == DENSITY_STREAM_STATE_READY && s->next != SQUASH_DENSITY_ACTION_FINISHED) {
    switch (s->next) {
      case SQUASH_DENSITY_ACTION_INIT:
        if (stream->stream_type == SQUASH_STREAM_COMPRESS) {
          DENSITY_COMPRESSION_MODE compression_mode =
            squash_density_level_to_mode (squash_codec_get_option_int_index (stream->codec, stream->options, SQUASH_DENSITY_OPT_LEVEL));
          DENSITY_BLOCK_TYPE block_type =
            squash_codec_get_option_bool_index (stream->codec, stream->options, SQUASH_DENSITY_OPT_CHECKSUM) ?
              DENSITY_BLOCK_TYPE_WITH_HASHSUM_INTEGRITY_CHECK :
              DENSITY_BLOCK_TYPE_DEFAULT;

          s->state = density_stream_compress_init (s->stream, compression_mode, block_type);
        } else {
          s->state = density_stream_decompress_init (s->stream, NULL);
        }
        if (SQUASH_UNLIKELY(s->state != DENSITY_STREAM_STATE_READY))
          return squash_error (SQUASH_FAILED);
        s->next = SQUASH_DENSITY_ACTION_CONTINUE;
        break;
      case SQUASH_DENSITY_ACTION_CONTINUE_OR_FINISH:
        s->next = (operation == SQUASH_OPERATION_PROCESS) ? SQUASH_DENSITY_ACTION_CONTINUE : SQUASH_DENSITY_ACTION_FINISH;
        break;
      case SQUASH_DENSITY_ACTION_CONTINUE:
        if (stream->stream_type == SQUASH_STREAM_COMPRESS) {
          s->state = density_stream_compress_continue (s->stream);
        } else {
          s->state = density_stream_decompress_continue (s->stream);
        }

        if (s->state == DENSITY_STREAM_STATE_STALL_ON_INPUT)
          s->next = SQUASH_DENSITY_ACTION_CONTINUE_OR_FINISH;

        break;
      case SQUASH_DENSITY_ACTION_FINISH:
        if (stream->stream_type == SQUASH_STREAM_COMPRESS) {
          s->state = density_stream_compress_finish (s->stream);
        } else {
          s->state = density_stream_decompress_finish (s->stream);
        }
        if (s->state == DENSITY_STREAM_STATE_READY) {
          s->state = DENSITY_STREAM_STATE_STALL_ON_OUTPUT;
          s->output_invalid = false;
          s->next = SQUASH_DENSITY_ACTION_FINISHED;
        }
        break;
      case SQUASH_DENSITY_ACTION_FINISHED:
      default:
        squash_assert_unreachable();
        break;
    }
  }

  if (s->state == DENSITY_STREAM_STATE_STALL_ON_INPUT) {
    if (s->input_buffer_active) {
      assert (s->active_input_size == s->input_buffer_size);
      s->input_buffer_active = false;
      s->input_buffer_size = 0;
    } else {
      assert (s->active_input_size <= stream->avail_in);
      stream->next_in += s->active_input_size;
      stream->avail_in -= s->active_input_size;
    }
    s->active_input_size = 0;
  } else if (s->state == DENSITY_STREAM_STATE_STALL_ON_OUTPUT) {
    {
      if (!s->output_invalid) {
        const size_t written = density_stream_output_available_for_use (s->stream);
        total_bytes_written += written;

        if (s->buffer_active) {
          s->buffer_size = written;
          s->buffer_pos = 0;

          const size_t cp_size = s->buffer_size < stream->avail_out ? s->buffer_size : stream->avail_out;
          memcpy (stream->next_out, s->buffer, cp_size);
          stream->next_out += cp_size;
          stream->avail_out -= cp_size;
          s->buffer_pos += cp_size;
          if (s->buffer_pos == s->buffer_size) {
            s->buffer_pos = 0;
            s->buffer_size = 0;
          }
        } else {
          assert (written <= stream->avail_out);
          stream->next_out += written;
          stream->avail_out -= written;
        }

        s->output_invalid = true;
        return SQUASH_PROCESSING;
      } else {
        squash_assert_unreachable();
      }
    }
  }

  if (operation == SQUASH_OPERATION_FINISH)
    total_bytes_written = 0;

  if (stream->avail_in == 0) {
    return SQUASH_OK;
  } else {
    return SQUASH_PROCESSING;
  }
}
Example #25
0
static SquashStatus
squash_lz4f_compress_stream (SquashStream* stream, SquashOperation operation) {
  SquashLZ4FStream* s = (SquashLZ4FStream*) stream;
  bool progress = false;

  if (s->data.comp.output_buffer_size != 0) {
    const size_t buffer_remaining = s->data.comp.output_buffer_size - s->data.comp.output_buffer_pos;
    const size_t cp_size = (buffer_remaining < stream->avail_out) ? buffer_remaining : stream->avail_out;

    memcpy (stream->next_out, s->data.comp.output_buffer + s->data.comp.output_buffer_pos, cp_size);
    stream->next_out += cp_size;
    stream->avail_out -= cp_size;
    s->data.comp.output_buffer_pos += cp_size;

    if (cp_size == buffer_remaining) {
      s->data.comp.output_buffer_size = 0;
      s->data.comp.output_buffer_pos = 0;

      progress = true;
    } else {
      return SQUASH_PROCESSING;
    }
  }

  while ((stream->avail_in != 0 || operation != SQUASH_OPERATION_PROCESS) && stream->avail_out != 0) {
    if (s->data.comp.state == SQUASH_LZ4F_STATE_INIT) {
      s->data.comp.state = SQUASH_LZ4F_STATE_ACTIVE;
      if (stream->avail_out < 19) {
        s->data.comp.output_buffer_size =
          LZ4F_compressBegin (s->data.comp.ctx,
                              squash_lz4f_stream_get_output_buffer (stream),
                              squash_lz4f_stream_get_output_buffer_size (stream),
                              &(s->data.comp.prefs));
        break;
      } else {
        size_t written = LZ4F_compressBegin (s->data.comp.ctx, stream->next_out, stream->avail_out, &(s->data.comp.prefs));
        stream->next_out += written;
        stream->avail_out -= written;
        progress = true;
      }
    } else {
      const size_t input_buffer_size = squash_lz4f_get_input_buffer_size (stream);
      const size_t total_input = stream->avail_in + s->data.comp.input_buffer_size;
      const size_t output_buffer_max_size = squash_lz4f_stream_get_output_buffer_size (stream);

      if (progress && (total_input < input_buffer_size || stream->avail_out < output_buffer_max_size))
        break;

      uint8_t* obuf;
      size_t olen;

      const size_t input_size = (total_input > input_buffer_size) ? (input_buffer_size - s->data.comp.input_buffer_size) : stream->avail_in;
      if (input_size > 0) {
        obuf = (output_buffer_max_size > stream->avail_out) ? squash_lz4f_stream_get_output_buffer (stream) : stream->next_out;
        olen = LZ4F_compressUpdate (s->data.comp.ctx, obuf, output_buffer_max_size, stream->next_in, input_size, NULL);

        if (!LZ4F_isError (olen)) {
          if (input_size + s->data.comp.input_buffer_size == input_buffer_size) {
            s->data.comp.input_buffer_size = 0;
          } else {
            s->data.comp.input_buffer_size += input_size;
            assert (olen == 0);
          }

          stream->next_in += input_size;
          stream->avail_in -= input_size;
        } else {
          squash_assert_unreachable();
        }
      } else if (operation == SQUASH_OPERATION_FLUSH) {
        assert (stream->avail_in == 0);
        olen = squash_lz4f_stream_get_output_buffer_size (stream);
        obuf = (olen > stream->avail_out) ? squash_lz4f_stream_get_output_buffer (stream) : stream->next_out;
        olen = LZ4F_flush (s->data.comp.ctx, obuf, olen, NULL);

        s->data.comp.input_buffer_size = 0;
      } else if (operation == SQUASH_OPERATION_FINISH) {
        assert (stream->avail_in == 0);
        olen = squash_lz4f_stream_get_output_buffer_size (stream);
        obuf = (olen > stream->avail_out) ? squash_lz4f_stream_get_output_buffer (stream) : stream->next_out;
        olen = LZ4F_compressEnd (s->data.comp.ctx, obuf, olen, NULL);

        s->data.comp.input_buffer_size = 0;
      } else if (progress) {
        break;
      } else {
        squash_assert_unreachable();
      }

      if (SQUASH_UNLIKELY(LZ4F_isError (olen))) {
        squash_assert_unreachable();
        return squash_error (SQUASH_FAILED);
      } else {
        if (olen != 0) {
          if (obuf == s->data.comp.output_buffer) {
            s->data.comp.output_buffer_size = olen;
            break;
          } else {
            stream->next_out += olen;
            stream->avail_out -= olen;
          }
        }
      }

      if (operation != SQUASH_OPERATION_PROCESS)
        break;
    }
  }

  if (s->data.comp.output_buffer_size != 0) {
    const size_t buffer_remaining = s->data.comp.output_buffer_size - s->data.comp.output_buffer_pos;
    const size_t cp_size = (buffer_remaining < stream->avail_out) ? buffer_remaining : stream->avail_out;

    memcpy (stream->next_out, s->data.comp.output_buffer + s->data.comp.output_buffer_pos, cp_size);
    stream->next_out += cp_size;
    stream->avail_out -= cp_size;
    s->data.comp.output_buffer_pos += cp_size;

    if (cp_size == buffer_remaining) {
      s->data.comp.output_buffer_size = 0;
      s->data.comp.output_buffer_pos = 0;

      progress = true;
    } else {
      return SQUASH_PROCESSING;
    }
  }

  return (stream->avail_in == 0 && s->data.comp.output_buffer_size == 0) ? SQUASH_OK : SQUASH_PROCESSING;
}