stream_buffer_encoder.c revision 223935
118334Speter/////////////////////////////////////////////////////////////////////////////// 218334Speter// 318334Speter/// \file stream_buffer_encoder.c 418334Speter/// \brief Single-call .xz Stream encoder 5132718Skan// 6169689Skan// Author: Lasse Collin 750397Sobrien// 8132718Skan// This file has been put into the public domain. 990075Sobrien// You can do whatever you want with this file. 1018334Speter// 1190075Sobrien/////////////////////////////////////////////////////////////////////////////// 1290075Sobrien 1390075Sobrien#include "index.h" 1490075Sobrien 1518334Speter 1690075Sobrien/// Maximum size of Index that has exactly one Record. 1790075Sobrien/// Index Indicator + Number of Records + Record + CRC32 rounded up to 1890075Sobrien/// the next multiple of four. 1990075Sobrien#define INDEX_BOUND ((1 + 1 + 2 * LZMA_VLI_BYTES_MAX + 4 + 3) & ~3) 2018334Speter 2118334Speter/// Stream Header, Stream Footer, and Index 2290075Sobrien#define HEADERS_BOUND (2 * LZMA_STREAM_HEADER_SIZE + INDEX_BOUND) 23169689Skan 24169689Skan 2518334Speterextern LZMA_API(size_t) 2618334Speterlzma_stream_buffer_bound(size_t uncompressed_size) 2718334Speter{ 2818334Speter // Get the maximum possible size of a Block. 2918334Speter const size_t block_bound = lzma_block_buffer_bound(uncompressed_size); 3018334Speter if (block_bound == 0) 3118334Speter return 0; 3218334Speter 3318334Speter // Catch the possible integer overflow and also prevent the size of 3418334Speter // the Stream exceeding LZMA_VLI_MAX (theoretically possible on 3518334Speter // 64-bit systems). 3618334Speter if (my_min(SIZE_MAX, LZMA_VLI_MAX) - block_bound < HEADERS_BOUND) 3718334Speter return 0; 3818334Speter 3918334Speter return block_bound + HEADERS_BOUND; 4018334Speter} 4118334Speter 4218334Speter 4318334Speterextern LZMA_API(lzma_ret) 4418334Speterlzma_stream_buffer_encode(lzma_filter *filters, lzma_check check, 4518334Speter lzma_allocator *allocator, const uint8_t *in, size_t in_size, 4618334Speter uint8_t *out, size_t *out_pos_ptr, size_t out_size) 4718334Speter{ 4818334Speter // Sanity checks 4918334Speter if (filters == NULL || (unsigned int)(check) > LZMA_CHECK_ID_MAX 5018334Speter || (in == NULL && in_size != 0) || out == NULL 5118334Speter || out_pos_ptr == NULL || *out_pos_ptr > out_size) 5218334Speter return LZMA_PROG_ERROR; 5318334Speter 5418334Speter if (!lzma_check_is_supported(check)) 5518334Speter return LZMA_UNSUPPORTED_CHECK; 5618334Speter 5718334Speter // Note for the paranoids: Index encoder prevents the Stream from 5818334Speter // getting too big and still being accepted with LZMA_OK, and Block 5918334Speter // encoder catches if the input is too big. So we don't need to 6018334Speter // separately check if the buffers are too big. 6118334Speter 6218334Speter // Use a local copy. We update *out_pos_ptr only if everything 6318334Speter // succeeds. 6418334Speter size_t out_pos = *out_pos_ptr; 6518334Speter 6618334Speter // Check that there's enough space for both Stream Header and 6718334Speter // Stream Footer. 6818334Speter if (out_size - out_pos <= 2 * LZMA_STREAM_HEADER_SIZE) 6918334Speter return LZMA_BUF_ERROR; 7018334Speter 7118334Speter // Reserve space for Stream Footer so we don't need to check for 7218334Speter // available space again before encoding Stream Footer. 7318334Speter out_size -= LZMA_STREAM_HEADER_SIZE; 7418334Speter 7518334Speter // Encode the Stream Header. 7618334Speter lzma_stream_flags stream_flags = { 7718334Speter .version = 0, 7818334Speter .check = check, 7918334Speter }; 8018334Speter 8118334Speter if (lzma_stream_header_encode(&stream_flags, out + out_pos) 8218334Speter != LZMA_OK) 8318334Speter return LZMA_PROG_ERROR; 8418334Speter 8518334Speter out_pos += LZMA_STREAM_HEADER_SIZE; 8618334Speter 8718334Speter // Encode a Block but only if there is at least one byte of input. 8818334Speter lzma_block block = { 8918334Speter .version = 0, 9018334Speter .check = check, 9118334Speter .filters = filters, 9218334Speter }; 9318334Speter 9418334Speter if (in_size > 0) 9518334Speter return_if_error(lzma_block_buffer_encode(&block, allocator, 9618334Speter in, in_size, out, &out_pos, out_size)); 9718334Speter 9818334Speter // Index 9918334Speter { 10018334Speter // Create an Index. It will have one Record if there was 101132718Skan // at least one byte of input to encode. Otherwise the 10218334Speter // Index will be empty. 103132718Skan lzma_index *i = lzma_index_init(allocator); 104132718Skan if (i == NULL) 105132718Skan return LZMA_MEM_ERROR; 106132718Skan 107132718Skan lzma_ret ret = LZMA_OK; 108132718Skan 109132718Skan if (in_size > 0) 110132718Skan ret = lzma_index_append(i, allocator, 111132718Skan lzma_block_unpadded_size(&block), 112132718Skan block.uncompressed_size); 113132718Skan 114132718Skan // If adding the Record was successful, encode the Index 115132718Skan // and get its size which will be stored into Stream Footer. 116132718Skan if (ret == LZMA_OK) { 117132718Skan ret = lzma_index_buffer_encode( 118132718Skan i, out, &out_pos, out_size); 119132718Skan 120132718Skan stream_flags.backward_size = lzma_index_size(i); 121132718Skan } 122132718Skan 123132718Skan lzma_index_end(i, allocator); 124132718Skan 125132718Skan if (ret != LZMA_OK) 12618334Speter return ret; 12718334Speter } 12818334Speter 12918334Speter // Stream Footer. We have already reserved space for this. 13018334Speter if (lzma_stream_footer_encode(&stream_flags, out + out_pos) 13118334Speter != LZMA_OK) 13218334Speter return LZMA_PROG_ERROR; 133132718Skan 134132718Skan out_pos += LZMA_STREAM_HEADER_SIZE; 135132718Skan 136132718Skan // Everything went fine, make the new output position available 137132718Skan // to the application. 138132718Skan *out_pos_ptr = out_pos; 13918334Speter return LZMA_OK; 14018334Speter} 14118334Speter