static void test_header(void) { memcrap(buffer, sizeof(buffer)); expect(lzma_stream_header_encode(&known_flags, buffer) == LZMA_OK); succeed(test_header_decoder(LZMA_OK)); }
static void test_decode_invalid(void) { known_flags.check = LZMA_CHECK_NONE; known_flags.backward_size = 1024; expect(lzma_stream_header_encode(&known_flags, buffer) == LZMA_OK); // Test 1 (invalid Magic Bytes) buffer[5] ^= 1; succeed(test_header_decoder(LZMA_FORMAT_ERROR)); buffer[5] ^= 1; // Test 2a (valid CRC32) uint32_t crc = lzma_crc32(buffer + 6, 2, 0); unaligned_write32le(buffer + 8, crc); succeed(test_header_decoder(LZMA_OK)); // Test 2b (invalid Stream Flags with valid CRC32) buffer[6] ^= 0x20; crc = lzma_crc32(buffer + 6, 2, 0); unaligned_write32le(buffer + 8, crc); succeed(test_header_decoder(LZMA_OPTIONS_ERROR)); // Test 3 (invalid CRC32) expect(lzma_stream_header_encode(&known_flags, buffer) == LZMA_OK); buffer[9] ^= 1; succeed(test_header_decoder(LZMA_DATA_ERROR)); // Test 4 (invalid Stream Flags with valid CRC32) expect(lzma_stream_footer_encode(&known_flags, buffer) == LZMA_OK); buffer[9] ^= 0x40; crc = lzma_crc32(buffer + 4, 6, 0); unaligned_write32le(buffer, crc); succeed(test_footer_decoder(LZMA_OPTIONS_ERROR)); // Test 5 (invalid Magic Bytes) expect(lzma_stream_footer_encode(&known_flags, buffer) == LZMA_OK); buffer[11] ^= 1; succeed(test_footer_decoder(LZMA_FORMAT_ERROR)); }
static void test_encode_invalid(void) { known_flags.check = LZMA_CHECK_ID_MAX + 1; known_flags.backward_size = 1024; expect(lzma_stream_header_encode(&known_flags, buffer) == LZMA_PROG_ERROR); expect(lzma_stream_footer_encode(&known_flags, buffer) == LZMA_PROG_ERROR); known_flags.check = (lzma_check)(-1); expect(lzma_stream_header_encode(&known_flags, buffer) == LZMA_PROG_ERROR); expect(lzma_stream_footer_encode(&known_flags, buffer) == LZMA_PROG_ERROR); known_flags.check = LZMA_CHECK_NONE; known_flags.backward_size = 0; // Header encoder ignores backward_size. expect(lzma_stream_header_encode(&known_flags, buffer) == LZMA_OK); expect(lzma_stream_footer_encode(&known_flags, buffer) == LZMA_PROG_ERROR); known_flags.backward_size = LZMA_VLI_MAX; expect(lzma_stream_header_encode(&known_flags, buffer) == LZMA_OK); expect(lzma_stream_footer_encode(&known_flags, buffer) == LZMA_PROG_ERROR); }
static lzma_ret stream_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator, const lzma_filter *filters, lzma_check check) { lzma_next_coder_init(&stream_encoder_init, next, allocator); if (filters == NULL) return LZMA_PROG_ERROR; if (next->coder == NULL) { next->coder = lzma_alloc(sizeof(lzma_coder), allocator); if (next->coder == NULL) return LZMA_MEM_ERROR; next->code = &stream_encode; next->end = &stream_encoder_end; next->update = &stream_encoder_update; next->coder->filters[0].id = LZMA_VLI_UNKNOWN; next->coder->block_encoder = LZMA_NEXT_CODER_INIT; next->coder->index_encoder = LZMA_NEXT_CODER_INIT; next->coder->index = NULL; } // Basic initializations next->coder->sequence = SEQ_STREAM_HEADER; next->coder->block_options.version = 0; next->coder->block_options.check = check; // Initialize the Index lzma_index_end(next->coder->index, allocator); next->coder->index = lzma_index_init(allocator); if (next->coder->index == NULL) return LZMA_MEM_ERROR; // Encode the Stream Header lzma_stream_flags stream_flags = { .version = 0, .check = check, }; return_if_error(lzma_stream_header_encode( &stream_flags, next->coder->buffer)); next->coder->buffer_pos = 0; next->coder->buffer_size = LZMA_STREAM_HEADER_SIZE; // Initialize the Block encoder. This way we detect unsupported // filter chains when initializing the Stream encoder instead of // giving an error after Stream Header has already written out. return stream_encoder_update( next->coder, allocator, filters, NULL); } extern LZMA_API(lzma_ret) lzma_stream_encoder(lzma_stream *strm, const lzma_filter *filters, lzma_check check) { lzma_next_strm_init(stream_encoder_init, strm, filters, check); strm->internal->supported_actions[LZMA_RUN] = true; strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true; strm->internal->supported_actions[LZMA_FULL_FLUSH] = true; strm->internal->supported_actions[LZMA_FINISH] = true; return LZMA_OK; }
lzma_stream_buffer_encode(lzma_filter *filters, lzma_check check, lzma_allocator *allocator, const uint8_t *in, size_t in_size, uint8_t *out, size_t *out_pos_ptr, size_t out_size) { // Sanity checks if (filters == NULL || (unsigned int)(check) > LZMA_CHECK_ID_MAX || (in == NULL && in_size != 0) || out == NULL || out_pos_ptr == NULL || *out_pos_ptr > out_size) return LZMA_PROG_ERROR; if (!lzma_check_is_supported(check)) return LZMA_UNSUPPORTED_CHECK; // Note for the paranoids: Index encoder prevents the Stream from // getting too big and still being accepted with LZMA_OK, and Block // encoder catches if the input is too big. So we don't need to // separately check if the buffers are too big. // Use a local copy. We update *out_pos_ptr only if everything // succeeds. size_t out_pos = *out_pos_ptr; // Check that there's enough space for both Stream Header and // Stream Footer. if (out_size - out_pos <= 2 * LZMA_STREAM_HEADER_SIZE) return LZMA_BUF_ERROR; // Reserve space for Stream Footer so we don't need to check for // available space again before encoding Stream Footer. out_size -= LZMA_STREAM_HEADER_SIZE; // Encode the Stream Header. lzma_stream_flags stream_flags = { .version = 0, .check = check, }; if (lzma_stream_header_encode(&stream_flags, out + out_pos) != LZMA_OK) return LZMA_PROG_ERROR; out_pos += LZMA_STREAM_HEADER_SIZE; // Encode a Block but only if there is at least one byte of input. lzma_block block = { .version = 0, .check = check, .filters = filters, }; if (in_size > 0) return_if_error(lzma_block_buffer_encode(&block, allocator, in, in_size, out, &out_pos, out_size)); // Index { // Create an Index. It will have one Record if there was // at least one byte of input to encode. Otherwise the // Index will be empty. lzma_index *i = lzma_index_init(allocator); if (i == NULL) return LZMA_MEM_ERROR; lzma_ret ret = LZMA_OK; if (in_size > 0) ret = lzma_index_append(i, allocator, lzma_block_unpadded_size(&block), block.uncompressed_size); // If adding the Record was successful, encode the Index // and get its size which will be stored into Stream Footer. if (ret == LZMA_OK) { ret = lzma_index_buffer_encode( i, out, &out_pos, out_size); stream_flags.backward_size = lzma_index_size(i); } lzma_index_end(i, allocator); if (ret != LZMA_OK) return ret; } // Stream Footer. We have already reserved space for this. if (lzma_stream_footer_encode(&stream_flags, out + out_pos) != LZMA_OK) return LZMA_PROG_ERROR; out_pos += LZMA_STREAM_HEADER_SIZE; // Everything went fine, make the new output position available // to the application. *out_pos_ptr = out_pos; return LZMA_OK; }