1207753Smm/////////////////////////////////////////////////////////////////////////////// 2207753Smm// 3207753Smm/// \file block_header_encoder.c 4207753Smm/// \brief Encodes Block Header for .xz files 5207753Smm// 6207753Smm// Author: Lasse Collin 7207753Smm// 8207753Smm// This file has been put into the public domain. 9207753Smm// You can do whatever you want with this file. 10207753Smm// 11207753Smm/////////////////////////////////////////////////////////////////////////////// 12207753Smm 13207753Smm#include "common.h" 14207753Smm#include "check.h" 15207753Smm 16207753Smm 17207753Smmextern LZMA_API(lzma_ret) 18207753Smmlzma_block_header_size(lzma_block *block) 19207753Smm{ 20292588Sdelphij if (block->version > 1) 21207753Smm return LZMA_OPTIONS_ERROR; 22207753Smm 23207753Smm // Block Header Size + Block Flags + CRC32. 24207753Smm uint32_t size = 1 + 1 + 4; 25207753Smm 26207753Smm // Compressed Size 27207753Smm if (block->compressed_size != LZMA_VLI_UNKNOWN) { 28207753Smm const uint32_t add = lzma_vli_size(block->compressed_size); 29207753Smm if (add == 0 || block->compressed_size == 0) 30207753Smm return LZMA_PROG_ERROR; 31207753Smm 32207753Smm size += add; 33207753Smm } 34207753Smm 35207753Smm // Uncompressed Size 36207753Smm if (block->uncompressed_size != LZMA_VLI_UNKNOWN) { 37207753Smm const uint32_t add = lzma_vli_size(block->uncompressed_size); 38207753Smm if (add == 0) 39207753Smm return LZMA_PROG_ERROR; 40207753Smm 41207753Smm size += add; 42207753Smm } 43207753Smm 44207753Smm // List of Filter Flags 45207753Smm if (block->filters == NULL || block->filters[0].id == LZMA_VLI_UNKNOWN) 46207753Smm return LZMA_PROG_ERROR; 47207753Smm 48207753Smm for (size_t i = 0; block->filters[i].id != LZMA_VLI_UNKNOWN; ++i) { 49207753Smm // Don't allow too many filters. 50207753Smm if (i == LZMA_FILTERS_MAX) 51207753Smm return LZMA_PROG_ERROR; 52207753Smm 53207753Smm uint32_t add; 54207753Smm return_if_error(lzma_filter_flags_size(&add, 55207753Smm block->filters + i)); 56207753Smm 57207753Smm size += add; 58207753Smm } 59207753Smm 60207753Smm // Pad to a multiple of four bytes. 61207753Smm block->header_size = (size + 3) & ~UINT32_C(3); 62207753Smm 63207753Smm // NOTE: We don't verify that the encoded size of the Block stays 64207753Smm // within limits. This is because it is possible that we are called 65207753Smm // with exaggerated Compressed Size (e.g. LZMA_VLI_MAX) to reserve 66207753Smm // space for Block Header, and later called again with lower, 67207753Smm // real values. 68207753Smm 69207753Smm return LZMA_OK; 70207753Smm} 71207753Smm 72207753Smm 73207753Smmextern LZMA_API(lzma_ret) 74207753Smmlzma_block_header_encode(const lzma_block *block, uint8_t *out) 75207753Smm{ 76207753Smm // Validate everything but filters. 77207753Smm if (lzma_block_unpadded_size(block) == 0 78207753Smm || !lzma_vli_is_valid(block->uncompressed_size)) 79207753Smm return LZMA_PROG_ERROR; 80207753Smm 81207753Smm // Indicate the size of the buffer _excluding_ the CRC32 field. 82207753Smm const size_t out_size = block->header_size - 4; 83207753Smm 84207753Smm // Store the Block Header Size. 85207753Smm out[0] = out_size / 4; 86207753Smm 87207753Smm // We write Block Flags in pieces. 88207753Smm out[1] = 0x00; 89207753Smm size_t out_pos = 2; 90207753Smm 91207753Smm // Compressed Size 92207753Smm if (block->compressed_size != LZMA_VLI_UNKNOWN) { 93207753Smm return_if_error(lzma_vli_encode(block->compressed_size, NULL, 94207753Smm out, &out_pos, out_size)); 95207753Smm 96207753Smm out[1] |= 0x40; 97207753Smm } 98207753Smm 99207753Smm // Uncompressed Size 100207753Smm if (block->uncompressed_size != LZMA_VLI_UNKNOWN) { 101207753Smm return_if_error(lzma_vli_encode(block->uncompressed_size, NULL, 102207753Smm out, &out_pos, out_size)); 103207753Smm 104207753Smm out[1] |= 0x80; 105207753Smm } 106207753Smm 107207753Smm // Filter Flags 108207753Smm if (block->filters == NULL || block->filters[0].id == LZMA_VLI_UNKNOWN) 109207753Smm return LZMA_PROG_ERROR; 110207753Smm 111207753Smm size_t filter_count = 0; 112207753Smm do { 113207753Smm // There can be a maximum of four filters. 114207753Smm if (filter_count == LZMA_FILTERS_MAX) 115207753Smm return LZMA_PROG_ERROR; 116207753Smm 117207753Smm return_if_error(lzma_filter_flags_encode( 118207753Smm block->filters + filter_count, 119207753Smm out, &out_pos, out_size)); 120207753Smm 121207753Smm } while (block->filters[++filter_count].id != LZMA_VLI_UNKNOWN); 122207753Smm 123207753Smm out[1] |= filter_count - 1; 124207753Smm 125207753Smm // Padding 126207753Smm memzero(out + out_pos, out_size - out_pos); 127207753Smm 128207753Smm // CRC32 129207753Smm unaligned_write32le(out + out_size, lzma_crc32(out, out_size, 0)); 130207753Smm 131207753Smm return LZMA_OK; 132207753Smm} 133