Beispiel #1
0
/**
 * @brief Decompress a buffer with an existing @ref SquashOptions
 *
 * @param codec The codec to use
 * @param[out] decompressed Location to store the decompressed data
 * @param[in,out] decompressed_length Location storing the size of the
 *   @a decompressed buffer on input, replaced with the actual size of
 *   the decompressed data
 * @param compressed The compressed data
 * @param compressed_length Length of the compressed data (in bytes)
 * @param options Compression options
 * @return A status code
 */
SquashStatus
squash_codec_decompress_with_options (SquashCodec* codec,
                                      size_t* decompressed_length,
                                      uint8_t decompressed[SQUASH_ARRAY_PARAM(*decompressed_length)],
                                      size_t compressed_length,
                                      const uint8_t compressed[SQUASH_ARRAY_PARAM(compressed_length)],
                                      SquashOptions* options) {
  SquashCodecImpl* impl = NULL;

  assert (codec != NULL);

  impl = squash_codec_get_impl (codec);
  if (impl == NULL)
    return squash_error (SQUASH_UNABLE_TO_LOAD);

  if (decompressed == compressed)
    return squash_error (SQUASH_INVALID_BUFFER);

  if (impl->decompress_buffer != NULL) {
    SquashStatus res;
    res = impl->decompress_buffer (codec,
                                   decompressed_length, decompressed,
                                   compressed_length, compressed,
                                   squash_object_ref (options));
    squash_object_unref (options);
    return res;
  } else {
    SquashStatus status;
    SquashStream* stream;

    stream = squash_codec_create_stream_with_options (codec, SQUASH_STREAM_DECOMPRESS, options);
    stream->next_in = compressed;
    stream->avail_in = compressed_length;
    stream->next_out = decompressed;
    stream->avail_out = *decompressed_length;

    do {
      status = squash_stream_process (stream);
    } while (status == SQUASH_PROCESSING);

    if (status == SQUASH_END_OF_STREAM) {
      status = SQUASH_OK;
      *decompressed_length = stream->total_out;
    } else if (status == SQUASH_OK) {
      do {
        status = squash_stream_finish (stream);
      } while (status == SQUASH_PROCESSING);

      if (status == SQUASH_OK) {
        *decompressed_length = stream->total_out;
      }
    }

    assert (stream->stream_type == SQUASH_STREAM_DECOMPRESS);
    squash_object_unref (stream);

    return status;
  }
}
Beispiel #2
0
	//----------
	void Stream::read(const void * dataRaw, size_t size) {
		auto squashDirection = this->direction == Direction::Compress ? SQUASH_STREAM_COMPRESS : SQUASH_STREAM_DECOMPRESS;

		if (!this->squashStream) {
			if (!this->codec.isValid()) {
				OFXSQUASH_ERROR << "Cannot read stream. Codec is not initialized";
				return;
			}


			this->squashStream = squash_stream_new(this->codec.getSquashCodec(), squashDirection, nullptr);
			if (!squashStream) {
				OFXSQUASH_ERROR << "Failed to initialize stream for codec [" << codec.getName() << "]";
			}
		}

		const uint8_t* data = (const uint8_t*) dataRaw;
		int64_t incomingBytesRemaining = size;

		SquashStatus status;

		this->squashStream->next_in = data;
		this->squashStream->avail_in = size;

		do
		{
			this->squashStream->next_out = this->buffer.data();
			this->squashStream->avail_out = this->buffer.size();

			status = squash_stream_process(this->squashStream);

			if (status != SQUASH_OK && status != SQUASH_PROCESSING)
			{
				OFXSQUASH_ERROR << "Processing stream failed: " << squash_status_to_string(status);
				return;
			}

			const size_t outputSize = this->buffer.size() - this->squashStream->avail_out;
			if (outputSize > 0)
			{
				if (this->writeFunction) {
					WriteFunctionArguments args{ this->buffer.data(), outputSize, false };
					this->writeFunction(args);
				}
				else {
					OFXSQUASH_WARNING << "Cannot write stream output. No WriteFunction has been set";
				}
			}
		} while (status == SQUASH_PROCESSING);
	}
Beispiel #3
0
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;
}
Beispiel #4
0
/**
 * @brief Read from a compressed file
 *
 * This function is the same as @ref squash_file_read, except it will
 * not acquire a lock on the @ref SquashFile instance.  It should be
 * used only when there is no possibility of other threads accessing
 * the file, or if you have already acquired the lock with @ref
 * squash_file_lock.
 *
 * @param file the file to read from
 * @param decompressed_size number of bytes to attempt to write to @a decompressed
 * @param decompressed buffer to write the decompressed data to
 * @return the result of the operation
 * @retval SQUASH_OK successfully read some data
 * @retval SQUASH_END_OF_STREAM the end of the file was reached
 */
SquashStatus
squash_file_read_unlocked (SquashFile* file,
                           size_t* decompressed_size,
                           uint8_t decompressed[SQUASH_ARRAY_PARAM(*decompressed_size)]) {
  assert (file != NULL);
  assert (decompressed_size != NULL);
  assert (decompressed != 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_DECOMPRESS, file->options);
    if (SQUASH_UNLIKELY(file->stream == NULL)) {
      return file->last_status = squash_error (SQUASH_FAILED);
    }
  }
  SquashStream* stream = file->stream;

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

  if (stream->state == SQUASH_STREAM_STATE_FINISHED) {
    *decompressed_size = 0;
    return SQUASH_END_OF_STREAM;
  }

  file->stream->next_out = decompressed;
  file->stream->avail_out = *decompressed_size;

  while (stream->avail_out != 0) {
    if (file->last_status < 0) {
      break;
    }

    if (stream->state == SQUASH_STREAM_STATE_FINISHED)
      break;

    if (file->last_status == SQUASH_PROCESSING) {
      if (stream->state < SQUASH_STREAM_STATE_FINISHING) {
        file->last_status = squash_stream_process (stream);
      } else {
        file->last_status = squash_stream_finish (stream);
      }

      continue;
    }

    assert (file->last_status == SQUASH_OK);

#if defined(SQUASH_MMAP_IO)
    if (file->map.data != MAP_FAILED)
      squash_mapped_file_destroy (&(file->map), true);

    if (squash_mapped_file_init_full(&(file->map), file->fp, SQUASH_FILE_BUF_SIZE, true, false)) {
      stream->next_in = file->map.data;
      stream->avail_in = file->map.size;
    } else
#endif
    {
      stream->next_in = file->buf;
      stream->avail_in = SQUASH_FREAD_UNLOCKED(file->buf, 1, SQUASH_FILE_BUF_SIZE, file->fp);
    }

    if (stream->avail_in == 0) {
      if (feof (file->fp)) {
        file->last_status = squash_stream_finish (stream);
      } else {
        file->last_status = squash_error (SQUASH_IO);
        break;
      }
    } else {
      file->last_status = squash_stream_process (stream);
    }
  }

  *decompressed_size = (stream->next_out - decompressed);

  stream->next_out = 0;
  stream->avail_out = 0;

  return file->last_status;
}
Beispiel #5
0
/**
 * @brief Compress a buffer with an existing @ref SquashOptions
 *
 * @param codec The codec to use
 * @param[out] compressed Location to store the compressed data
 * @param[in,out] compressed_length Location storing the size of the
 *   @a compressed buffer on input, replaced with the actual size of
 *   the compressed data
 * @param uncompressed The uncompressed data
 * @param uncompressed_length Length of the uncompressed data (in bytes)
 * @param options Compression options
 * @return A status code
 */
SquashStatus
squash_codec_compress_with_options (SquashCodec* codec,
                                    size_t* compressed_length,
                                    uint8_t compressed[SQUASH_ARRAY_PARAM(*compressed_length)],
                                    size_t uncompressed_length,
                                    const uint8_t uncompressed[SQUASH_ARRAY_PARAM(uncompressed_length)],
                                    SquashOptions* options) {
  SquashCodecImpl* impl = NULL;

  assert (codec != NULL);

  assert (compressed != NULL);
  assert (uncompressed != NULL);

  impl = squash_codec_get_impl (codec);
  if (impl == NULL)
    return squash_error (SQUASH_UNABLE_TO_LOAD);

  if (compressed == uncompressed)
    return squash_error (SQUASH_INVALID_BUFFER);

  if (impl->compress_buffer ||
      impl->compress_buffer_unsafe) {
    size_t max_compressed_length = squash_codec_get_max_compressed_size (codec, uncompressed_length);

    if (*compressed_length >= max_compressed_length) {
      if (impl->compress_buffer_unsafe != NULL) {
        return impl->compress_buffer_unsafe (codec,
                                              compressed_length, compressed,
                                              uncompressed_length, uncompressed,
                                              options);
      } else {
        return impl->compress_buffer (codec,
                                       compressed_length, compressed,
                                       uncompressed_length, uncompressed,
                                       options);
      }
    } else if (impl->compress_buffer != NULL) {
      return impl->compress_buffer (codec,
                                     compressed_length, compressed,
                                     uncompressed_length, uncompressed,
                                     options);
    } else {
      SquashStatus status;
      uint8_t* tmp_buf = malloc (max_compressed_length);
      if (tmp_buf == NULL)
        return squash_error (SQUASH_MEMORY);

      status = impl->compress_buffer_unsafe (codec,
                                              &max_compressed_length, tmp_buf,
                                              uncompressed_length, uncompressed,
                                              options);
      if (status == SQUASH_OK) {
        if (*compressed_length < max_compressed_length) {
          *compressed_length = max_compressed_length;
          free (tmp_buf);
          return squash_error (SQUASH_BUFFER_FULL);
        } else {
          *compressed_length = max_compressed_length;
          memcpy (compressed, tmp_buf, max_compressed_length);
          free (tmp_buf);
          return SQUASH_OK;
        }
      } else {
        free (tmp_buf);
        return status;
      }
    }
  } else {
    SquashStatus status;
    SquashStream* stream;

    stream = squash_codec_create_stream_with_options (codec, SQUASH_STREAM_COMPRESS, options);
    if (stream == NULL)
      return squash_error (SQUASH_FAILED);

    stream->next_in = uncompressed;
    stream->avail_in = uncompressed_length;
    stream->next_out = compressed;
    stream->avail_out = *compressed_length;

    do {
      status = squash_stream_process (stream);
    } while (status == SQUASH_PROCESSING);

    if (status != SQUASH_OK) {
      squash_object_unref (stream);
      return status;
    }

    do {
      status = squash_stream_finish (stream);
    } while (status == SQUASH_PROCESSING);

    if (status != SQUASH_OK) {
      squash_object_unref (stream);
      return status;
    }

    *compressed_length = stream->total_out;
    squash_object_unref (stream);
    return status;
  }
}